窗口收到消息后,P/Invoke PostMessage崩溃 [英] P/Invoke PostMessage crashes once the window received message

查看:220
本文介绍了窗口收到消息后,P/Invoke PostMessage崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