如何检测USB设备的连接/断开?

4

我不太熟悉使用Delphi连接USB设备,并且对编写设备驱动程序的细节知之甚少(虽然在学习GoASM汇编时遇到过一些)。

该设备可能是USB调制解调器或USB打印机。

我需要一个方向和有关此主题的示例代码。


2
尝试这个:http://delphiheaven.blogspot.com/2007/03/detect-if-usb-device-is-connected-or.html - PresleyDias
@PresleyDias:你能把你的评论迁移成一个答案并详细阐述一下吗,这样我就可以接受它了吗? - menjaraz
@PresleyDias,但你链接中的帖子是关于USB设备连接/断开通知的。我认为这个问题是关于“是否连接了特定的USB设备?” - TLama
1
如果您知道设备的一些特征,可以使用纯WinAPI(无需驱动程序代码)枚举USB总线,并在已连接设备列表中查找您的设备。我做到了,不幸的是我的代码太长,无法作为答案发送。 - kludg
@Serg:看起来这个答案在Linux中做了类似的事情,不是吗? - menjaraz
显示剩余5条评论
2个回答

9
这篇文章来自于检测USB设备连接状态
 unit U_Usb;

 interface

uses
Windows, Messages, SysUtils, Classes, Forms;

type

PDevBroadcastHdr = ^DEV_BROADCAST_HDR;
DEV_BROADCAST_HDR = packed record
dbch_size: DWORD;
dbch_devicetype: DWORD;
dbch_reserved: DWORD;
end;

PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE;
 DEV_BROADCAST_DEVICEINTERFACE = record
 dbcc_size: DWORD;
 dbcc_devicetype: DWORD;
 dbcc_reserved: DWORD;
  dbcc_classguid: TGUID;
  dbcc_name: short;
 end;

const
  GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
  DBT_DEVICEARRIVAL = $8000; // system detected a new device
  DBT_DEVICEREMOVECOMPLETE = $8004; // device is gone
  DBT_DEVTYP_DEVICEINTERFACE = $00000005; // device interface class

type

 TComponentUSB = class(TComponent)
   private
   FWindowHandle: HWND;
   FOnUSBArrival: TNotifyEvent;
   FOnUSBRemove: TNotifyEvent;
   procedure WndProc(var Msg: TMessage);
   function USBRegister: Boolean;
   protected
   procedure WMDeviceChange(var Msg: TMessage); dynamic;
  public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
  published
    property OnUSBArrival: TNotifyEvent read FOnUSBArrival write FOnUSBArrival;
    property OnUSBRemove: TNotifyEvent read FOnUSBRemove write FOnUSBRemove;
  end;

  implementation

constructor TComponentUSB.Create(AOwner: TComponent);
   begin
     inherited Create(AOwner);
     FWindowHandle := AllocateHWnd(WndProc);
     USBRegister;
   end;

   destructor TComponentUSB.Destroy;
    begin
   DeallocateHWnd(FWindowHandle);
    inherited Destroy;
   end;

 procedure TComponentUSB.WndProc(var Msg: TMessage);
     begin
     if (Msg.Msg = WM_DEVICECHANGE) then
      begin
      try
      WMDeviceChange(Msg);
    except
  Application.HandleException(Self);
   end;
   end
  else
     Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
   end;

  procedure TComponentUSB.WMDeviceChange(var Msg: TMessage);
   var
   devType: Integer;
     Datos: PDevBroadcastHdr;
   begin
    if (Msg.wParam = DBT_DEVICEARRIVAL) or (Msg.wParam = DBT_DEVICEREMOVECOMPLETE) then
    begin
  Datos := PDevBroadcastHdr(Msg.lParam);
    devType := Datos^.dbch_devicetype;
     if devType = DBT_DEVTYP_DEVICEINTERFACE then
    begin // USB Device
     if Msg.wParam = DBT_DEVICEARRIVAL then
     begin
      if Assigned(FOnUSBArrival) then
       FOnUSBArrival(Self);
       end
        else
      begin
     if Assigned(FOnUSBRemove) then
      FOnUSBRemove(Self);
   end;
  end;
   end;
  end;

  function TComponentUSB.USBRegister: Boolean;
    var
      dbi: DEV_BROADCAST_DEVICEINTERFACE;
       Size: Integer;
     r: Pointer;
      begin
     Result := False;
     Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
      ZeroMemory(@dbi, Size);
      dbi.dbcc_size := Size;
      dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
     dbi.dbcc_reserved := 0;
     dbi.dbcc_classguid := GUID_DEVINTERFACE_USB_DEVICE;
     dbi.dbcc_name := 0;

     r := RegisterDeviceNotification(FWindowHandle, @dbi,
      DEVICE_NOTIFY_WINDOW_HANDLE
     );
      if Assigned(r) then Result := True;
    end;

    end. 

谢谢!这将是一个良好的开端,我现在可以清楚地看到前进的方向。 - menjaraz
好的,没问题,很高兴能帮忙。 - PresleyDias

0
你可以使用一些shell脚本来实现。 当设备连接时,命令lsusb会显示设备并在设备断开连接后从列表中删除。 因此,在您的shell脚本中,您需要找到旧列表和当前列表之间的差异。 最后,您需要将此脚本作为cron作业运行,以便在频繁的时间间隔内进行检查。
敬礼, Barun Parichha

1
欢迎来到stackoverflow。感谢您的回答,确实很有价值,但不适用于在Windows环境下使用Delphi检测USB的情况。 - menjaraz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接