Để liên lạc với bộ điều khiển vi mô, tôi sử dụng cổng nối tiếp. Tôi sử dụng TCommPortDriver 2.1 hoạt động tốt. Tuy nhiên, nó thiếu khả năng phát hiện thêm hoặc loại bỏ các comports mới. Điều này xảy ra thường xuyên trong một phiên.Làm cách nào để phát hiện thêm cổng nối tiếp mới?
Có sự kiện nào cho biết khi nào một bổ sung đã được thêm hoặc xóa không?
Cập nhật 1
tôi đã cố gắng đề nghị đầu tiên của RRUZ và biến nó thành một chương trình độc lập. Nó phản ứng trên WM_DEVICECHANGE
khi cáp được cắm vào hoặc ra, nhưng WParam
không hiển thị việc đến hoặc tháo thiết bị. Kết quả là:
msg = 537, wparam = 7, lparam = 0
msg = 537, wparam = 7, lparam = 0
msg = 537, wparam = 7, lparam = 0
Thông điệp đầu tiên được gửi khi cáp USB được cắm ra và tiếp theo hai khi nó được cắm vào Phần thông điệp cho thấy WM_DEVICECHANGE
nhắn (537) nhưng WParam
là 7, đó là. không phải WM_DEVICECHANGE
hoặc DBT_DEVICEARRIVAL
. Tôi sửa đổi mã phần nào theo thứ tự tin nhắn được xử lý nhưng như LParam
là số không này là không sử dụng. Kết quả giống hệt với VCL và FMX. Như một kiểm tra xem mã dưới đây.
Cập nhật 2
bây giờ tôi đã nhận mã WMI chạy. Nó chỉ cháy khi một cổng COM được thêm vào, không có phản ứng khi một bị loại bỏ. Kết quả:
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
Điều này có thể giải thích thực tế là mã khác này không được xem là bổ sung cổng COM không? Nó xuất hiện để xem kết nối mới như một cổng USB (những gì nó thực sự là). Trình điều khiển Arduino dịch thành cổng COM nhưng không được WMI nhận diện. Windows nhắn tin 'thấy' một cổng COM thay đổi nhưng không thể phát hiện cho dù nó được thêm vào hoặc gỡ bỏ.
Dù sao đi nữa: thay đổi thiết bị hoạt động. Tôi chỉ cần liệt kê các cổng COM để xem cổng nào thực sự hiện diện và đó là điều tôi đã làm theo cách thủ công. Bây giờ tôi có thể làm điều đó tự động với WM_DEVICECHANGE
. Tôi chỉ cần thêm một sự kiện vào thành phần CPDrv.
Cảm ơn RRUZ về mã của bạn và trợ giúp!
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.
Bạn có thể có một số may mắn bằng WMI sự kiện, chỉ cần sử dụng sự kiện DEVICE_CHANGE và tìm kiếm cổng nối tiếp mới được bổ sung –
Mã WMI được đăng không bao gồm phát hiện thiết bị loại bỏ, vì vậy bạn phải thay đổi câu WQL thành 'Select * From __InstanceDeletionEvent Trong vòng 1 Where TargetInstance ISA" Win32_PnPEntity "AND TargetInstance.ClassGuid =" {4d36e978-e325-11ce-bfc1- 08002be10318} "' – RRUZ
hoặc để phát hiện sự xuất hiện hoặc loại bỏ thiết bị bằng một câu WQL đơn, bạn có thể sử dụng sự kiện WMI '__InstanceOperationEvent'. – RRUZ