2013-12-16 3 views
3

В D мой сборщик мусора каждый раз запускает мое приложение.Сбой коллектора мусора при использовании функций WinAPI

модуль для Windows:

pragma(lib, "user32.lib"); 

import std.string; 

extern(Windows) { 
    void* CreateWindowExW(uint extendedStyle , 
          const char* classname, 
          const char* title, 
          uint style, 
          int x, int y, 
          int width, int height, 
          void* parentHandle, 
          void* menuHandle, 
          void* moduleInstance, 
          void* lParam); 
} 

class Window { 
    private void* handle; 
    private string title; 

    this(string title, const int x, const int y, const int width, const int height) { 
     this.title = title; 
     handle = CreateWindowExW(0, null, toStringz(this.title), 0, x, y, width, height, null, null, null, null); 

     if(handle == null) 
      throw new Exception("Error while creating Window (WinAPI)"); 
    } 
} 

Главный модуль:

import std.stdio; 

version(Windows) { 
    import windows; 
    extern (Windows) { 
    int WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) { 
     import core.runtime; 

     Runtime.initialize(); 
     scope(exit) Runtime.terminate(); 
     auto window = new Window("Hello", 0, 0, 0, 0); 
     writeln("test"); 
     return 0; 
    } 
    } 
} 

Это дает мне нарушение прав доступа в месте 0. Когда я просматривать dissassembly, это сбой в

0040986F mov   ecx,dword ptr [eax] 

Эта сборка находится внутри _gc_malloc.


EDIT: Вот новый код:

Windows, модуль:

pragma(lib, "user32.lib"); 

import std.utf; 

extern(Windows) { 
    void* CreateWindowExW(uint extendedStyle , 
          const wchar* classname, 
          const wchar* title, 
          uint style, 
          int x, int y, 
          int width, int height, 
          void* parentHandle, 
          void* menuHandle, 
          void* moduleInstance, 
          void* lParam); 
} 

class Window { 
    private void* handle; 
    private wstring title; 

    this(wstring title, const int x, const int y, const int width, const int height) { 
     this.title = title; 
     handle = CreateWindowExW(0, null, toUTFz!(wchar*)(this.title), 0, x, y, width, height, null, null, null, null); 

     if(handle == null) 
      throw new Exception("Error while creating Window (WinAPI)"); 
    } 
} 

WinMain:

int WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) { 
     import core.runtime; 

     try { 
      Runtime.initialize(); 
      scope(exit) Runtime.terminate(); 
      auto window = new Window("Hello", 0, 0, 0, 0); 
      writeln("test"); 
     } catch(Exception ex) { 
      writeln(ex.toString); 
     } 
     return 0; 
    } 

Когда я запускаю этот второй код, я также получаю Нарушение доступа, по случайному (мне) адресу.

Dissasembly (внутри __d_createTrace):

0040C665 cmp   dword ptr [ecx+1Ch],0 
+2

Runtime.initialize и выход из области выполнения runtime.terminate должны быть как снаружи, так и снаружи, попробовать, поместить их в самый верх функции, а затем попробовать свой код. То, что происходит сейчас, - это новое окно, генерирующее исключение (например, Дэвид сказал, вам нужно сначала зарегистрировать класс окна, а не передать null), а затем в конце попытки завершается. Таким образом, внутри catch, материал не настроен, и вызов toString не может выполнять свою работу. Поэтому переместите эти две строки Runtime выше, и вы должны получить сообщение с хорошим сообщением об исключении. –

ответ

5

Сообщение Дэвида Хеффернана имеет хорошую информацию, но здесь не будет исправлена ​​основная проблема, связанная с тем, что время выполнения D не инициализируется. Вы код должен выбросить исключение, ваши аргументы для создания окна неверны, но должно быть не быть нарушением прав доступа.

Самый простой способ решить эту задачу - определить обычную функцию main вместо WinMain. WinMains действительны в D, но если вы определяете свой собственный, он пропускает функции инициализации времени выполнения. (Время выполнения, src/druntime/src/rt/main2.d, если вам интересно) определяют основную функцию C, которая выполняет задачи настройки, а затем вызывает вашу главную функцию D. В свою очередь, основной B-файл C вызван из WinMain с помощью среды выполнения C.

Если вам нужны аргументы для экземпляра или командной строки, вы можете получить доступ с помощью функции API Windows GetModuleHandle (null) и GetCommandLineW().

В качестве альтернативы, вы можете инициализировать выполнения самостоятельно в функции WinMain:

extern (Windows) { 
    int WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) { 
    import core.runtime; // the Runtime functions are in here 
    Runtime.initialize(); // initialize it! 
     auto window = new Window("Hello", 0, 0, 0, 0); 
     return 0; 
    } 
} 

Другая вещь, которую вы должны сделать, это прекратить его и перехватывать исключения.Невыделенное исключение в Windows по умолчанию вызовет системный отладчик, поэтому все не так плохо, но обычно в программах D вы ожидаете более приятного сообщения. Так что-то вроде этого:

int WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) { 
    import core.runtime; 
    Runtime.initialize(); 
    scope(exit) Runtime.terminate(); 
    try 
     auto window = new Window("Hello", 0, 0, 100, 100); 
    catch(Throwable t) 
     MessageBoxW(null, toUTFz!(wchar*)(t.toString()), null, 0); 
    return 0; 
} 

Я инициализируется его там, завершается, когда функция возвращается, а также поймал исключение и поместить его в окно сообщения для более легкого чтения. Я поставил прототип MessageBoxW в себя, как и для CreateWindow. Вы также можете получить более полные привязок win32 здесь http://www.dsource.org/projects/bindings/browser/trunk/win32думаю что и является актуальной ссылки в любом случае.)

Снова, хотя, вы можете просто использовать D основную функцию, которая делает этот вид вещи для вас. WinMain дает больше контроля, но не требуется D.

+0

+1 Спасибо за это. –

+0

Теперь я просто получаю нарушение прав доступа в разборке «отпуск». –

+0

Вы можете редактировать дополнительную информацию в вопрос? –

5

CreateWindowExW занимает 16-битовых строк, а не 8 битовых строк. Я не уверен, как достичь этого в D. Предполагаю, что char 8 бит, как и на C++ в Windows? Вы могли бы использовать CreateWindowExA, я полагаю, но лучше было бы передавать 16-битный текст UTF-16.

Ошибка null для параметра lpClassName. Окно требует класс окна.

+2

Да, тип должен быть 'wchar' вместо' char'. Если вы поместите префикс 'w' в конце строкового литерала, например. '" myclassname "w', он будет работать как wchar *. Преобразование нелитералов в wchar выполняется с помощью 'std.utf.toUTFz! Wstring (your_data);' –

+0

@ AdamD.Ruppe Спасибо! Я не знаю ничего подобного в контексте D! –

+2

Я только что попробовал, и, видимо, wstrings не подразумевает конвертацию в указатели, так что либо сделайте toUTFz onthem тоже, либо используйте свойство ptr, 'myclassname" w.ptr'. (Я думаю, что это может быть контроль над компилятором, поскольку строки utf-8 string * do * неявно преобразуются в char *. Строки D не обязательно нулевые, поэтому неявное преобразование плохое в целом, но поскольку литералы являются особым случаем, это нормально, все строковые литералы получают нулевой терминатор для удобной совместимости C.) EDIT: также, по-видимому, это должно быть 'toUTFz! (wchar *)', а не wstring. Странно, я думал, wstring работал ... –

Смежные вопросы