直到今天我一直在使用以下代码来捕获WM_DEVICECHANGE
应用程序主窗体中的消息并且它运行良好。但是,如果我尝试在自定义控件中使用它,我不会收到有关设备插入或删除的通知。怎么了 ?
TDriveBar = class(TCustomPanel)
private
procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
end;
implementation
procedure TDriveBar.WMDeviceChange(var Msg: TMessage);
const DBT_DEVICEARRIVAL = $8000;
DBT_DEVICEREMOVECOMPLETE = $8004;
DBT_DEVTYP_VOLUME = 2;
type PDEV_BROADCAST_HDR = ^DEV_BROADCAST_HDR;
DEV_BROADCAST_HDR = record
dbch_size: dword;
dbch_devicetype: dword;
dbch_reserved: dword;
end;
begin
case Msg.WParam of
DBT_DEVICEREMOVECOMPLETE:
if PDEV_BROADCAST_HDR(Msg.LParam)^.dbch_devicetype = DBT_DEVTYP_VOLUME then UpdateDrives;
DBT_DEVICEARRIVAL:
if PDEV_BROADCAST_HDR(Msg.LParam)^.dbch_devicetype = DBT_DEVTYP_VOLUME then UpdateDrives;
end;
end;
操作系统发送wm_DeviceChange
向所有顶级窗口发送消息。应用程序的主窗体是顶级窗口,但您的控件不是,这就是窗体接收消息而您的控件不接收消息的原因。
对于任意设备类型,您有两种选择:
-
Use AllocateHWnd创建一个仅包含消息的顶级窗口,该窗口将通过调用与控件关联的函数来响应消息。这将为您提供与主表单收到的相同的基本信息。
为您的控件编写一个与签名相匹配的方法TWndMethod
,这就是AllocateHWnd
需要。它可能看起来像这样:
procedure TDriveBar.DeviceWindowProc(var Message: TMessage);
begin
case Message.Msg of
wm_DeviceChange: begin
case Message.WParam of
DBT_DEVICEREMOVECOMPLETE, DBT_DEVICEARRIVAL:
if PDEV_BROADCAST_HDR(Message.LParam).dbch_devicetype = DBT_DEVTYP_VOLUME then
UpdateDrives;
end;
end;
end;
Message.Result := DefWindowProc(FDeviceWnd, Message.Msg, Message.WParam, Message.LParam);
end;
然后在创建消息窗口时使用该方法:
FDeviceWnd := AllocateHWnd(DeviceWindowProc);
Call RegisterDeviceNotification告诉操作系统您的控件的窗口也想要接收通知。 (确保你处理好你的控件CreateWnd
and DestroyWnd
方法,以便如果重新创建控件,您可以使用控件的新窗口句柄更新通知注册。)这将为您提供比默认值更详细的信息wm_DeviceChange
消息提供,但仅适用于您在注册窗口句柄时指定的设备类型。
但是,您对以下更改感兴趣volumes。备注为RegisterDeviceNotification
对此有话要说(强调):
The DBT_DEVICEARRIVAL
and DBT_DEVICEREMOVECOMPLETE
事件会自动广播到端口设备的所有顶级窗口。因此,没有必要调用RegisterDeviceNotification
对于端口,如果dbch_devicetype
成员是DBT_DEVTYP_PORT
. 音量通知也会广播到顶级窗口,因此如果出现以下情况,该功能将失败dbch_devicetype
is DBT_DEVTYP_VOLUME
.
这消除了通知注册作为您的一个选项,因此您的情况唯一的解决方案是使用AllocateHWnd
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)