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.
unit Wim;
{$MODE objfpc}{$H+}
interface
uses
SysUtils, Windows;
type
TWimCallBack = procedure(const AMessage: String);
procedure WimSetCallBack(const ASender: HWND; const ACallBack: TWimCallBack);
function WimSendMessage(const ASender: HWND; const AReceiver, AMessage: String): Boolean;
implementation
function WimSendMessage(const ASender: HWND; const AReceiver, AMessage: String): Boolean;
var
LHandle: HWND;
LCopyDataStruct: TCopyDataStruct;
begin
LHandle := FindWindow(nil, pchar(AReceiver));
Result := LHandle <> 0;
if Result then begin
LCopyDataStruct.dwData := 0;
LCopyDataStruct.cbData := Length(AMessage) + 1;
LCopyDataStruct.lpData := pchar(AMessage);
SendMessage(LHandle, WM_COPYDATA, WPARAM(ASender), LPARAM(@LCopyDataStruct));
end;
end;
var
GWndProc: WNDPROC;
GWimCallBack: TWimCallBack;
function WimProc(AHwnd: HWND; AMessage: UINT; AWParam: WParam; ALParam: LParam): LRESULT; stdcall;
var
LCopyDataStruct: TCopyDataStruct;
begin
if Assigned(GWimCallBack) and (AMessage = WM_COPYDATA) then begin
LCopyDataStruct := PCopyDataStruct(ALParam)^;
if LCopyDataStruct.dwData = 0 then begin
GWimCallBack(pchar(LCopyDataStruct.lpData));
end;
Result := S_OK;
end else begin
Result := CallWindowProc(GWndProc, AHwnd, AMessage, AWParam, ALParam);
end;
end;
procedure WimSetCallBack(const ASender: HWND; const ACallBack: TWimCallBack);
begin
GWimCallBack := ACallBack;
if GWndProc = nil then begin
GWndProc := Windows.WNDPROC(SetWindowLongPtr(ASender, GWL_WNDPROC, PtrInt(@WimProc)));
end;
end;
end.
To use, include unit wim, and:
// This is your message receiver.
procedure GMyMessageCallBack(const AMessage: String);
begin
ShowMessage(AMessage);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Set the receiver callback.
WimSetCallBack(Handle, @GMyMessageCallBack);
// Set the caption. (I will explain why its here below)
Caption := 'MyCaption';
end;
// Send a message like this.
procedure TForm1.Button1Click(Sender: TObject);
begin
WimSendMessage(Handle, 'MyCaption', 'Hello There');
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