2012-01-24 19 views
4

我的主要目标是纯粹使用能够处理USB HID事件的P/Invoke调用实现适当的消息循环。当然,它的功能应该与以下代码相同,在Windows Forms中运行良好。由此NativeWindow后裔接收事件:实现Win32消息循环并使用P/Invoke创建Window对象

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; 
} 
+2

出于好奇,如果你有工作代码,你为什么要改写它不同的方式? –

+0

我想用P/Invoke在Silverlight 5中捕获这些事件。有一个很好的理由,它完全缺乏Win32特定的东西。 – tamasf

+0

你从pinvoke.net获得p/invoke声明? –

回答

4

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

无论如何,创建一个窗口需要您首先注册一个窗口类(RegisterClassEx),然后创建窗口(CreateWindow)。两者都不是特别困难。而不是使用base.WndProc(),您需要致电DefWindowProc

试图在消息循环内直接处理所有消息将会过于困难,这就是创建窗口过程的原因。对于您选择直接处理的任何消息,请勿拨打TranslateMessageDispatchMessage

+0

这就是我正在做的,但它似乎并没有工作。但是现在我发现了** lpfnWndProc **回调方法(RegisterClassEx)是针对USB事件调用的,但是** GetMessage **调用不会返回。这是正确的行为? – tamasf

+0

@tamasf:你有没有检查你的错误?如果你没有正确处理消息(通过将它们传递给DefWindowProc),你的'CreateWindow'调用将返回NULL,'RegisterDeviceNotification'将失败,并且你将不会收到消息。 –

+2

@tamasf:你可能会努力让[Raymond Chen的骨架Win32应用](http://blogs.msdn.com/b/oldnewthing/archive/2003/07/23/54576.aspx)启动并运行,首先在C ,然后在C#中用P/Invoke。 –

0

你可能想看看这个家伙怎么检测USB设备:A USB Library to Detect USB Devices

+0

这不是我想念的信息。我知道如何听USB事件。提供的样品和我完全一样。我的问题是,我无法像NativeWindow类一样创建Win32 Window对象。这是很重要的,因为Silverlight不暴露底层窗口对象的句柄,也不提供任何方式来挂钩事件循环。 – tamasf