Adding USB Detection to a Formless { dpr } only Delphi Application

时间:2015-05-28 11:16:39

标签: delphi usb

is it possible to add usb detection to a formless (dpr only) Delphi Program? I have written the detection class but it seems to work only when I add a form to the program.

Here is the class

unit uMyUSB;

interface

uses

  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes,
  Winapi.ShellApi, Vcl.Dialogs;

// Start of Declarations

const
  DBT_DEVICEARRIVAL = $00008000;
  DBT_DEVICEREMOVECOMPLETE = $00008004;
  DBT_DEVTYP_VOLUME = $00000002;
  DBTF_MEDIA = $00000001;
  USB_INTERFACE = $00000005;

  // Device structs
type
  PDevBroadcastDeviceInterface = ^_DEV_BROADCAST_HDR;

  _DEV_BROADCAST_HDR = packed record
    dbch_size: DWORD;
    dbch_devicetype: DWORD;
    dbch_reserved: DWORD;
  end;

  DEV_BROADCAST_HDR = _DEV_BROADCAST_HDR;
  TDevBroadcastHeader = DEV_BROADCAST_HDR;
  PDevBroadcastHeader = ^TDevBroadcastHeader;

type
  _DEV_BROADCAST_VOLUME = packed record
    dbch_size: DWORD;
    dbch_devicetype: DWORD;
    dbch_reserved: DWORD;
    dbcv_unitmask: DWORD;
    dbcv_flags: WORD;
  end;

  DEV_BROADCAST_VOLUME = _DEV_BROADCAST_VOLUME;
  TDevBroadcastVolume = DEV_BROADCAST_VOLUME;
  PDevBroadcastVolume = ^TDevBroadcastVolume;

  // End of Declarations

  type

  TUSB = class(TObject)
  private
    FHandle: HWND;
    procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
    procedure WinMethod(var Msg: TMessage);
    procedure RegisterUsbHandler;
    { Public declarations }
  public
    { Public declarations }
    constructor Create();
    destructor Destroy(); override;
  end;

implementation

constructor TUSB.Create();
begin
  inherited Create;
  FHandle := AllocateHWnd(WinMethod);
  RegisterUsbHandler;
end;

destructor TUSB.Destroy();
begin
  DeallocateHWnd(FHandle);
  inherited Destroy;
end;

procedure TUSB.WinMethod(var Msg: TMessage);
begin
  if (Msg.Msg = WM_DEVICECHANGE) then
  begin
    WMDeviceChange(Msg);
  end
  else
  begin
    Msg.Result := DefWindowProc(FHandle, Msg.Msg, Msg.WParam, Msg.LParam);
  end;

end;

procedure TUSB.RegisterUsbHandler;
var
  rDbi: _DEV_BROADCAST_HDR;
  iSize: Integer;
begin
  iSize := SizeOf(_DEV_BROADCAST_HDR);
  ZeroMemory(@rDbi, iSize);
  rDbi.dbch_size := iSize;
  rDbi.dbch_devicetype := USB_INTERFACE;
  rDbi.dbch_reserved := 0;

  RegisterDeviceNotification(FHandle, @rDbi, DEVICE_NOTIFY_WINDOW_HANDLE);
end;

procedure TUSB.WMDeviceChange(var Msg: TMessage);
var
  lpdbhHeader: PDevBroadcastHeader;

begin
  lpdbhHeader := PDevBroadcastHeader(Msg.LParam);

    case Msg.WParam of
      DBT_DEVICEARRIVAL:
        begin
          if (lpdbhHeader^.dbch_devicetype = DBT_DEVTYP_VOLUME) then
          begin
            ShowMessage('Inserted');

          end;

        end;
      DBT_DEVICEREMOVECOMPLETE:
        begin
          if (lpdbhHeader^.dbch_devicetype = DBT_DEVTYP_VOLUME) then
          begin
            ShowMessage('Removed');
          end;

        end;
    end;


end;

and Here is the TestUnit

// My dpr Program

program TestUSB;

uses
  System.SysUtils,
  System.Classes,
  uMyUSB in 'Sources\uMyUSB.pas';

{$R *.res}

var
  FUSB: TUSB;

begin
{$WARNINGS OFF}
  ReportMemoryLeaksOnShutdown := DebugHook <> 0;
{$WARNINGS ON}

  FUSB := TUSB.Create();

// Loop to keep the Program Running Continually.
  while 1 = 1 do
  begin
  // Do Something
  end;

  FreeandNil(CustomUsb);

end.

How can I make a formless program accept USB change (WM_DEVICECHANGE) commands?

Thanks a Lot.

Delphi XE7.

1 个答案:

答案 0 :(得分:3)

虽然消息是同步的,即非排队的,但您需要调度消息以便传递同步消息。通常,当您调用GetMessage或类似函数时,消息循环将完成消息调度。

您的应用程序没有消息循环,也不会分发消息。您只需要安排您的程序发送消息。添加消息循环就可以了。但是你只需要做一些调度消息的事情。不需要成为一个完整的消息循环。例如,你可以用以下代码替换你的循环:

while True do
  SendMessage(hwnd, WM_NULL, 0, 0);

这可以满足您的需求,因为SendMessage是分发消息的功能之一。

您需要决定使用哪个窗口句柄。您可以使用您创建的窗口句柄。或者您可以将消息发送到值为0的无效窗口句柄。

或者您可以决定运行标准的消息循环:

while GetMessage(Msg, 0, 0, 0) do
begin
  TranslateMessage(Msg);
  DispatchMessage(Msg);
end;