根据 http://delphi.cjcsoft.net/viewthread.php?tid=48860 文章内容,将类似 \\?\USB#Vid_4146&Pid_d2b5#0005050400044#{a5dcbf10-6530-11d2-901f-00c04fb951ed} 转化为更易读的类型,例如
USB Inserted
Device Type = USB Mass Storage Device
Driver Name = Disk drive
Friendly Name = I0MEGA UMni1GB*IOM2J4 USB Device
之前《关于监视插入U盘的问题(1)》中给出了接收 WM_DEVICECHANGE 消息的方法。从资料中可以看出,直接处理这个消息能够获得当前系统发生变化的盘符,但是无法处理未产生盘符变化(未分区或者其他USB设备)。对于这样的问题,可以使用RegisterDeviceNotification来向系统注册一个回调函数,并且设置好只通知USB设备变化,通过这样的方法能够取得发生变化的USB设备的信息,之后再通过查询注册表对照出更易读的信息。
文章还指出这样的转换是通过读取注册表来完成的。
我编写了如下例子,实践证明这个程序工作很好。除了普通的U盘,我还地尝试了一个 USB2UART 的 Cable,可以看出工作正常。
测试环境为 Win7+Delphi10,不需要管理员权限运行程序即可。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,MahUSB; type TForm1 = class(TForm) procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } FUsb : TUsbClass; procedure UsbIN(ASender : TObject; const ADevType,ADriverName, AFriendlyName : string); procedure UsbOUT(ASender : TObject; const ADevType,ADriverName, AFriendlyName : string); public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin FreeAndNil(FUsb); end; procedure TForm1.FormShow(Sender: TObject); begin FUsb := TUsbClass.Create; FUsb.OnUsbInsertion := UsbIN; FUsb.OnUsbRemoval := UsbOUT; end; procedure TForm1.UsbIN(ASender : TObject; const ADevType,ADriverName, AFriendlyName : string); begin showmessage('USB Inserted - Device Type = ' + ADevType + #13#10 + 'Driver Name = ' + ADriverName + #13+#10 + 'Friendly Name = ' + AFriendlyName); end; procedure TForm1.UsbOUT(ASender : TObject; const ADevType,ADriverName, AFriendlyName : string); begin showmessage('USB Removed - Device Type = ' + ADevType + #13#10 + 'Driver Name = ' + ADriverName + #13+#10 + 'Friendly Name = ' + AFriendlyName); end; end. ============================================================================================ unit MahUSB; interface uses Windows, Messages, SysUtils, Classes, Registry, Masks; type { Event Types } TOnUsbChangeEvent = procedure(AObject : TObject; const ADevType,ADriverName, AFriendlyName : string) of object; { USB Class } TUsbClass = class(TObject) private FHandle : HWND; FOnUsbRemoval, FOnUsbInsertion : TOnUsbChangeEvent; procedure GetUsbInfo(const ADeviceString : string; out ADevType,ADriverDesc, AFriendlyName : string); procedure WinMethod(var AMessage : TMessage); procedure RegisterUsbHandler; procedure WMDeviceChange(var AMessage : TMessage); public constructor Create; destructor Destroy; override; property OnUsbInsertion : TOnUsbChangeEvent read FOnUsbInsertion write FOnUsbInsertion; property OnUsbRemoval : TOnUsbChangeEvent read FOnUsbRemoval write FOnUsbRemoval; end; // ----------------------------------------------------------------------------- implementation type // Win API Definitions PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE; DEV_BROADCAST_DEVICEINTERFACE = record dbcc_size : DWORD; dbcc_devicetype : DWORD; dbcc_reserved : DWORD; dbcc_classguid : TGUID; dbcc_name : char; end; const // Miscellaneous GUID_DEVINTF_USB_DEVICE : TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}'; USB_INTERFACE = $00000005; // Device interface class USB_INSERTION = $8000; // System detected a new device USB_REMOVAL = $8004; // Device is gone // Registry Keys USBKEY = 'SYSTEM\CurrentControlSet\Enum\USB\%s\%s'; USBSTORKEY = 'SYSTEM\CurrentControlSet\Enum\USBSTOR'; SUBKEY1 = USBSTORKEY + '\%s'; SUBKEY2 = SUBKEY1 + '\%s'; constructor TUsbClass.Create; begin inherited Create; FHandle := AllocateHWnd(WinMethod); RegisterUsbHandler; end; destructor TUsbClass.Destroy; begin DeallocateHWnd(FHandle); inherited Destroy; end; procedure TUsbClass.GetUsbInfo(const ADeviceString : string; out ADevType,ADriverDesc, AFriendlyName : string); var sWork,sKey1,sKey2 : string; oKeys,oSubKeys : TStringList; oReg : TRegistry; i,ii : integer; bFound : boolean; begin ADevType := ''; ADriverDesc := ''; AFriendlyName := ''; if ADeviceString<>'' then begin bFound := false; oReg := TRegistry.Create; oReg.RootKey := HKEY_LOCAL_MACHINE; // Extract the portions of the string we need for registry. eg. // \\?\USB#Vid_4146&Pid_d2b5#0005050400044#{a5dcbf10- ..... -54334fb951ed} // We need sKey1='Vid_4146&Pid_d2b5' and sKey2='0005050400044' sWork := copy(ADeviceString,pos('#',ADeviceString) + 1,1026); sKey1 := copy(sWork,1,pos('#',sWork) - 1); sWork := copy(sWork,pos('#',sWork) + 1,1026); sKey2 := copy(sWork,1,pos('#',sWork) - 1); // Get the Device type description from \USB key if oReg.OpenKeyReadOnly(Format(USBKEY,[skey1,sKey2])) then begin ADevType := oReg.ReadString('DeviceDesc'); oReg.CloseKey; oKeys := TStringList.Create; oSubKeys := TStringList.Create; // Get list of keys in \USBSTOR and enumerate each key // for a key that matches our sKey2='0005050400044' // NOTE : The entry we are looking for normally has '&0' // appended to it eg. '0005050400044&0' if oReg.OpenKeyReadOnly(USBSTORKEY) then begin oReg.GetKeyNames(oKeys); oReg.CloseKey; // Iterate through list to find our sKey2 for i := 0 to oKeys.Count - 1 do begin if oReg.OpenKeyReadOnly(Format(SUBKEY1,[oKeys[i]])) then begin oReg.GetKeyNames(oSubKeys); oReg.CloseKey; for ii := 0 to oSubKeys.Count - 1 do begin if MatchesMask(oSubKeys[ii],sKey2 + '*') then begin // Got a match?, get the actual desc and friendly name if oReg.OpenKeyReadOnly(Format(SUBKEY2,[oKeys[i], oSubKeys[ii]])) then begin ADriverDesc := oReg.ReadString('DeviceDesc'); AFriendlyName := oReg.ReadString('FriendlyName'); oReg.CloseKey; end; bFound := true; end; end; end; if bFound then break; end; end; FreeAndNil(oKeys); FreeAndNil(oSubKeys); end; FreeAndNil(oReg); end; end; procedure TUsbClass.WMDeviceChange(var AMessage : TMessage); var iDevType : integer; sDevString,sDevType, sDriverName,sFriendlyName : string; pData : PDevBroadcastDeviceInterface; begin if (AMessage.wParam = USB_INSERTION) or (AMessage.wParam = USB_REMOVAL) then begin pData := PDevBroadcastDeviceInterface(AMessage.LParam); iDevType := pData^.dbcc_devicetype; // Is it a USB Interface Device ? if iDevType = USB_INTERFACE then begin sDevString := PChar(@pData^.dbcc_name); GetUsbInfo(sDevString,sDevType,sDriverName,sFriendlyName); // Trigger Events if assigned if (AMessage.wParam = USB_INSERTION) and Assigned(FOnUsbInsertion) then FOnUsbInsertion(self,sDevType,sDriverName,sFriendlyName); if (AMessage.wParam = USB_REMOVAL) and Assigned(FOnUsbRemoval) then FOnUsbRemoval(self,sDevType,sDriverName,sFriendlyName); end; end; end; procedure TUsbClass.WinMethod(var AMessage : TMessage); begin if (AMessage.Msg = WM_DEVICECHANGE) then WMDeviceChange(AMessage) else AMessage.Result := DefWindowProc(FHandle,AMessage.Msg, AMessage.wParam,AMessage.lParam); end; procedure TUsbClass.RegisterUsbHandler; var rDbi : DEV_BROADCAST_DEVICEINTERFACE; iSize : integer; begin iSize := SizeOf(DEV_BROADCAST_DEVICEINTERFACE); ZeroMemory(@rDbi,iSize); rDbi.dbcc_size := iSize; rDbi.dbcc_devicetype := USB_INTERFACE; rDbi.dbcc_reserved := 0; rDbi.dbcc_classguid := GUID_DEVINTF_USB_DEVICE; rDbi.dbcc_name := #0; RegisterDeviceNotification(FHandle,@rDbi,DEVICE_NOTIFY_WINDOW_HANDLE); end; end.
比较好用,我是D11+win11,32位和64位都可以使用,不过有个问题,我用的是usb2uart,虽然type信息显示出来了,但没有对应的端口号,这样就无法做到自动连接设备了,这个有解吗?
Hi,这个问题我很久没有研究了,推荐你看看下面的文章?
https://blog.csdn.net/u013919153/article/details/120033220