For communication with microcontrollers I use a serial port. I am using TCommPortDriver 2.1, which works great. However, it does not have the ability to detect the addition or removal of new components. This happens regularly during the session.
Is there an event that reports when a component has been added or removed?
Update 1
I tried the first RRUZ sentence and turned it into a standalone program. It responds to WM_DEVICECHANGE when the cable is connected or turned off, but WParam does not show the arrival or removal of the device. Results:
msg = 537, wparam = 7, lparam = 0 msg = 537, wparam = 7, lparam = 0 msg = 537, wparam = 7, lparam = 0
The first message is sent when the USB cable is connected, and the next two when it is connected. The message WM_DEVICECHANGE (537) is displayed in the message WM_DEVICECHANGE , but WParam is 7, which is not equal to WM_DEVICECHANGE or DBT_DEVICEARRIVAL . I changed the code to process the message a LParam , but since LParam is zero, this is useless. The results are identical to VCL and FMX. For verification, see Code below.
Update 2
Now I got the WMI code. It only starts when a COM port is added; when it is removed, there is no reaction. Results:
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
Perhaps this explains the fact that in another code this is not considered as adding a COM port? It looks like the new connection is seen as a USB port (which is actually). The Arduino driver translates this to a COM port, but WMI is not recognized. Windows messaging "sees" a change in the COM port, but cannot determine whether it has been added or removed.
Anyway: changing the device works. I only need to list the COM ports to see which one is really present, and that was what I already did manually. Now I can do it automatically using WM_DEVICECHANGE . I just add an event to the CPDrv component.
Thanks to RRUZ for your code and help!
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, Msg, WParam, 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.