2010-01-13 43 views

回答

38

你需要一個窗口,這是沒有辦法的。這是一個示例實現。爲DeviceChangeNotifier.DeviceNotify事件實現事件處理程序以獲取通知。在程序開始時調用DeviceChangeNotifier.Start()方法。在程序結束時調用DeviceChangeNotifier.Stop()。請注意,DeviceNotify事件在後臺線程中引發,請務必根據需要進行鎖定,以確保您的代碼線程安全。

using System; 
using System.Windows.Forms; 
using System.Threading; 

class DeviceChangeNotifier : Form { 
    public delegate void DeviceNotifyDelegate(Message msg); 
    public static event DeviceNotifyDelegate DeviceNotify; 
    private static DeviceChangeNotifier mInstance; 

    public static void Start() { 
    Thread t = new Thread(runForm); 
    t.SetApartmentState(ApartmentState.STA); 
    t.IsBackground = true; 
    t.Start(); 
    } 
    public static void Stop() { 
    if (mInstance == null) throw new InvalidOperationException("Notifier not started"); 
    DeviceNotify = null; 
    mInstance.Invoke(new MethodInvoker(mInstance.endForm)); 
    } 
    private static void runForm() { 
    Application.Run(new DeviceChangeNotifier()); 
    } 

    private void endForm() { 
    this.Close(); 
    } 
    protected override void SetVisibleCore(bool value) { 
    // Prevent window getting visible 
    if (mInstance == null) CreateHandle(); 
    mInstance = this; 
    value = false; 
    base.SetVisibleCore(value); 
    } 
    protected override void WndProc(ref Message m) { 
    // Trap WM_DEVICECHANGE 
    if (m.Msg == 0x219) { 
     DeviceNotifyDelegate handler = DeviceNotify; 
     if (handler != null) handler(m); 
    } 
    base.WndProc(ref m); 
    } 
} 
+1

+1很好的例子,nobugz是正確的,你需要一個窗口。 – SwDevMan81 2010-01-14 02:40:23

+0

+1。很好的例子。 – 2010-01-14 03:54:52

+0

我看到你使用.Invoke。如果代理不在用戶界面中,這是否工作? – 2010-01-25 21:01:08

5

我有一個工作的USB通信類,實現設備更改通知以稍微不同的方式,如果任何人有興趣。它非常緊湊(沒有評論),不依賴於ThreadingOnSourceInitializedHwndHandler東西在客戶端。另外,您不需要上述的Form或Window。可以使用任何可以覆蓋的類型WndProc()。我使用Control

該示例僅包含通知所需的代碼,而沒有其他內容。示例代碼是C++/CLI,儘管我沒有訂閱將可執行代碼放在頭文件中的做法,爲了簡潔起見,我在這裏做了這個。

#pragma once 

#include <Windows.h> // Declares required datatypes. 
#include <Dbt.h>  // Required for WM_DEVICECHANGE messages. 
#include <initguid.h> // Required for DEFINE_GUID definition (see below). 

namespace USBComms 
{ 
    using namespace System; 
    using namespace System::Runtime::InteropServices; 
    using namespace System::Windows; 
    using namespace System::Windows::Forms; 

    // This function is required for receieving WM_DEVICECHANGE messages. 
    // Note: name is remapped "RegisterDeviceNotificationUM" 
    [DllImport("user32.dll" , CharSet = CharSet::Unicode, EntryPoint="RegisterDeviceNotification")]     
    extern "C" HDEVNOTIFY WINAPI RegisterDeviceNotificationUM(
     HANDLE hRecipient, 
     LPVOID NotificationFilter, 
     DWORD Flags); 

