实现一个Win32消息循环和创建窗口对象的P / Invoke对象、窗口、消息、Invoke

2023-09-03 03:51:06 作者:都是酸牛奶装什么特仑苏啊

我的主要目标是纯粹的实现适当的消息循环使用的P / Invoke调用,能够处理USB HID事件。肯定它的功能应该是相同的以下code,在WinForms.NET效果很好。由此NativeWindow descandent接收事件:

 公共类Win32EventHandler:NativeWindow的
{
    公共const int的WM_DEVICECHANGE = 0x0219;

    公共Win32EventHandler()
    {
        this.CreateHandle(新的CreateParams());
    }

    保护覆盖无效OnHandleChange()
    {
        base.OnHandleChange();

        IntPtr的处理= UsbHelper.RegisterForUsbEvents(this.Handle);
    }

    保护覆盖无效的WndProc(参考消息M)
    {
        如果(m.Msg == WM_DEVICECHANGE)
        {
            //处理事件
        }

        base.WndProc(REF米);
    }
}
 

...搭载这一事件循环:

  Win32EventHandler处理器=新Win32EventHandler();

VAR上下文=新的ApplicationContext();
Application.Run(上下文);

//其他线程调用:
// context.ExitThread()
 

我发现执行事件循环是相当容易的:

 ,而(真)
{
    RES = Win32.GetMessage(出味精,IntPtr.Zero,0,0);

    如果(RES == 0)
    {
        打破;
    }

    Win32.TranslateMessage(REF MSG);
    Win32.DispatchMessage(REF MSG);

    如果(msg.message == WM_DEVICECHANGE)
    {
        //处理事件
    }
}
 
Winodw消息编程总结

不过,我不知道如何底层的Window对象应创建。 NativeWindow类的实现似乎太复杂了我。

更新: 这是我目前的解决方案:

 公共无效CustomLoop()
{
    字符串clsName =类;
    字符串wndName =窗口;

    Win32.WNDCLASSEX WNDCLASSEX =新Win32.WNDCLASSEX();

    wndClassEx.cbSize =(UINT)Marshal.SizeOf(WNDCLASSEX);
    wndClassEx.lpszClassName = clsName;
    wndClassEx.lpfnWndProc = WndProc的;

    Win32.RegisterClassEx(REF WNDCLASSEX);

    IntPtr的windowHandle = Win32.CreateWindowEx(0,clsName,wndName,0,0,0,0,0,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero);

    IntPtr的usbEventHandle = UsbHelper.RegisterForUsbEvents(windowHandle);

    Win32.MSG味精;
    为sbyte解析度= 0;

    而(真)
    {
        RES = Win32.GetMessage(出味精,IntPtr.Zero,0,0);

        如果(RES == 0)
        {
            打破;
        }

        如果(msg.message == WM.DEVICECHANGE)
        {
            //处理事件(不火)
        }
        其他
        {
            Win32.TranslateMessage(REF MSG);
            Win32.DispatchMessage(REF MSG);
        }

    }

    Win32.DestroyWindow(windowHandle);
    Win32.UnregisterClass(clsName,IntPtr.Zero);
}

[AllowReversePInvokeCalls]
私有的IntPtr的WndProc(IntPtr的的HWND,WM味精,IntPtr的wParam中,IntPtr的lParam的)
{
    开关(MSG)
    {
        案例WM.DEVICECHANGE:
            //处理事件(火灾
            打破;
        默认:
            返回Win32.DefWindowProc(HWND,味精,的wParam,lParam的);
    }

    返回IntPtr.Zero;
}
 

解决方案

这是一个非常在供电事件循环。考虑使用,而不是的GetMessage 类似 MsgWaitForMultipleObjectsEx

总之,创建一个窗口要求您先注册一个窗口类( RegisterClassEx ),然后创建窗口(CreateWindow的)。没有一个是特别困难的。而不是使用 base.WndProc()和,你将需要调用给DefWindowProc

试图直接处理所有邮件里面的消息循环将是太困难,这就是为什么创建窗口过程。不要叫的TranslateMessage 在DispatchMessage 供您选择直接处理的任何消息。

My main goal is to implement a proper message loop purely with P/Invoke calls that is able to handle USB HID events. Definitely its functionality should be identical with the following code that works well in WinForms.NET. This NativeWindow descandent receives the events:

public class Win32EventHandler : NativeWindow
{
    public const int WM_DEVICECHANGE = 0x0219;

    public Win32EventHandler()
    {
        this.CreateHandle(new CreateParams());
    }

    protected override void OnHandleChange()
    {
        base.OnHandleChange();

        IntPtr handle = UsbHelper.RegisterForUsbEvents(this.Handle);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_DEVICECHANGE)
        {
            // Handle event
        }

        base.WndProc(ref m);
    }
}

... powered by this event loop:

Win32EventHandler handler = new Win32EventHandler();

var context = new ApplicationContext(); 
Application.Run(context);

// Other thread calls: 
// context.ExitThread()

I found out that implementing the event loop is rather easy:

while (true)
{
    res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0);

    if (res == 0)
    {
        break;
    }

    Win32.TranslateMessage(ref msg);
    Win32.DispatchMessage(ref msg);

    if (msg.message == WM_DEVICECHANGE)
    {
        // Handle event
    }
}

But I have no idea how the underlying Window object should be created. The implementation of the NativeWindow class seems too complex for me.

Update: This is my solution at the moment:

public void CustomLoop()
{
    string clsName = "Class";
    string wndName = "Window";

    Win32.WNDCLASSEX wndClassEx = new Win32.WNDCLASSEX();

    wndClassEx.cbSize = (uint)Marshal.SizeOf(wndClassEx);
    wndClassEx.lpszClassName = clsName;
    wndClassEx.lpfnWndProc = WndProc;

    Win32.RegisterClassEx(ref wndClassEx);

    IntPtr windowHandle = Win32.CreateWindowEx(0, clsName, wndName, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

    IntPtr usbEventHandle = UsbHelper.RegisterForUsbEvents(windowHandle);

    Win32.MSG msg;
    sbyte res = 0;

    while (true)
    {
        res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0);

        if (res == 0)
        {
            break;
        }

        if (msg.message == WM.DEVICECHANGE)
        {
            // Handle event (does not fire)
        }
        else
        {
            Win32.TranslateMessage(ref msg);
            Win32.DispatchMessage(ref msg);
        }

    }

    Win32.DestroyWindow(windowHandle);
    Win32.UnregisterClass(clsName, IntPtr.Zero);
}

[AllowReversePInvokeCalls]
private IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam)
{
    switch (msg)
    {
        case WM.DEVICECHANGE:
            // Handle event (fires
            break;
        default:
            return Win32.DefWindowProc(hWnd, msg, wParam, lParam);
    }

    return IntPtr.Zero;
}

解决方案

That's an very under-powered event loop. Consider using something like MsgWaitForMultipleObjectsEx instead of GetMessage.

Anyway, creating a window requires you to first register a window class (RegisterClassEx) and then create the window (CreateWindow). Neither one is particularly difficult. And instead of using base.WndProc(), you'll need to call DefWindowProc.

Trying to handle all messages directly inside the message loop is going to be overly difficult, that's why window procedures were created. And don't call TranslateMessage or DispatchMessage for any message you choose to process directly.