4

私の主な目標は、 USBHIDイベントを処理できるP/Invoke呼び出しだけで適切なメッセージループを実装することです。間違いなく、その機能は、 Windowsフォームでうまく機能する次のコードと同じである必要があります。このNativeWindowの子孫は、次のイベントを受け取ります。

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);
    }
}

...このイベントループを利用:

Win32EventHandler handler = new Win32EventHandler();

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

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

イベントループの実装はかなり簡単であることがわかりました。

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
    }
}

しかし、基になるWindowオブジェクトをどのように作成する必要があるのか​​わかりません。NativeWindowクラスの実装は、私には複雑すぎるようです。

これが現時点での私の解決策です。

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;
}
4

2 に答える 2

4

これは非常に能力の低いイベント ループです。MsgWaitForMultipleObjectsExの代わりに次のようなものを使用することを検討してくださいGetMessage

とにかく、ウィンドウを作成するには、最初にウィンドウ クラスを登録し ( RegisterClassEx)、次にウィンドウを作成する( ) 必要がありますCreateWindow。どちらも特に難しいことはありません。を使用する代わりに、base.WndProc()を呼び出す必要がありますDefWindowProc

すべてのメッセージをメッセージ ループ内で直接処理しようとすると、非常に困難になるため、ウィンドウ プロシージャが作成されました。また、直接処理することを選択したメッセージについて、TranslateMessageまたは電話をかけないでください。DispatchMessage

于 2012-01-24T01:21:20.310 に答える
0

この男が USB デバイスを検出する方法を確認することをお勧めします: USB デバイスを検出するための USB ライブラリ

于 2012-01-24T01:18:56.393 に答える