在D中,每次启动应用程序时,我的垃圾收集器都会崩溃。
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给我一个访问冲突。当我查看反汇编时,它崩溃了
0040986F mov ecx,dword ptr [eax]
此程序集位于_gc_malloc
内。
编辑:以下是新代码:
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
答案 0 :(得分:5)
CreateWindowExW
采用16位字符串而不是8位字符串。我不确定如何在D中实现这一点。我假设char
是8位,就像在Windows上的C ++中一样?您可以使用CreateWindowExA
,但最好传递16位UTF-16文本。
为null
参数传递lpClassName
一定是错误的。窗口确实需要一个窗口类。
答案 1 :(得分:5)
David Heffernan的帖子有很好的信息,但不会解决这里的主要问题,即D运行时没有初始化。您的代码应该抛出异常,您创建窗口的参数是错误的,但不应该是访问冲突。
解决此问题的最简单方法是定义常规main
函数而不是WinMain
。 WinMains在D中有效,但是如果你定义了自己的,它会跳过druntime初始化函数。 (如果你感兴趣,运行时,src / druntime / src / rt / main2.d)定义一个C main函数,它执行设置任务,然后调用你的D main函数。反过来,C main btw是由C运行时从WinMain调用的。
如果需要实例或命令行的参数,可以使用Windows API函数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 main函数为你做这种事情。 WinMain提供更多控制权,但D不需要。