一旦窗口接收到消息,P/Invoke PostMessage就崩溃
本文关键字:Invoke PostMessage 崩溃 消息 窗口 | 更新日期: 2023-09-27 18:15:39
我在。net核心的c#控制台应用程序中通过p/Invoke Win32 API创建了一个窗口。以下是核心代码:
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(...)
// ...
}
}
但是当我把鼠标移到窗口上时,程序总是崩溃。
程序'[18996]dotnet.exe'已退出,代码为-1073740771 (0xc000041d).
最后我发现崩溃发生在PeekMessage被调用的时候。但我不知道为什么。
经过3个小时的搜索和调试,终于找到了原因。
WinProc委托实例被垃圾收集。那么本机代码将访问一个无效的函数指针。
我指的是这个wndclass.lpfnWndProc = WindowProc;
。windclass是一个临时对象——确切地说是一个结构体实例——当程序从CreateWindow
返回时,它将不存在于堆栈上。之后,由CLR决定是否GC wndclass.lpfnWndProc
。
因此,解决方案是使wndclass
不是一个临时对象。例如,
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;
}
}
现在,windclass与WindowContext实例存在的时间一样长。问题解决了。
SO:
上的一些类似问题https://stackoverflow.com/a/5007211/3427520 https://stackoverflow.com/a/1616718/3427520