https://www.thoughtco.com/send-information-between-applications-1058476
Seems straight forward - but it's not playing...
One app is doing the work - the other controlling (and starting) it, when the work needs to be done.
The controlling app is not having a visible form - only a trayicon with a menu.
The worker does have a form, and does show what it is doing.
I would like to send a message from the worker to the icon, that the worker has in fact started as it was instructed to, and again, when it is done doing what it should, and closes.
For now, I have this for sending a message:it seems to be doing what it should - if tray is not running, I get the "CopyData Receiver NOT found!" message.
procedure TWorkForm.MsgToTray(Ident : integer); var copyDataStruct : TCopyDataStruct; receiverHandle : THandle; res : integer; begin copyDataStruct.dwData := Ident; //use it to identify the message contents copyDataStruct.cbData := 1 + Length(FBckName) ; copyDataStruct.lpData := PChar(FBckName) ; receiverHandle := FindWindow(nil,PChar('TrayForm')) ; if receiverHandle = 0 then begin ShowMessage('CopyData Receiver NOT found!') ; Exit; end else begin res := SendMessage(receiverHandle, WM_COPYDATA, Integer(Handle), Integer(@copyDataStruct)); if res <> 10 then ShowMessage('Sent but not received'); end; end;
When it is running, I get the "Sent but not received" message.
But the message is never received.
(I did try FindWindow(PChar('TTrayForm'),PChar('TrayForm')) - but it never finds the app/Window, so nothing is ever sent)
Receiving programming looks like this:
type TWMCopyData = packed record Msg: Cardinal; From: HWND; // Handle of the Window that passed the data CopyDataStruct: PCopyDataStruct; // data passed Result: Longint; // Use it to send a value back to the "Sender" end; TTrayForm = class(TForm) ... private procedure WMCopyData(var Msg : TWMCopyData); message WM_COPYDATA; procedure TTrayForm.WMCopyData(var Msg: TWMCopyData); var s : string; tp : integer; begin s := PChar((Msg.CopyDataStruct^).lpData); tp := (Msg.CopyDataStruct^).dwData; msg.Result := 10; // Send something back ShowMessage('Recieved'); end;
The message is never shown, and debugging, execution never seem to get there. (Breakpoint at the line that is here nr. 19.)
Any good ideas?
Use ready-made components.Interesting.
Example.
First app (Controller). New empty project. Put TMemo and TSimpleIPCServer (from System), set it ServerId=TestServer, Global=True, Active=True and add OnMessageQueued event:Started it.
procedure TForm1.SimpleIPCServer1MessageQueued(Sender: TObject); begin SimpleIPCServer1.ReadMessage; Memo1.Append(SimpleIPCServer1.StringMessage); end;
Second app (Worker). New empty project. Put TSimpleIPCClient, set it ServerId=TestServer, add events for form:
procedure TForm1.FormCreate(Sender: TObject); begin if SimpleIPCClient1.ServerRunning then begin SimpleIPCClient1.Connect; SimpleIPCClient1.SendStringMessage('I started'); end; end; procedure TForm1.FormDestroy(Sender: TObject); begin if SimpleIPCClient1.Active then SimpleIPCClient1.SendStringMessage('I am finished'); end;
When the Worker started / finished, the Controller adds the appropriate lines to the memo.
I need to be able to start "the worker" manually as well.In my example is done precisely during runtime.
So the IPCClient can not be activated at design time, or the program crashes, even before the CreateForm event is fired (and even at desing time, if server is not running)...
So checking if Server is running and setting Client activate to true, if it is, is needed.
Need more checking (like what happens if Server is shut down while Client is active? Will the worker crash immediately, or when the closing message is attempted sent?)Check it by timer, for example.
Also, OnMessageQueed, does not deliver data.Yes, it's only trigger. Server create invisible window, which receive messages WM_COPYDATA, cache all inputs and trigger OnMessageQueue. By calling ReadMessage you pop all cached messages.
It is necessary to call ReadMessage, that will trigger OnMessage, to get the actual data transferred.
In my example is done precisely during runtime.May have been the intention.