The following example shows how to modify the HookingTheWndProc example to listen for USB device change notifications. This example is windows specific and uses ctypes which is included in Python 2.5. To register for a specific USB device you will also need the comtypes GUID ctypes structure which you can get from http://svn.python.org/projects/ctypes/trunk/comtypes/comtypes/GUID.py

Code Sample

   1 #Modified from: http://wiki.wxpython.org/HookingTheWndProc
   2 ##########################################################################
   3 ##
   4 ##  This is a modification of the original WndProcHookMixin by Kevin Moore,
   5 ##  modified to use ctypes only instead of pywin32, so it can be used
   6 ##  with no additional dependencies in Python 2.5
   7 ##
   8 ##########################################################################
   9 
  10 
  11 import sys
  12 import ctypes, GUID
  13 from ctypes import c_long, c_int, wintypes
  14 
  15 import wx
  16 
  17 
  18 GWL_WNDPROC = -4
  19 WM_DESTROY  = 2
  20 DBT_DEVTYP_DEVICEINTERFACE = 0x00000005  # device interface class
  21 DBT_DEVICEREMOVECOMPLETE = 0x8004  # device is gone
  22 DBT_DEVICEARRIVAL = 0x8000  # system detected a new device
  23 WM_DEVICECHANGE = 0x0219
  24 
  25 ## It's probably not neccesary to make this distinction, but it never hurts to be safe
  26 if 'unicode' in wx.PlatformInfo:
  27     SetWindowLong = ctypes.windll.user32.SetWindowLongW
  28     CallWindowProc = ctypes.windll.user32.CallWindowProcW
  29 else:
  30     SetWindowLong = ctypes.windll.user32.SetWindowLongA
  31     CallWindowProc = ctypes.windll.user32.CallWindowProcA
  32 
  33 ## Create a type that will be used to cast a python callable to a c callback function
  34 ## first arg is return type, the rest are the arguments
  35 #WndProcType = ctypes.WINFUNCTYPE(c_int, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
  36 WndProcType = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_int, ctypes.c_uint, ctypes.c_int, ctypes.c_int)
  37 
  38 if 'unicode' in wx.PlatformInfo:
  39     RegisterDeviceNotification = ctypes.windll.user32.RegisterDeviceNotificationW
  40 else:
  41     RegisterDeviceNotification = ctypes.windll.user32.RegisterDeviceNotificationA
  42 RegisterDeviceNotification.restype = wintypes.HANDLE
  43 RegisterDeviceNotification.argtypes = [wintypes.HANDLE, wintypes.c_void_p, wintypes.DWORD]
  44 
  45 UnregisterDeviceNotification = ctypes.windll.user32.UnregisterDeviceNotification
  46 UnregisterDeviceNotification.restype = wintypes.BOOL
  47 UnregisterDeviceNotification.argtypes = [wintypes.HANDLE]
  48 
  49 class DEV_BROADCAST_DEVICEINTERFACE(ctypes.Structure):
  50     _fields_ = [("dbcc_size", ctypes.c_ulong),
  51                   ("dbcc_devicetype", ctypes.c_ulong),
  52                   ("dbcc_reserved", ctypes.c_ulong),
  53                   ("dbcc_classguid", GUID.GUID),
  54                   ("dbcc_name", ctypes.c_wchar * 256)]
  55 
  56 class DEV_BROADCAST_HDR(ctypes.Structure):
  57     _fields_ = [("dbch_size", wintypes.DWORD),
  58                 ("dbch_devicetype", wintypes.DWORD),
  59                 ("dbch_reserved", wintypes.DWORD)]
  60 
  61 
  62 class WndProcHookMixin:
  63     """
  64     This class can be mixed in with any wxWindows window class in order to hook it's WndProc function. 
  65     You supply a set of message handler functions with the function addMsgHandler. When the window receives that
  66     message, the specified handler function is invoked. If the handler explicitly returns False then the standard 
  67     WindowProc will not be invoked with the message. You can really screw things up this way, so be careful. 
  68     This is not the correct way to deal with standard windows messages in wxPython (i.e. button click, paint, etc) 
  69     use the standard wxWindows method of binding events for that. This is really for capturing custom windows messages
  70     or windows messages that are outside of the wxWindows world.
  71     """
  72     def __init__(self):
  73         self.__msgDict = {}
  74         ## We need to maintain a reference to the WndProcType wrapper
  75         ## because ctypes doesn't
  76         self.__localWndProcWrapped = None 
  77         self.rtnHandles = []
  78 
  79     def hookWndProc(self):
  80         self.__localWndProcWrapped = WndProcType(self.localWndProc)
  81         self.__oldWndProc = SetWindowLong(self.GetHandle(),
  82                                         GWL_WNDPROC,
  83                                         self.__localWndProcWrapped)
  84     def unhookWndProc(self):
  85         SetWindowLong(self.GetHandle(),
  86                         GWL_WNDPROC,
  87                         self.__oldWndProc)
  88 
  89         ## Allow the ctypes wrapper to be garbage collected
  90         self.__localWndProcWrapped = None
  91 
  92     def addMsgHandler(self,messageNumber,handler):
  93         self.__msgDict[messageNumber] = handler
  94 
  95     def localWndProc(self, hWnd, msg, wParam, lParam):
  96         # call the handler if one exists
  97         # performance note: "in" is the fastest way to check for a key
  98         # when the key is unlikely to be found
  99         # (which is the case here, since most messages will not have handlers).
 100         # This is called via a ctypes shim for every single windows message 
 101         # so dispatch speed is important
 102         if msg in self.__msgDict:
 103             # if the handler returns false, we terminate the message here
 104             # Note that we don't pass the hwnd or the message along
 105             # Handlers should be really, really careful about returning false here
 106             if self.__msgDict[msg](wParam,lParam) == False:
 107                 return
 108 
 109         # Restore the old WndProc on Destroy.
 110         if msg == WM_DESTROY: self.unhookWndProc()
 111 
 112         return CallWindowProc(self.__oldWndProc,
 113                                 hWnd, msg, wParam, lParam)
 114 
 115     def registerDeviceNotification(self, guid, devicetype=DBT_DEVTYP_DEVICEINTERFACE):
 116         devIF = DEV_BROADCAST_DEVICEINTERFACE()
 117         devIF.dbcc_size = ctypes.sizeof(DEV_BROADCAST_DEVICEINTERFACE)
 118         devIF.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
 119 
 120         if guid:
 121             devIF.dbcc_classguid = GUID.GUID(guid)
 122         return RegisterDeviceNotification(self.GetHandle(), ctypes.byref(devIF), 0)
 123 
 124     def unregisterDeviceNotification(self, handle):
 125         if UnregisterDeviceNotification(handle) == 0:
 126             raise Exception("Unable to unregister device notification messages")
 127 
 128 
 129 # a simple example
 130 if __name__ == "__main__":
 131 
 132     class MyFrame(wx.Frame,WndProcHookMixin):
 133         def __init__(self,parent):
 134             WndProcHookMixin.__init__(self)
 135             wx.Frame.__init__(self,parent,-1,"Insert and Remove USE Device and Watch STDOUT",size=(640,480))
 136 
 137             self.Bind(wx.EVT_CLOSE, self.onClose)
 138 
 139             #Change the following guid to the GUID of the device you want notifications for
 140             self.devNotifyHandle = self.registerDeviceNotification(guid="{3c5e1462-5695-4e18-876b-f3f3d08aaf18}")
 141 
 142             self.addMsgHandler(WM_DEVICECHANGE, self.onDeviceChange)
 143             self.hookWndProc()
 144 
 145         def onDeviceChange(self,wParam,lParam):
 146             print "WM_DEVICECHANGE [WPARAM:%i][LPARAM:%i]"%(wParam,lParam)
 147 
 148             if wParam == DBT_DEVICEARRIVAL:
 149                 print "Device Arrival"
 150             elif wParam == DBT_DEVICEREMOVECOMPLETE:
 151                 print "Device Remvoed"
 152 
 153             if lParam:
 154                 dbh = DEV_BROADCAST_HDR.from_address(lParam)
 155                 if dbh.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE:
 156                     dbd = DEV_BROADCAST_DEVICEINTERFACE.from_address(lParam)
 157                     #Verify that the USB VID and PID match our assigned VID and PID
 158                     if 'Vid_10c4&Pid_8382' in dbd.dbcc_name:
 159                         print "Was Our USB Device"
 160 
 161             return True
 162 
 163         def onClose(self, event):
 164             self.unregisterDeviceNotification(self.devNotifyHandle)
 165             event.Skip()
 166 
 167 
 168     app = wx.App(False)
 169     frame = MyFrame(None)
 170     frame.Show()
 171     app.MainLoop()

MonitoringWindowsUsb (last edited 2009-12-10 01:58:35 by vpn-8061f573)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.