当我使用" message"时,为什么我不能在我的控制中接收消息?指示?

时间:2015-06-26 15:31:59

标签: delphi delphi-2009 messages

创建控件后,我必须使用DeviceWnd:=AllocateHWnd(DeviceWindowProc);接收WM_DEVICECHANGE条消息。然后......

procedure TFileList.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
           OnDeviceChange;
      end;
    end;
  end; 
  Message.Result:=DefWindowProc(DeviceWnd, Message.Msg, Message.WParam, Message.LParam);
end;

这很好用,但为什么我这样做的时候却没有意识到这个消息呢? :

TFileList = class(TCustomControl)
private
  procedure DeviceChage(var AMessage:TMessage); message WM_DEVICECHANGE;
end;

procedure TFileList.DeviceWindowProc(var Message: TMessage);
begin
  Message.Result:=DefWindowProc(DeviceWnd, Message.Msg, Message.WParam, Message.LParam);
end;

procedure TFileList.DeviceChage(var AMessage:TMessage);
begin
 case AMessage.WParam of
   DBT_DEVICEREMOVECOMPLETE, DBT_DEVICEARRIVAL:
     if PDEV_BROADCAST_HDR(AMessage.LParam).dbch_devicetype = DBT_DEVTYP_VOLUME then
       OnDeviceChange;
 end;
end;

2 个答案:

答案 0 :(得分:4)

来自RegisterDeviceNotification的文档:

  

应用程序使用BroadcastSystemMessage函数发送事件通知。具有顶级窗口的任何应用程序都可以通过处理WM_DEVICECHANGE消息来接收基本通知。应用程序可以使用RegisterDeviceNotification函数进行注册以接收设备通知。

使用AllocateHWnd创建的窗口是顶级窗口。因此它接收广播消息。

您的自定义控件不是顶级窗口。如果您希望它接收消息,您必须通过其窗口句柄调用RegisterDeviceNotification。如果您这样做,请务必通过在CreateWnd注册并取消注册DestroyWnd来处理VCL窗口娱乐。

作为一般经验法则,AllocateHwnd是侦听通知的首选方式。那是因为它不受VCL窗口娱乐的影响,所以不能错过通知。在重新创建VCL窗口时,会有一个发送通知的机会窗口,但您的应用程序没有准备好接收的窗口。

这肯定会成为您的问题,因此您应该使用AllocateHwnd。您可以安排使用AllocateHwnd创建的窗口归自定义控件所有,然后您可以将通知路由到该控件的代码。

答案 1 :(得分:2)

WM_DEVICECHANGE广播到顶级窗口。您的自定义控件的窗口不是顶级窗口,它是控件的Parent窗口的子窗口。这就是为什么你的message处理程序没有被调用的原因 - 消息永远不会到达你的控件的WndProc(),因此可以将它发送给message处理程序。

对于大多数设备通知,您可以使用RegisterDeviceNotification()WM_DEVICECHANGE条消息发送给特定的HWND。但是,在您的示例中,更改邮件无法像以下那样注册:

  

如果dbch_devicetype为 DBT_DEVTYP_VOLUME ,则函数失败。

因此,对于接收WM_DEVICECHANGE消息的自定义控件,它必须分配自己的顶级窗口,例如使用AllocateHwnd()函数:

type
  // TCustomControl is meant to be used for developing **visual**
  // controls. If your custom control is not visual, you should
  // derive from `TComponent` instead...
  TFileList = class(TCustomControl)
  private
    DeviceWnd: HWND;
    procedure DeviceWindowProc(var Message: TMessage);
  public
    constructor Create(Owner: TComponent); override;
    destructor Destroy; override;
  end;

constructor TFileList.Create(Owner: TComponent);
begin
  inherited Create(Owner);
  if not (csDesigning in ComponentState) then
    DeviceWnd := AllocateHwnd(DeviceWindowProc);
end;

destructor TFileList.Destroy;
begin
  if DeviceWnd <> 0 then
    DeallocateHwnd(DeviceWnd);
  inherited Destroy;
end;

procedure TFileList.DeviceWindowProc(var Message: TMessage);
begin
  if Message.Msg = WM_DEVICECHANGE then
  begin
    case Message.WParam of
      DBT_DEVICEREMOVECOMPLETE, DBT_DEVICEARRIVAL:
        if PDEV_BROADCAST_HDR(Message.LParam).dbch_devicetype = DBT_DEVTYP_VOLUME then
          OnDeviceChange;
    end;
  end;
  Message.Result := DefWindowProc(DeviceWnd, Message.Msg, Message.WParam, Message.LParam);
end;