窗口收到消息后,P/Invoke PostMessage崩溃 [英] P/Invoke PostMessage crashes once the window received message
问题描述
我正在.NET Core上的C#控制台应用程序中通过P/Invoke Win32 API创建一个窗口.以下是核心代码.
I'm creating a window via P/Invoke Win32 API in a C# console application on .NET core. Following is the core code.
class WindowContext
{
public IWindow MainLoop(Action guiMethod)// this is called somewhere else
{
MSG msg = new MSG();
while (msg.message != 0x12/*WM_QUIT*/)
{
if (PeekMessage(ref msg, IntPtr.Zero, 0, 0, 0x0001/*PM_REMOVE*/))
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
}
}
private IntPtr WindowProc(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam)
{
//....
}
public IWindow CreateWindow(Point position, Size size)// this is called to create a window
{
IntPtr hInstance = processHandle.DangerousGetHandle();
string szAppName = "ImGuiApplication~";
WNDCLASS wndclass;
wndclass.style = 0x0002 /*CS_HREDRAW*/ | 0x0001/*CS_VREDRAW*/;
wndclass.lpfnWndProc = WindowProc;
// RegisterClass(ref wndclass);
// CreateWindowEx(...)
// ...
}
}
但是,一旦我将鼠标移到窗口上,该程序就会不断崩溃.
But the program keeps crashing once I move the mouse onto the window.
程序"[18996] dotnet.exe"已退出,代码为-1073740771(0xc000041d).
The program '[18996] dotnet.exe' has exited with code -1073740771 (0xc000041d).
最后我发现调用PeekMessage时发生了崩溃.但是我不知道为什么.
Finally I found out the crash occurred when the PeekMessage is called. But I couldn't tell why.
推荐答案
搜索和调试3小时后,终于找到了原因.
After searching and debugging for 3 hours, finally I found the cause.
WinProc委托实例已被垃圾回收.然后,本机代码将访问无效的函数指针.
The WinProc delegate instance is garbage collected. Then the native code will access a invalid function pointer.
我的意思是这个wndclass.lpfnWndProc = WindowProc;
. wndclass是一个临时对象-完全是一个结构实例-并且当程序从CreateWindow
返回时将不存在于堆栈中.然后,由CLR决定是否使用GC wndclass.lpfnWndProc
.
I mean this one wndclass.lpfnWndProc = WindowProc;
. The wndclass is a temporary object-a struct instance exactly-and will not exist on the stack when the program returns from CreateWindow
. And after that, it is up to the CLR to determine whether to GC wndclass.lpfnWndProc
.
因此解决方案是使wndclass
不是临时对象.例如,
So the solution is to make wndclass
not a temporary object. For example,
class WindowContext
{
WNDCLASS wndclass;
public IWindow CreateWindow(Point position, Size size)// this is called to create a window
{
IntPtr hInstance = processHandle.DangerousGetHandle();
string szAppName = "ImGuiApplication~";
wndclass.style = 0x0002 /*CS_HREDRAW*/ | 0x0001/*CS_VREDRAW*/;
wndclass.lpfnWndProc = WindowProc;
}
}
现在,wndclass与WindowContext实例的寿命相同.问题解决了.
Now the wndclass lives the same long with the WindowContext instance. Problem solved.
关于SO的一些类似问题:
Some similar problems on SO:
https://stackoverflow.com/a/5007211/3427520
https://stackoverflow.com/a/1616718/3427520
这篇关于窗口收到消息后,P/Invoke PostMessage崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!