Обнаружение вставки USB-устройства на Windows 10 - PullRequest
4 голосов
/ 22 января 2020

Я не могу получить следующий код для Обнаружение вставки USB-устройства для работы на моем Windows 10 (64-битном) компьютере с Python 3.7.

import win32serviceutil
import win32service
import win32event
import servicemanager

import win32gui
import win32gui_struct
struct = win32gui_struct.struct
pywintypes = win32gui_struct.pywintypes
import win32con

GUID_DEVINTERFACE_USB_DEVICE = "{A5DCBF10-6530-11D2-901F-00C04FB951ED}"
DBT_DEVICEARRIVAL = 0x8000
DBT_DEVICEREMOVECOMPLETE = 0x8004

import ctypes

#
# Cut-down clone of UnpackDEV_BROADCAST from win32gui_struct, to be
# used for monkey-patching said module with correct handling
# of the "name" param of DBT_DEVTYPE_DEVICEINTERFACE
#
def _UnpackDEV_BROADCAST (lparam):
  if lparam == 0: return None
  hdr_format = "iii"
  hdr_size = struct.calcsize (hdr_format)
  hdr_buf = win32gui.PyGetMemory (lparam, hdr_size)
  size, devtype, reserved = struct.unpack ("iii", hdr_buf)
  # Due to x64 alignment issues, we need to use the full format string over
  # the entire buffer.  ie, on x64:
  # calcsize('iiiP') != calcsize('iii')+calcsize('P')
  buf = win32gui.PyGetMemory (lparam, size)

  extra = {}
  if devtype == win32con.DBT_DEVTYP_DEVICEINTERFACE:
    fmt = hdr_format + "16s"
    _, _, _, guid_bytes = struct.unpack (fmt, buf[:struct.calcsize(fmt)])
    extra['classguid'] = pywintypes.IID (guid_bytes, True)
    extra['name'] = ctypes.wstring_at (lparam + struct.calcsize(fmt))
  else:
    raise NotImplementedError("unknown device type %d" % (devtype,))
  return win32gui_struct.DEV_BROADCAST_INFO(devtype, **extra)
win32gui_struct.UnpackDEV_BROADCAST = _UnpackDEV_BROADCAST

class DeviceEventService (win32serviceutil.ServiceFramework):

  _svc_name_ = "DevEventHandler"
  _svc_display_name_ = "Device Event Handler"
  _svc_description_ = "Handle device notification events"

  def __init__(self, args):
    win32serviceutil.ServiceFramework.__init__ (self, args)
    self.hWaitStop = win32event.CreateEvent (None, 0, 0, None)
    #
    # Specify that we're interested in device interface
    # events for USB devices
    #
    filter = win32gui_struct.PackDEV_BROADCAST_DEVICEINTERFACE (
      GUID_DEVINTERFACE_USB_DEVICE
    )
    self.hDevNotify = win32gui.RegisterDeviceNotification (
      self.ssh, # copy of the service status handle
      filter,
      win32con.DEVICE_NOTIFY_SERVICE_HANDLE
    )

  #
  # Add to the list of controls already handled by the underlying
  # ServiceFramework class. We're only interested in device events
  #
  def GetAcceptedControls(self):
    rc = win32serviceutil.ServiceFramework.GetAcceptedControls (self)
    rc |= win32service.SERVICE_CONTROL_DEVICEEVENT
    return rc

  #
  # Handle non-standard service events (including our device broadcasts)
  # by logging to the Application event log
  #
  def SvcOtherEx(self, control, event_type, data):
    if control == win32service.SERVICE_CONTROL_DEVICEEVENT:
      info = win32gui_struct.UnpackDEV_BROADCAST(data)
      #
      # This is the key bit here where you'll presumably
      # do something other than log the event. Perhaps pulse
      # a named event or write to a secure pipe etc. etc.
      #
      if event_type == DBT_DEVICEARRIVAL:
        servicemanager.LogMsg (
          servicemanager.EVENTLOG_INFORMATION_TYPE,
          0xF000,
          ("Device %s arrived" % info.name, '')
        )
      elif event_type == DBT_DEVICEREMOVECOMPLETE:
        servicemanager.LogMsg (
          servicemanager.EVENTLOG_INFORMATION_TYPE,
          0xF000,
          ("Device %s removed" % info.name, '')
        )

  #
  # Standard stuff for stopping and running service; nothing
  # specific to device notifications
  #
  def SvcStop(self):
    self.ReportServiceStatus (win32service.SERVICE_STOP_PENDING)
    win32event.SetEvent (self.hWaitStop)

  def SvcDoRun(self):
    win32event.WaitForSingleObject (self.hWaitStop, win32event.INFINITE)
    servicemanager.LogMsg (
      servicemanager.EVENTLOG_INFORMATION_TYPE,
      servicemanager.PYS_SERVICE_STOPPED,
      (self._svc_name_, '')
    )

if __name__=='__main__':
  win32serviceutil.HandleCommandLine (DeviceEventService)
  1. Я запускаю сценарий с помощью следующей команды: python main.py start

  2. Затем в командной строке появляются следующие сообщения об ошибках:

Starting service DevEventHandler Error starting service: Access denied

Затем я запустил скрипт с правами администратора: runas /user:administrator "python main.py start"

В командной строке появилось еще одно сообщение об ошибке:

Starting service DevEventHandler Error starting service: The specified service does not exist as an installed service.

Как исправить ошибку «Указанная служба не существует как установленная служба»?

Ответы [ 2 ]

4 голосов
/ 12 марта 2020

Я тестировал с Python 3.8.2 x64.

  1. Установка pywin32 (pip install pywin32)
  2. Установка текущей / последней версии (1.5) модуля WMI из https://github.com/tjguk/wmi (pip install -e git+https://github.com/tjguk/wmi.git#egg=wmi)
  3. запустить скрипт (test.py в моем случае), например:
import wmi

raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_USBHub\'"
c = wmi.WMI ()
watcher = c.watch_for(raw_wql=raw_wql)
while 1:
  usb = watcher ()
  print(usb)
подключите USB-устройство. Вывод выглядит так:
(wmi-py) C:\Users\USER\Source\wmi-py>py test.py

instance of Win32_USBHub
{
        Caption = "USB Composite Device";
        ConfigManagerErrorCode = 0;
        ConfigManagerUserConfig = FALSE;
        CreationClassName = "Win32_USBHub";
        Description = "USB Composite Device";
...

Большое спасибо автору модуля WMI и обсуждению Windows ботаников здесь Обнаружение вставки и извлечения USB-накопителя с использованием сервиса windows и c#

1 голос
/ 12 марта 2020

Я попытался запустить скрипт с аргументом debug и появилось сообщение о том, что служба не установлена. Попробуйте сначала набрать

python main.py install

, затем

python main.py start

...