Author Topic: Processing WM_CopyData message fails  (Read 2904 times)


  • Newbie
  • Posts: 3
Processing WM_CopyData message fails
« on: August 31, 2015, 09:03:22 am »
Hi! I try to create a plugin in Lazarus which is based on existing open-source code. I use Windows and Messages classes.  WM_COPYDATA message should be used to communicate with the main programme and TCopyDataStruct should collect the data.
However, I found out that the messages between them are lost. After research I think it might be connected with Processing non-user messages in your window (

Now I try to implement the WndCallBack function, but I stuck with an error. I don't know what parameter should I pass to the procedure WMCopyData inside of the function WndCallback. I have already tried with:
- (var Msg: TCopyDataStruct) as in the procedure declaration. It raises an error: <<Sytax error, expected ")" but "IDENTIFIER MSG" found>>
- (Msg) - Error <<Error: Only class methods, class properties and class variables can be referred with class references>>
-() - Error <<Wrong number of parameters specified to call WmCopyData>>

Could you tell me how to make it work?

The code of my procedure:
Code: [Select]
procedure TForm1.WMCopyData(var Msg: TCopyDataStruct);

  sText: array[0..199] of Char;
  s, nr, kod, x, y, z : string;
  xx, yy : Double;
  err, n : Integer;

    if Msg.dwData = 1 then
         pkt := Msg.lpData;
         for n := 0 to 5000 do
           if pkt^[n].nr = '' then Break;
           Memo1.Lines.Add(pkt^[n].nr+' '+pkt^[n].k+' '+tostr(pkt^[n].x,2)+' '+tostr(pkt^[n].y,2)+' '+tostr(pkt^[n].z,3));


The WndCallBack function
Code: [Select]
function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;

   case uMsg of WM_COPYDATA:
       Result := TForm1.WMCopyData();
      Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);


Declared with:
Code: [Select]
procedure WMCopyData(var Msg:TCopyDataStruct); message WM_COPYDATA;


  • Guest
Re: Processing WM_CopyData message fails
« Reply #1 on: August 31, 2015, 09:54:19 am »
This is the method i'm using. This unit is hacked from one of my projects. Would be nice to have something like this which is portable.

Code: Pascal  [Select]
  1. unit Wim;
  3. {$MODE objfpc}{$H+}
  5. interface
  7. uses
  8.   SysUtils, Windows;
  10. type
  11.   TWimCallBack = procedure(const AMessage: String);
  13. procedure WimSetCallBack(const ASender: HWND; const ACallBack: TWimCallBack);
  14. function WimSendMessage(const ASender: HWND; const AReceiver, AMessage: String): Boolean;
  16. implementation
  18. function WimSendMessage(const ASender: HWND; const AReceiver, AMessage: String): Boolean;
  19. var
  20.   LHandle: HWND;
  21.   LCopyDataStruct: TCopyDataStruct;
  22. begin
  23.   LHandle := FindWindow(nil, pchar(AReceiver));
  24.   Result := LHandle <> 0;
  25.   if Result then begin
  26.     LCopyDataStruct.dwData := 0;
  27.     LCopyDataStruct.cbData := Length(AMessage) + 1;
  28.     LCopyDataStruct.lpData := pchar(AMessage);
  29.     SendMessage(LHandle, WM_COPYDATA, WPARAM(ASender), LPARAM(@LCopyDataStruct));
  30.   end;
  31. end;
  33. var
  35.   GWndProc: WNDPROC;
  36.   GWimCallBack: TWimCallBack;
  38. function WimProc(AHwnd: HWND; AMessage: UINT; AWParam: WParam; ALParam: LParam): LRESULT; stdcall;
  39. var
  40.   LCopyDataStruct: TCopyDataStruct;
  41. begin
  42.   if Assigned(GWimCallBack) and (AMessage = WM_COPYDATA) then begin
  43.     LCopyDataStruct := PCopyDataStruct(ALParam)^;
  44.     if LCopyDataStruct.dwData = 0 then begin
  45.       GWimCallBack(pchar(LCopyDataStruct.lpData));
  46.     end;
  47.     Result := S_OK;
  48.   end else begin
  49.     Result := CallWindowProc(GWndProc, AHwnd, AMessage, AWParam, ALParam);
  50.   end;
  51. end;
  53. procedure WimSetCallBack(const ASender: HWND; const ACallBack: TWimCallBack);
  54. begin
  55.   GWimCallBack := ACallBack;
  56.   if GWndProc = nil then begin
  57.     GWndProc := Windows.WNDPROC(SetWindowLongPtr(ASender, GWL_WNDPROC, PtrInt(@WimProc)));
  58.   end;
  59. end;
  61. end.

To use, include unit wim, and:
Code: Pascal  [Select]
  1. // This is your message receiver.
  2. procedure GMyMessageCallBack(const AMessage: String);
  3. begin
  4.   ShowMessage(AMessage);
  5. end;
  7. procedure TForm1.FormCreate(Sender: TObject);
  8. begin
  9.   // Set the receiver callback.
  10.   WimSetCallBack(Handle, @GMyMessageCallBack);
  11.   // Set the caption. (I will explain why its here below)
  12.   Caption := 'MyCaption';
  13. end;
  15. // Send a message like this.
  16. procedure TForm1.Button1Click(Sender: TObject);
  17. begin
  18.   WimSendMessage(Handle, 'MyCaption', 'Hello There');
  19. end;  

The way I use this is for single instances applications. I use WimSendMessage to send the ParamStr(1) (or, EmptyStr if there are no paramstr's) to a known window caption. If that succeeds, I halt the application, since another instance will pick up the filename and load it.

If it fails, then I must be the first instance, in which cause I handle the file loading. The reason why Caption must be set after the WinSendMessage, is so I dont pick up my own messages.

Anyway, if you have problems with the code, sing out. I guess I like this feature in a seperate unit, because, it makes porting the code easy. On other platforms, I just ignor WinSendMessage/WimSetCallBack
« Last Edit: October 02, 2015, 03:17:24 am by Geepster »


  • Newbie
  • Posts: 3
Re: Processing WM_CopyData message fails
« Reply #2 on: August 31, 2015, 11:07:13 am »
I have reproduced your code as you provided and I worked. Now I will try to use in the original project. I'll give you feedback soon :)
Thanks a lot for your help!


  • Newbie
  • Posts: 3
Re: Processing WM_CopyData message fails
« Reply #3 on: September 01, 2015, 09:56:50 am »
I managed to rewrite those codes and make it work in my project. So the problem was solved. Your hint was very useful. Thanks!