delphi – 如何检测新串口的添加?

前端之家收集整理的这篇文章主要介绍了delphi – 如何检测新串口的添加?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
要与微控制器通信,我使用串行端口.我使用TCommPortDriver 2.1工作正常.但是,它缺乏检测新组合的添加删除的能力.这会在会话期间定期发生.

是否有事件告知何时添加删除了一个comport?

更新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.

猜你在找的Delphi相关文章