2012-01-24 18 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