tags:

views:

278

answers:

5

I found "Delphi Inter Process Communication (IPC) using SendMessage" with Google.

Here's a piece of the code from Sender to send a message for Receiver :

procedure TfrmClient.FormCreate(Sender: TObject);
begin
  MyMsg := RegisterWindowMessage('MyMessage');
  ServerApplicationHandle := FindWindow('TApplication', 'Project1');
end;

The problem is my receiver have random caption name. So how can I send a message to receiver? Any idea? My Sender is a DLL and my receiver is Exe.

+4  A: 

One obvious solution is for the EXE to give the DLL the handle to a window that it should send messages to. The EXE will call a function in the DLL, so that's the perfect time to provide a window handle. Remove all the guesswork. (For that matter, the EXE could just give the DLL the address of a function to call and skip messages altogether.)

Another solution is to broadcast the message. Use the special window handle HWND_BROADCAST when you call SendMessage and the message will go to all the top-level windows in the system. Only other windows that have registered the same message ID will do anything when they receive that message; the others should simply and safely ignore it.

Rob Kennedy
HWND_BROADCAST is the wrong solution. Since it uses a message that is application-defined, there's no way to 100% avoid another app defining the same message and therefore reacting to your sending of the message when it shouldn't. IIRC, Raymond Chen did a post a while back about this topic; if I get a minute, I'll check to see if I can find it to post the URL.
Ken White
Didn't edit fast enough. :-( While using RegisterWindowMessage narrows the chances of the conflict, it also still means that the window manager has to take the time to send the message to all top-level windows, and many of those top level windows will forward it to their child windows; all of this is meaningless and wastefuloverhead that can easily be avoided. Here's the URL at Raymond's site: http://blogs.msdn.com/oldnewthing/archive/2006/06/13/629451.aspx. Of special note is the last paragraph of that article.
Ken White
I don't find that article's last paragraph to be of much note. We're not broadcasting a message to trick anything into doing something for us. We're broadcasting because we really don't know which window we need to talk to. As Nat's answer suggests, the first broadcast message can also be the *only* one if we provide our own window handle as a "return address." I don't think that's too wasteful. The *danger* in broadcasting is when it's a message other windows might respond to. That's mitigated by using `RegisterWindowMessage` to generate a unique ID.
Rob Kennedy
You didn't think "hundreds of other windows" was meaningful? If you use HWND_BROADCAST, you cause your message to be BROADCAST to all other top-level windows. That's a random blast that may or may not mean something to *all* top-level windows. Not noteworthy? We have different definitions of what's worth paying attention to, I guess. The "trick" wasn't the important part.
Ken White
One more post from Raymond on the subject at http://blogs.msdn.com/oldnewthing/archive/2006/06/12/628193.aspx - in particular the list of messages that are *designed* to be broadcast, and the paragraph immediately following that list.
Ken White
I never mentioned meaning. I said it's not *too* *wasteful* — just wasteful enough for the job. The trick *was* the important part; the whole article was about sending messages to windows to get their default side effects, like turning off the monitor. The next article doesn't discuss message IDs generated by `RegisterWindowMessage`. They're outside the `wm_User` and `wm_App` ranges and shouldn't mean anything to any other windows except those who registered the same message. Chen discussed it in 2004: http://blogs.msdn.com/oldnewthing/126427.aspx.
Rob Kennedy
Is it possible to use first solution for me. Actually I have DLL to get selected path(s) from windows explorer (contextmenu). The problem is how DLL send the paths/string to EXE.
Iira, there's something you're not telling us about the relationship between the DLL and the EXE. Here's my guess: The DLL is a shell extension. Users select files in Explorer, right-click for the menu, and choose your DLL's command. The DLL then needs to forward the list of files to an already-running instance of your EXE, which does not load the DLL. There is no initial communication from the EXE to the DLL. Am I right? Then you can't use my first suggestion. In fact, **messages aren't a good solution at all** because you can't send string pointers to other processes in custom messages.
Rob Kennedy
YES, you're rightIt seems I have to use another way such as mailslots?. btw, Many of IPC codes are bundled as component. Is it possible to use VCL component for DLL? or I have to remove "procedure Register;" from the unit to make it compatible with DLL? Sorry I ask this because I cant try this now, my "pc" is in the office.
Yes. Mailslots, pipes, memory-mapped files + events, sockets — there are many non-message options for sending data to another process. No need to do anything special with components. Just create them like you'd create any other object: `ms := TMailslotComponent.Create(nil);` The `Register` procedure doesn't have to be removed; it's only called when the unit is in a design-time package anyway.
Rob Kennedy
Rob, I've tried Mailslots from http://www.funkypuppy.com/ I try to make the Sender without using the component and I still use the component for the Receiver. It works fine. But when I put the Sender's code for DLL, the Receiver can't receive the data from DLL? Weird.. My shell extension is works fine because I have tried it using clipboard for IPC method. Well u dont have crystal ball, might I send my code to u, I guess I have ur email already.
+1  A: 

Further to Rob's answer, if you have a large amount of messages to exchange, use the first message to send a window handle, and start two way non-broadcast communication.

And unless you really need an actual control, I would use AllocateHWnd() to give you a window handle to receive the broadcast.

Nat
A: 

I know it is not answer to your question but I thing the choice of IPC is not the best one in this case. Look at IPC based on named pipes. They are fater then messages and you don't have the problem, how to find the receiver:

http://www.cromis.net/blog/downloads/cromis-ipc/

Runner
A: 

Don't post to the TApplication, but to the main form, and give yor main form a meaningful name:

const
  DLL_MESSAGE = WM_APP + 100;

type
  TMyDLLMessageReceiverForm=class(TForm)
    procedure ReceiveTheDLLsCustomMessage(var Msg: TMessage); message DLL_MESSAGE;
  end;

From the DLL:

var
  WndHandle: HWND;

...

WndHandle := FindWindow('TMyDLLReceiverForm', nil);
if WndHandle <> 0 then
  PostMessage(WndHandle, DLL_MESSAGE, SomeParam, SomeOtherParam);
Ken White
This has one of the same drawbacks as the broadcasting idea, which is that you really don't know whether the window you're sending messages to is the one you wanted. Multiple windows may respond to a broadcast message, and multiple windows may have the same class name.
Rob Kennedy
So, as I said, give it a meaningful (should have probably said "distinctive") name. Chances of someone else creating a window class named "TRobKennedysCoolWizardDllForm" and conflicting with yours are a lot more slim than someone posting a message to something else that happens to conflict with the atom returned by RegisterWindowMessage(),and the "unique" value returned in that atom is just an integer, unless things have changed since I last looked.
Ken White
When there are multiple copies of the program running, which one does `FindWindow` find? Which one does `SendMessage(HWnd_Broadcast)` send to first? I'd rather not write a program that relied on the answer to either one of those questions, which is why I wrote the first paragraph of my answer.
Rob Kennedy
Rob, I think you misunderstood my objection. I was commenting *only* on the portion of your answer concerning HWND_BROADCAST, which is why there was only a comment and not a vote involved.
Ken White
A: 

Keep in mind that elevation will impact your ability to communicate. An application with elevated privileges can not send/receive messages from a process that is not.

As Runner suggested, your better with named pipes or even Mailslots.

skamradt