108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
# Demo RegisterDeviceNotification etc. Creates a hidden window to receive
|
|
# notifications. See serviceEvents.py for an example of a service doing
|
|
# that.
|
|
import sys
|
|
import time
|
|
|
|
import win32api
|
|
import win32con
|
|
import win32file
|
|
import win32gui
|
|
import win32gui_struct
|
|
import winnt
|
|
|
|
# These device GUIDs are from Ioevent.h in the Windows SDK. Ideally they
|
|
# could be collected somewhere for pywin32...
|
|
GUID_DEVINTERFACE_USB_DEVICE = "{A5DCBF10-6530-11D2-901F-00C04FB951ED}"
|
|
|
|
|
|
# WM_DEVICECHANGE message handler.
|
|
def OnDeviceChange(hwnd, msg, wp, lp):
|
|
# Unpack the 'lp' into the appropriate DEV_BROADCAST_* structure,
|
|
# using the self-identifying data inside the DEV_BROADCAST_HDR.
|
|
info = win32gui_struct.UnpackDEV_BROADCAST(lp)
|
|
print("Device change notification:", wp, str(info))
|
|
if (
|
|
wp == win32con.DBT_DEVICEQUERYREMOVE
|
|
and info.devicetype == win32con.DBT_DEVTYP_HANDLE
|
|
):
|
|
# Our handle is stored away in the structure - just close it
|
|
print("Device being removed - closing handle")
|
|
win32file.CloseHandle(info.handle)
|
|
# and cancel our notifications - if it gets plugged back in we get
|
|
# the same notification and try and close the same handle...
|
|
win32gui.UnregisterDeviceNotification(info.hdevnotify)
|
|
return True
|
|
|
|
|
|
def TestDeviceNotifications(dir_names):
|
|
wc = win32gui.WNDCLASS()
|
|
wc.lpszClassName = "test_devicenotify"
|
|
wc.style = win32con.CS_GLOBALCLASS | win32con.CS_VREDRAW | win32con.CS_HREDRAW
|
|
wc.hbrBackground = win32con.COLOR_WINDOW + 1
|
|
wc.lpfnWndProc = {win32con.WM_DEVICECHANGE: OnDeviceChange}
|
|
class_atom = win32gui.RegisterClass(wc)
|
|
hwnd = win32gui.CreateWindow(
|
|
wc.lpszClassName,
|
|
"Testing some devices",
|
|
# no need for it to be visible.
|
|
win32con.WS_CAPTION,
|
|
100,
|
|
100,
|
|
900,
|
|
900,
|
|
0,
|
|
0,
|
|
0,
|
|
None,
|
|
)
|
|
|
|
hdevs = []
|
|
# Watch for all USB device notifications
|
|
filter = win32gui_struct.PackDEV_BROADCAST_DEVICEINTERFACE(
|
|
GUID_DEVINTERFACE_USB_DEVICE
|
|
)
|
|
hdev = win32gui.RegisterDeviceNotification(
|
|
hwnd, filter, win32con.DEVICE_NOTIFY_WINDOW_HANDLE
|
|
)
|
|
hdevs.append(hdev)
|
|
# and create handles for all specified directories
|
|
for d in dir_names:
|
|
hdir = win32file.CreateFile(
|
|
d,
|
|
winnt.FILE_LIST_DIRECTORY,
|
|
winnt.FILE_SHARE_READ | winnt.FILE_SHARE_WRITE | winnt.FILE_SHARE_DELETE,
|
|
None, # security attributes
|
|
win32con.OPEN_EXISTING,
|
|
win32con.FILE_FLAG_BACKUP_SEMANTICS
|
|
| win32con.FILE_FLAG_OVERLAPPED, # required privileges: SE_BACKUP_NAME and SE_RESTORE_NAME.
|
|
None,
|
|
)
|
|
|
|
filter = win32gui_struct.PackDEV_BROADCAST_HANDLE(hdir)
|
|
hdev = win32gui.RegisterDeviceNotification(
|
|
hwnd, filter, win32con.DEVICE_NOTIFY_WINDOW_HANDLE
|
|
)
|
|
hdevs.append(hdev)
|
|
|
|
# now start a message pump and wait for messages to be delivered.
|
|
print("Watching", len(hdevs), "handles - press Ctrl+C to terminate, or")
|
|
print("add and remove some USB devices...")
|
|
if not dir_names:
|
|
print("(Note you can also pass paths to watch on the command-line - eg,")
|
|
print("pass the root of an inserted USB stick to see events specific to")
|
|
print("that volume)")
|
|
while 1:
|
|
win32gui.PumpWaitingMessages()
|
|
time.sleep(0.01)
|
|
win32gui.DestroyWindow(hwnd)
|
|
win32gui.UnregisterClass(wc.lpszClassName, None)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# optionally pass device/directory names to watch for notifications.
|
|
# Eg, plug in a USB device - assume it connects as E: - then execute:
|
|
# % win32gui_devicenotify.py E:
|
|
# Then remove and insert the device.
|
|
TestDeviceNotifications(sys.argv[1:])
|