简体   繁体   English

如何在TForm以外的控件中捕获WM_DEVICECHANGE?

[英]How to catch WM_DEVICECHANGE in a control other than TForm?

Until today I was using the following code to catch WM_DEVICECHANGE message in application main form and it worked pefectly. 直到今天,我仍在使用以下代码在应用程序主表单中捕获WM_DEVICECHANGE消息,并且该方法可以正常工作。 But if I try to use this in my custom control I don't get notifyed on device insert or remove. 但是,如果我尝试在自定义控件中使用此功能,则不会在设备插入或移除时收到通知。 What is happening ? 怎么了 ?

  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;

The OS sends wm_DeviceChange messages to all top-level windows. 操作系统将wm_DeviceChange消息发送到所有顶级窗口。 The application's main form is a top-level window, but your control is not, which is why the form receives the messages and your control does not. 该应用程序的主窗体是一个顶层窗口,但您的控件却没有,这就是该窗体接收消息而您的控件没有接收到消息的原因。

For arbitrary device types, you have two alternatives: 对于任意设备类型,您有两种选择:

  1. Use AllocateHWnd to create a message-only top-level window that will respond to messages by calling a function associated with your control. 使用AllocateHWnd创建仅消息的顶级窗口,该窗口将通过调用与控件关联的函数来响应消息。 This will give you the same basic information as the main form receives. 这将为您提供与主表格相同的基本信息。

    Write a method for your control that matches the signature for TWndMethod , which is what AllocateHWnd requires. 为您的控件编写一个与TWndMethod的签名匹配的方法,这是AllocateHWnd需要的。 It might look like this: 它可能看起来像这样:

     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; 

    Then use that method when you create the message window: 然后在创建消息窗口时使用该方法:

     FDeviceWnd := AllocateHWnd(DeviceWindowProc); 
  2. Call RegisterDeviceNotification to tell the OS that your control's window wants to receive notifications, too. 调用RegisterDeviceNotification告诉OS,您的控件窗口也希望接收通知。 (Make sure you handle your control's CreateWnd and DestroyWnd methods so that if your control is re-created, you renew the notification registration with the control's new window handle.) This will give you more detailed information than the default wm_DeviceChange message provides, but only for the kinds of devices you specify when you register your window handle. (确保您处理了控件的CreateWndDestroyWnd方法,以便在重新创建控件时,可以使用控件的新窗口句柄续订通知注册。)这将为您提供比默认wm_DeviceChange消息提供的详细信息,但仅用于注册窗口句柄时指定的设备类型。

However, you're interested in changes to volumes . 但是,你有兴趣的变化 The remarks for RegisterDeviceNotification have something to say about that (emphasis added): 关于RegisterDeviceNotification的评论对此有话要说(强调):

The DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE events are automatically broadcast to all top-level windows for port devices. DBT_DEVICEARRIVALDBT_DEVICEREMOVECOMPLETE事件将自动广播到端口设备的所有顶级窗口。 Therefore, it is not necessary to call RegisterDeviceNotification for ports, and the function fails if the dbch_devicetype member is DBT_DEVTYP_PORT . 因此,没有必要为端口调用RegisterDeviceNotification ,并且如果dbch_devicetype成员为DBT_DEVTYP_PORT ,则该函数将失败。 Volume notifications are also broadcast to top-level windows, so the function fails if dbch_devicetype is DBT_DEVTYP_VOLUME . 卷通知也会广播到顶级窗口,因此,如果dbch_devicetypeDBT_DEVTYP_VOLUME ,该功能将失败。

That eliminates that notification registration as an option for you, so the only solution in your case is to use AllocateHWnd . 这消除了通知注册作为您的选项,因此您的情况下唯一的解决方案是使用AllocateHWnd

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM