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()