Do komunikacji z mikrokontrolerami używam portu szeregowego. Używam TCommPortDriver 2.1, który działa dobrze. Jednak nie ma możliwości wykrycia dodania lub usunięcia nowych komportów. Dzieje się to regularnie podczas sesji.Jak wykryć dodanie nowego portu szeregowego?
Czy jest jakieś wydarzenie informujące o dodaniu lub usunięciu konta?
Update 1
Próbowałem pierwszą sugestię RRUZ i przekształcił go w samodzielny program. Reaguje on na WM_DEVICECHANGE
, gdy kabel jest podłączony lub odłączony, ale WParam
nie pokazuje przybycia lub usunięcia urządzenia. Wyniki są następujące:
msg = 537, wparam = 7, lparam = 0
msg = 537, wparam = 7, lparam = 0
msg = 537, wparam = 7, lparam = 0
Pierwsza wiadomość zostanie wysłana, gdy kabel USB jest podłączony out i dwa następne, gdy jest on podłączony Część wiadomość pojawia się komunikat WM_DEVICECHANGE
(537), ale WParam
wynosi 7, co jest. nie WM_DEVICECHANGE
lub . Zmieniłem trochę kod, aby wiadomość została przetworzona, ale jako LParam
jest zero, to nie ma sensu. Wyniki są identyczne z VCL i FMX. Weryfikacja patrz kod poniżej.
Aktualizacja 2
ja teraz mam kod WMI działa. Występuje tylko przy dodaniu portu COM, brak reakcji po usunięciu. Wyniki:
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
Czy to może wyjaśniać fakt, że w drugim kodzie nie jest to postrzegane jako dodanie portu COM? Wygląda na to, że nowe połączenie wygląda jak port USB (czym on jest). Sterownik Arduino tłumaczy to na port COM, ale nie jest to rozpoznawane przez WMI. Komunikat systemu Windows "widzi" zmianę portu COM, ale nie może wykryć, czy jest ona dodawana czy usuwana.
W każdym razie: zmiana urządzenia działa. Muszę tylko wyliczyć porty COM, aby zobaczyć, który z nich jest rzeczywiście obecny i to było coś, co już zrobiłem ręcznie. Teraz mogę to zrobić automatycznie za pomocą WM_DEVICECHANGE
. Dodaję tylko zdarzenie do komponentu CPDrv.
Dzięki RRUZ za kod i pomoc!
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.
można mieć trochę szczęścia przy użyciu zdarzeń WMI, wystarczy użyć zdarzenia DEVICE_CHANGE i spojrzeć na nowo dodawanych portów szeregowych –
Opublikowany kod WMI nie zawiera wykrywania urządzenia do usuwania, ponieważ musisz zmienić zdanie WQL na 'Wybierz * z __InstanceDeletionEvent w ciągu 1 Gdzie TargetInstance ISA" Win32_PnPEntity "AND TargetInstance.ClassGuid =" {4d36e978-e325-11ce-bfc1- 08002be10318} "' – RRUZ
lub do wykrywania przybycia lub usunięcia urządzenia za pomocą pojedynczego zdania WQL można użyć zdarzenia WMI "__InstanceOperationEvent". – RRUZ