3

我正在尝试编写一个组件,通过 WM_COPYDATA 在应用程序之间发送字符串消息。我想捕获 WM_COPYDATA,但这不起作用:

TMyMessage = class(TComponent)
private
{ Private declarations } 
…
protected
{ Protected declarations }
…
procedure WMCopyData(var Msg : TMessage); message WM_COPYDATA;
…
end;

大量搜索谷歌,找到了一些使用 wndproc 的参考资料。我试过了,但它也不起作用。

TMyMessage = class(TComponent)
…
protected
{ Protected declarations }
…
procedure WMCopyData(var Msg : TMessage); message WM_COPYDATA;
procedure WndProc(var Msg: TMessage);
…
end;
…
procedure TMyMessage.WndProc(var Msg: TMessage);
begin
  //inherited;
  if Msg.Msg = WM_COPYDATA then
    WMCopyData(Msg);
end;

请帮忙,有什么问题吗?

4

3 回答 3

3

到目前为止,您所拥有的一切都很好,但是您需要首先安排将消息传递到您的组件。这需要一个窗口句柄。调用AllocateHWnd并将其传递给组件的WndProc方法。它将返回一个窗口句柄,您应该在组件被销毁时将其销毁。

constructor TMyMessage.Create(AOwner: TComponent);
begin
  inhreited;
  FHandle := AllocateHWnd(WndProc);
end;

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

无需直接测试每条消息,您可以让其TObject为您执行此操作。这就是该Dispatch方法的用途。给它传递一条TMessage记录,它会为你找到并调用相应的消息处理方法。如果没有这样的处理程序,它将DefaultHandler改为调用。可以调用的覆盖DefWindowProc

procedure TMyMessage.WndProc(var Message);
begin
  Dispatch(Message);
end;

procedure TMyMessage.DefaultHandler(var Message);
begin
  TMessage(Message).Result := DefWindowProc(Self.Handle, TMessage(Message).Msg,
    TMessage(Message).WParam, TMessage(Message).LParam);
end;
于 2012-02-01T14:52:36.990 回答
1

您的问题是这TComponent不是窗口组件。WM_COPYDATA是一个窗口消息,通过窗口过程传递。因此,您需要一个窗口句柄。用于AllocateHwnd获取其中之一。

type
  TMyComponent = class(TComponent)
  private
    FWindowHandle: HWND;
    procedure WndProc(var Msg: TMessage);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited;
  FWindowHandle := AllocateHwnd(WndProc);
end;

destructor TMyComponent.Destroy;
begin
  DeallocateHwnd(FWindowHandle);
  inherited;
end;

procedure TMyComponent.WndProc(var Msg: TMessage);
begin
  if Msg.Msg=WM_COPYDATA then
    //do domething
  else
    Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.WParam, Msg.LParam);
end;

无论发送什么消息,都需要找到一种方法来获取窗口句柄。

于 2012-02-01T14:51:54.383 回答
1

我是这样做的:

我在线程中运行的 Web 模块需要将字符串发送到主窗体上的备忘录。FReceiverFromWS 是一个 Thandle

创建时:

procedure TWebModuleWebServices.WebModuleCreate(Sender: TObject);
begin
   FReceiverFromWS := FindWindow(PChar('TFormWebServices'),PChar(cFormCaption + FormWebServices.Instance)); // Search by class name and caption of receiving form
   // ==> you could to that without form caption, but I need to distinguish between running services
   if FReceiverFromWS = 0 then
      begin
         Assert(False,'CopyData receiver NOT found!');  // Probably TFormWebServices not yet created
         Exit;
      end;
end;

要发送消息:

procedure TWebModuleWebServices.SendAMessage(Msg: String);
// Windows will guarantee that the data sent in the COPYDATASTRUCT will exist until     after the WM_COPYDATA message
// has been carried out. As such, we must use SendMessage() to send a WM_COPYDATA message. We cannot use PostMessage().
var
   lCopyDataStruct: TCopyDataStruct;
begin
   lCopyDataStruct.dwData := 0;
   lCopyDataStruct.cbData := 1 + Length(Msg);
   lCopyDataStruct.lpData := PChar(Msg);
   SendMessage(FReceiverFromWS, WM_COPYDATA, wParam(FReceiverFromWS), lParam(@lCopyDataStruct));
end;

在主窗体中,公共方法

过程 WMCopyData(var Msg : TWMCopyData) ; 消息 WM_COPYDATA;

是:

procedure TFormWebServices.WMCopyData(var Msg: TWMCopyData);
var
   i : integer;
   s : string;
begin
   i := Msg.CopyDataStruct.dwData;
   case i of
      0: begin  // Message to display
            s := String(PChar(Msg.CopyDataStruct.lpData));
            AddMemoLine(s);
         end;
      1: begin  // Statistical data
            s := String(PChar(Msg.CopyDataStruct.lpData));
            FrmWebServiceStats.CollectStats(s);
         end;
   end;
end;

(如您所见,我实际上使用 dwData 来表示消息类型并以不同方式处理这些消息)

于 2012-02-02T15:45:58.373 回答