Reputation: 242
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.
Upvotes: 1
Views: 576
Reputation: 613461
Although the messages are synchronous, that is non-queued, you do need to dispatch messages in order for synchronous messages to be delivered. Typically message dispatch is done by the message loop, when you call GetMessage
or similar function.
Your application does not have a message loop and does not dispatch messages. You just need to arrange that your program dispatches messages. Adding a message loop would do it. But you just need to do something that dispatches messages. Doesn't need to be a full blown message loop. For instance you could replace your loop with:
while True do
SendMessage(hwnd, WM_NULL, 0, 0);
This does what you need because SendMessage
is one of the functions that dispatch messages.
You need to decide which window handle to use. You could use the window handle that you created. Or you could probably send the messages to the invalid window handle with value 0
.
Or you could just decide to run a standard message loop:
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
Upvotes: 3