    // Generic guid for usb devices (see e.g. http://msdn.microsoft.com/en-us/library/windows/hardware/ff545972%28v=vs.85%29.aspx). 
    // Note: GUIDs are device and OS specific and may require modification. Using the wrong guid will cause notification to fail. 
    // You may have to tinker with your device to find the appropriate GUID. "hid.dll" has a function `HidD_GetHidGuid' that returns 
    // "the device interfaceGUID for HIDClass devices" (see http://msdn.microsoft.com/en-us/library/windows/hardware/ff538924%28v=vs.85%29.aspx). 
    // However, testing revealed it does not always return a useful value. The GUID_DEVINTERFACE_USB_DEVICE value, defined as 
    // {A5DCBF10-6530-11D2-901F-00C04FB951ED}, has worked with cell phones, thumb drives, etc. For more info, see e.g. 
    // http://msdn.microsoft.com/en-us/library/windows/hardware/ff553426%28v=vs.85%29.aspx. 
    DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); 

    /// <summary> 
    /// Declare a delegate for the notification event handler. 
    /// </summary> 
    /// <param name="sender">The object where the event handler is attached.</param> 
    /// <param name="e">The event data.</param> 
    public delegate void NotificationEventHandler(Object^ sender, EventArgs^ e); 

    /// <summary> 
    /// Class that generetaes USB Device Change notification events. 
    /// </summary> 
    /// <remarks> 
    /// A Form is not necessary. Any type wherein you can override WndProc() can be used. 
    /// </remarks> 
    public ref class EventNotifier : public Control 
    { 
    private: 
     /// <summary> 
     /// Raises the NotificationEvent. 
     /// </summary> 
     /// <param name="e">The event data.</param> 
     void RaiseNotificationEvent(EventArgs^ e) { 
      NotificationEvent(this, e); 
     } 

    protected: 
     /// <summary> 
     /// Overrides the base class WndProc method. 
     /// </summary> 
     /// <param name="message">The Windows Message to process. </param> 
     /// <remarks> 
     /// This method receives Windows Messages (WM_xxxxxxxxxx) and 
     /// raises our NotificationEvent as appropriate. Here you should 
     /// add any message filtering (e.g. for the WM_DEVICECHANGE) and 
     /// preprocessing before raising the event (or not). 
     /// </remarks> 
     virtual void WndProc(Message% message) override { 
      if(message.Msg == WM_DEVICECHANGE) 
      { 
       RaiseNotificationEvent(EventArgs::Empty); 
      } 
      __super::WndProc(message); 
     } 

    public: 
     /// <summary> 
     /// Creates a new instance of the EventNotifier class. 
     /// </summary> 
     EventNotifier(void) { 
      RequestNotifications(this->Handle); // Register ourselves as the Windows Message processor. 
     } 

     /// <summary> 
     /// Registers an object, identified by the handle, for 
     /// Windows WM_DEVICECHANGE messages. 
     /// </summary> 
     /// <param name="handle">The object's handle.</param> 
     bool RequestNotifications(IntPtr handle) { 
      DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; 

      ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); 
      NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 
      NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); 
      NotificationFilter.dbcc_reserved = 0; 
      NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; 
      return RegisterDeviceNotificationUM((HANDLE)handle, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE) != NULL; 
     } 

     /// <summary> 
     /// Defines the notification event. 
     /// </summary> 
     virtual event NotificationEventHandler^ NotificationEvent; 
    }; 
} 

然後,在 '接收器'(即訂閱消耗我們的NotificationEvent的對象),所有你需要做的是:

void Receiver::SomeFunction(void) 
{ 
    USBComms::EventNotifier usb = gcnew USBComms::EventNotifier(); 

    usb->NotificationEvent += gcnew USBComms::NotificationEventHandler(this, &Receiver::USBEvent); 
} 

void Receiver::USBEvent(Object^ sender, EventArgs^ e) 
{ 
    // Handle the event notification as appropriate. 
} 
+0

窗體是從控制和控制的後代無論如何都包裝一個win32窗口實例。我發現的唯一基於非窗口的方法是使用ManagementEventWatcher。但是這似乎有它自己的問題。 – Felix 2017-01-18 05:08:17

0

在Windows CE/Windows移動/ SmartDevice項目,標準Form不提供覆蓋WndProc方法,但可以通過根據Microsoft.WindowsCE.Forms.MessageWindow創建一個類來創建一個構造函數,該構造函數接受一個表單,將該表單保存在局部變量中,以便該表單上的方法可以是在檢測到消息時調用。這裏有一個縮小的例子來說明。希望這對CE/Windows Mobile世界中的某個人有所幫助。

public class MsgWindow : Microsoft.WindowsCE.Forms.MessageWindow { 

    public const int WM_SER = 0x500; 
    public const int WM_SER_SCANDONE = WM_SER + 0; 

    frmMain msgform { get; set; } 

    public MsgWindow(frmMain msgform) { 
     this.msgform = msgform; 
    } 

    protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message m) { 
     switch (m.Msg) { 
     case WM_SER_SCANDONE: 
      this.msgform.RespondToMessage(WM_SER_SCANDONE); 
      break; 
     default: 
      break; 
     } 
     base.WndProc(ref m); 
    } 

    } 

    public partial class frmMain : Form { 

    public frmMain() { 
     InitializeComponent(); 
    } 

    public void RespondToMessage(int nMsg) { 
     try { 
     switch (nMsg) { 
      case MsgWindow.WM_SER_SCANDONE: 
      // do something here based on the message 
      break; 
      default: 
      break; 
     } 
     } catch (Exception ex) { 
     MessageBox.Show(string.Format("{0} - {1}", ex.Message, ex.ToString()), "RespondToMessage() Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 
     // throw; 
     } 
    } 

    } 
相關問題