Поймать WM_COPYDATA из компонента Delphi - PullRequest
3 голосов
/ 01 февраля 2012

Я пытаюсь написать компонент для отправки строковых сообщений между приложениями по WM_COPYDATA.Я бы хотел перехватить WM_COPYDATA, но это не сработало:

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

Много просматривая в Google, нашел ссылку с помощью 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;

Пожалуйста, помогите, что не так?

Ответы [ 3 ]

3 голосов
/ 01 февраля 2012

То, что у вас есть, в порядке, но вам нужно сначала организовать доставку сообщений на ваш компонент.Это требует дескриптор окна.Вызовите 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;
1 голос
/ 02 февраля 2012

Я сделал это так:

Мои веб-модули, работающие в потоке, должны отправлять строки в заметку в главной форме. FReceiverFromWS - это Тандл

При создании:

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, чтобы сигнализировать о типе сообщения и обрабатывать их по-разному)

1 голос
/ 01 февраля 2012

Ваша проблема в том, что TComponent не является оконным компонентом. WM_COPYDATA является сообщением Windows и доставляется через оконную процедуру. Следовательно, вам нужна ручка окна. Используйте 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;

Что бы ни отправляло сообщения, нужно найти способ завладеть дескриптором окна.

...