要与微控制器通信,我使用串行端口.我使用TCommPortDriver 2.1工作正常.但是,它缺乏检测新组合的添加或删除的能力.这会在会话期间定期发生.
更新1
我尝试了RRUZ的第一个建议,并把它变成了一个独立的程序.当电缆插入或拔出时,它会对WM_DEVICECHANGE作出反应,但WParam不会显示设备的到达或移除.结果是:
msg = 537,wparam = 7,lparam = 0 msg = 537,lparam = 0
插入USB电缆时会发送第一条消息,插入USB电缆时会发送下一条消息.
消息部分显示WM_DEVICECHANGE消息(537),但WParam为7,不是WM_DEVICECHANGE或DBT_DEVICEARRIVAL.我稍微修改了代码以便处理消息,但是当LParam为零时,这是没用的.结果与VCL和FMX相同.作为检查,请参阅下面的代码.
更新2
我现在运行WMI代码.它只在添加COM端口时触发,当一个端口被移除时没有反应.结果:
TargetInstance.ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} TargetInstance.Description : Arduino Mega ADK R3 TargetInstance.Name : Arduino Mega ADK R3 (COM4) TargetInstance.PNPDeviceID : USB\VID_2341&PID_0044\64935343733351E0E1D1 TargetInstance.Status : OK
这可以解释一个事实,在其他代码中,这不被视为添加COM端口?它似乎将新连接视为USB端口(实际上是什么). Arduino驱动程序将其转换为COM端口,但WMI无法识别. Windows消息传递’看到’COM端口更改但无法检测是否添加或删除了它.
无论如何:设备更改工作.我只需要枚举COM端口,看看哪个实际存在,这是我已经手动完成的.现在我可以使用WM_DEVICECHANGE自动执行此操作.我只是向CPDrv组件添加一个事件.
感谢RRUZ的代码和帮助!
unit dev_change; interface uses Winapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,Vcl.Controls,Vcl.Forms,Vcl.Dialogs,Vcl.StdCtrls; type TProc = procedure (text: string) of object; BroadcastHdr = ^DEV_BROADCAST_HDR; DEV_BROADCAST_HDR = packed record dbch_size: DWORD; dbch_devicetype: DWORD; dbch_reserved: DWORD; end; TDevBroadcastHdr = DEV_BROADCAST_HDR; type PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE; DEV_BROADCAST_DEVICEINTERFACE = record dbcc_size: DWORD; dbcc_devicetype: DWORD; dbcc_reserved: DWORD; dbcc_classguid: TGUID; dbcc_name: Char; end; TDevBroadcastDeviceInterface = DEV_BROADCAST_DEVICEINTERFACE; const DBT_DEVICESOMETHING = $0007; DBT_DEVICEARRIVAL = $8000; DBT_DEVICEREMOVECOMPLETE = $8004; DBT_DEVTYP_DEVICEINTERFACE = $00000005; type TDeviceNotifyProc = procedure(Sender: TObject; const DeviceName: String) of Object; TDeviceNotifier = class private hRecipient: HWND; FNotificationHandle: Pointer; FDeviceArrival: TDeviceNotifyProc; FDeviceRemoval: TDeviceNotifyProc; FOnWin: TProc; procedure WndProc(var Msg: TMessage); public constructor Create(GUID_DEVINTERFACE : TGUID); property OnDeviceArrival: TDeviceNotifyProc read FDeviceArrival write FDeviceArrival; property OnDeviceRemoval: TDeviceNotifyProc read FDeviceRemoval write FDeviceRemoval; destructor Destroy; override; property OnWin: TProc read FOnWin write FOnWin; end; TForm1 = class(TForm) Memo: TMemo; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } DeviceNotifier : TDeviceNotifier; public { Public declarations } procedure arrival(Sender: TObject; const DeviceName: String); procedure report (text: string); end; var Form1: TForm1; implementation {$R *.dfm} constructor TDeviceNotifier.Create(GUID_DEVINTERFACE : TGUID); var NotificationFilter: TDevBroadcastDeviceInterface; begin inherited Create; hRecipient := AllocateHWnd(WndProc); ZeroMemory (@NotificationFilter,SizeOf(NotificationFilter)); NotificationFilter.dbcc_size := SizeOf(NotificationFilter); NotificationFilter.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE; NotificationFilter.dbcc_classguid := GUID_DEVINTERFACE; //register the device class to monitor FNotificationHandle := RegisterDeviceNotification(hRecipient,@NotificationFilter,DEVICE_NOTIFY_WINDOW_HANDLE); end; procedure TDeviceNotifier.WndProc(var Msg: TMessage); var Dbi: PDevBroadcastDeviceInterface; begin OnWin (Format ('msg = %d,wparam = %d,lparam = %d',[msg.Msg,msg.WParam,msg.LParam])); with Msg do if (Msg = WM_DEVICECHANGE) and ((WParam = DBT_DEVICEARRIVAL) or (WParam = DBT_DEVICEREMOVECOMPLETE) or (WParam = DBT_DEVICESOMETHING)) then try Dbi := PDevBroadcastDeviceInterface (LParam); if Dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE then begin if WParam = DBT_DEVICEARRIVAL then begin if Assigned(FDeviceArrival) then FDeviceArrival(Self,PChar(@Dbi.dbcc_name)); end else if WParam = DBT_DEVICEREMOVECOMPLETE then begin if Assigned(FDeviceRemoval) then FDeviceRemoval(Self,PChar(@Dbi.dbcc_name)); end; end; except Result := DefWindowProc(hRecipient,Msg,WParam,LParam); end else Result := DefWindowProc(hRecipient,LParam); end; destructor TDeviceNotifier.Destroy; begin UnregisterDeviceNotification(FNotificationHandle); DeallocateHWnd(hRecipient); inherited; end; procedure TForm1.arrival(Sender: TObject; const DeviceName: String); begin report (DeviceName); ShowMessage(DeviceName); end; procedure TForm1.FormCreate(Sender: TObject); const GUID_DEVINTERFACE_COMPORT : TGUID = '{86E0D1E0-8089-11D0-9CE4-08003E301F73}'; begin DeviceNotifier:=TDeviceNotifier.Create(GUID_DEVINTERFACE_COMPORT); DeviceNotifier.FDeviceArrival:=arrival; DeviceNotifier.OnWin := report; end; procedure TForm1.FormDestroy(Sender: TObject); begin DeviceNotifier.Free; end; procedure TForm1.report (text: string); begin Memo.Lines.Add (text); end; end.
解决方法
您可以使用
RegisterDeviceNotification
WinAPI函数将
DEV_BROADCAST_DEVICEINTERFACE
结构与
GUID_DEVINTERFACE_COMPORT
设备接口类一起传递.
试试这个样本.
type PDevBroadcastHdr = ^DEV_BROADCAST_HDR; DEV_BROADCAST_HDR = packed record dbch_size: DWORD; dbch_devicetype: DWORD; dbch_reserved: DWORD; end; TDevBroadcastHdr = DEV_BROADCAST_HDR; type PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE; DEV_BROADCAST_DEVICEINTERFACE = record dbcc_size: DWORD; dbcc_devicetype: DWORD; dbcc_reserved: DWORD; dbcc_classguid: TGUID; dbcc_name: Char; end; TDevBroadcastDeviceInterface = DEV_BROADCAST_DEVICEINTERFACE; const DBT_DEVICEARRIVAL = $8000; DBT_DEVICEREMOVECOMPLETE = $8004; DBT_DEVTYP_DEVICEINTERFACE = $00000005; type TDeviceNotifyProc = procedure(Sender: TObject; const DeviceName: String) of Object; TDeviceNotifier = class private hRecipient: HWND; FNotificationHandle: Pointer; FDeviceArrival: TDeviceNotifyProc; FDeviceRemoval: TDeviceNotifyProc; procedure WndProc(var Msg: TMessage); public constructor Create(GUID_DEVINTERFACE : TGUID); property OnDeviceArrival: TDeviceNotifyProc read FDeviceArrival write FDeviceArrival; property OnDeviceRemoval: TDeviceNotifyProc read FDeviceRemoval write FDeviceRemoval; destructor Destroy; override; end; type TForm17 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } DeviceNotifier : TDeviceNotifier; public { Public declarations } procedure arrival(Sender: TObject; const DeviceName: String); end; var Form17: TForm17; implementation {$R *.dfm} constructor TDeviceNotifier.Create(GUID_DEVINTERFACE : TGUID); var NotificationFilter: TDevBroadcastDeviceInterface; begin inherited Create; hRecipient := AllocateHWnd(WndProc); ZeroMemory(@NotificationFilter,SizeOf(NotificationFilter)); NotificationFilter.dbcc_size := SizeOf(NotificationFilter); NotificationFilter.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE; NotificationFilter.dbcc_classguid := GUID_DEVINTERFACE; //register the device class to monitor FNotificationHandle := RegisterDeviceNotification(hRecipient,DEVICE_NOTIFY_WINDOW_HANDLE); end; procedure TDeviceNotifier.WndProc(var Msg: TMessage); var Dbi: PDevBroadcastDeviceInterface; begin with Msg do if (Msg = WM_DEVICECHANGE) and ((WParam = DBT_DEVICEARRIVAL) or (WParam = DBT_DEVICEREMOVECOMPLETE)) then try Dbi := PDevBroadcastDeviceInterface(LParam); if Dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE then begin if WParam = DBT_DEVICEARRIVAL then begin if Assigned(FDeviceArrival) then FDeviceArrival(Self,PChar(@Dbi.dbcc_name)); end else if WParam = DBT_DEVICEREMOVECOMPLETE then begin if Assigned(FDeviceRemoval) then FDeviceRemoval(Self,PChar(@Dbi.dbcc_name)); end; end; except Result := DefWindowProc(hRecipient,LParam); end else Result := DefWindowProc(hRecipient,LParam); end; destructor TDeviceNotifier.Destroy; begin UnregisterDeviceNotification(FNotificationHandle); DeallocateHWnd(hRecipient); inherited; end; procedure TForm17.arrival(Sender: TObject; const DeviceName: String); begin ShowMessage(DeviceName); end; procedure TForm17.FormCreate(Sender: TObject); const GUID_DEVINTERFACE_COMPORT : TGUID = '{86E0D1E0-8089-11D0-9CE4-08003E301F73}'; begin DeviceNotifier:=TDeviceNotifier.Create(GUID_DEVINTERFACE_COMPORT); DeviceNotifier.FDeviceArrival:=arrival; end; procedure TForm17.FormDestroy(Sender: TObject); begin DeviceNotifier.Free; end; end.