The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Inter-process: SendMessage API with WM_COPYDATA or DDE?

I know that there are lots of ways to achieve Interprocess communication: DDE, OLE 1, OLE 2, NetBIOS, Named pipes, win sockets, RPC, WM_COPYDATA.

But I just know how to use the WM_COPYDATA and DDE...
And I was wondering which one was better: wm_copydata or dde?

I'll describe my case:

I have MyApp.exe and before today I was happy sending strings via winsock, but now I want to be able to send a string inside a PC. There could be several instances of MyApp.exe running, and there could even be several MyApp1.exe MyApp2.exe, MyAppDummyFileCopy.exe, etc....
(And even they have different names, all they should communicate).

If I have instance A, B and C.
I want A to send messages to B and C.
And C to send messages to A and B...
Etc....

Well, I have 2 options.

Option 1: Use DDE.
Option 2: I use CopyMemory to convert my string to a COPYDATASTRUCT, then I Loop through all Windows.... using GetWindowText and GetNextWindow API to loop and compare if the window text is a target window, if it is then I use the SendMessage with WM_COPYDATA to pass the data to all windows.


So.... my 2 questions are:

- Which one is faster WM_DATACOPY or DDE? Pros? Cons?
- Am I using OK the WM_DATACOPY option? Is it OK to loop all wnidows and compare window text? or should i try another way of getting all exe's instances?

Thanks in advance,
Jag
JagVb Send private email
Wednesday, June 25, 2008
 
 
> - Am I using OK the WM_DATACOPY option?

Yup, DDE is really a very old and not often used mechanism nowadays. WM_COPYDATA is probably a better idea.

Under the hood they will both probably create a memory mapped file that is mapped into the address space of each process, the performance of each will probably be similar but WM_COPYDATA just has fewer things involved with it so it is more straightforward.

A named pipe may also be a good method.


> Is it OK to loop all wnidows and compare window text?
> or should i try another way of getting all exe's
> instances?

Yeah, but window text can be rather volatile, like later on maybe you might want to include the name of the currently open file in the window text so it shows up in taskbar, stuff like that. So I'd recommend using GetClassName() and compare the window class name instead of window text.
Michael G
Wednesday, June 25, 2008
 
 
You might want to look at Memory Mapped Files as a solution. I'd definitely avoid DDE and wouldn't use WM_COPYDATA these days.
Neville Franks Send private email
Wednesday, June 25, 2008
 
 
The old new thing is always important for any Windows questions.


Please feel free to stop using DDE
http://blogs.msdn.com/oldnewthing/archive/2007/02/26/1763683.aspx

A commenter asked, "As an application programmer, can I really ignore DDE if I need to interact with explorer/shell?"

The answer is, "Yes, please!"


(DDE isn't going away just yet, but unless its the only available option for some obscure reason, you're probably going to be better off looking at alternatives.)

There's windows messages (though pay attention to what you're doing cos terminal services and user switching has complicated the issue from the old 16-bit single-user days), shared memory, old-fashioned TCP/IP sockets, web services, COM, even CORBA, lots of fun options in .NET that I haven't investigated much, and probably many others besides. There's about a hundred million message queue products, both open source and proprietary, out there as well.

But SendMessage with WM_COPYDATA isn't that bad an option, if you need something simple.

Wednesday, June 25, 2008
 
 
Hi Neville - WM_COPYDATA is just basically a higher level wrapper that will use a memory mapped file internally anyway.

If you need to transfer larger quantities of data it may be a good idea to do the lower level memory mapped file so you have more control over the details, but for something like < 64k data as strings I don't know of any reason to avoid WM_COPYDATA.
Michael G
Wednesday, June 25, 2008
 
 
Michael,

Thanks a lot for your comment. I guess you are totally right about that.

DDE is old as hell, the good thing is that it is very unlikely that Microsoft will end its support. But... I've heard is slower than WM_COPYDATA.
Anyway that's why I perferred WM_COPYDATA, but I was unsure about my method of looping all windows below desktop window.

So I'll take your advice.
Even thought I never change the Text Window, I shouldn't rely on that.... since it could be easily changed and that could lead to loss of communication.

Great advice.
Thanks.




Neville,

Well, to be honest I have never used virtual files before.

I just know they are pretty cool.
I also know you have to use several API's like CreateFileMapping to create the virtual file in RAM mem, then map it (MapViewOfFile), and a bunch of them

This solution would take like a week to code.

But I still have one question, are they really much faster than a simple SendMessage with a pointer to a COPYDATASTRUCT?
JagVb Send private email
Wednesday, June 25, 2008
 
 
Michael,


I will just broadcast 1KB.
Or maybe a couple of KB when my app is "feeling crazy".

So... I'll stay cool and start coding the WM_COPYDATA solution to my problem.

But, any advice or comment from any member is still very appreciated.

Thaks Micheal and Neville.


Kind regards,
Jag
JagVb Send private email
Wednesday, June 25, 2008
 
 
Be aware of things like terminal server and fast user switching when sending window messages around.
Chris Tavares Send private email
Wednesday, June 25, 2008
 
 
For the love of God, please don't *broadcast* your freaking messages.

There isn't a chance in hell that you'll know what other applications are running or what they'll do with your message - so just send them directly to windows owned by your own code that will know what to do with the messages.

Even if other application authors get blamed when their applications crash because of your broadcasts, that doesn't do anything useful for the actual user who, at best, will eventually learn that your application is the source of the problem.

Wednesday, June 25, 2008
 
 
> but I was unsure about my method of looping all
> windows below desktop window.

Yup, that would be the normal way to do such a thing.

Although you may want to use the EnumWindows function instead of a manual loop, I think it can be a bit more reliable.

Using GetNextWindow() will retrieve the next window in the z-order and it is theoretically possible for the z order to change right while your loop is executing, although it is not very likely. But EnumWindows should take that concern out of the picture I think.
Michael G
Wednesday, June 25, 2008
 
 
> For the love of God, please don't *broadcast* your
> freaking messages.

The original poster was not asking about a global broadcast mechanism - the original question was asking about how to identify previous instances of the same application, and then send some data to the other application instances (same program but a separate running process of it).

Certainly it is not generally a good idea to send random messages to windows that you do not own, but that is not what this question was about.
Michael G
Wednesday, June 25, 2008
 
 
Is there any chance you app can run at different integrity levels on Vista? Is it likely that someone running with UAC enabled would want to run one app as admin and the others as a normal user? If yes, then look at the ChangeWindowMessageFilter function.
Adrian
Thursday, June 26, 2008
 
 
Additionally you might want to look at SetProp and GetProp as an additionaly validation that they are you windows.
Adrian
Thursday, June 26, 2008
 
 
to_be_defined
Thursday, June 26, 2008
 
 
Chris Tavares,


Could you please be more specific with your recommendation?
I would really like that advise.

P.S.
Actually, my goal is that every single Terminal Server instance gets my message.
I suppose that looping all windows would get all the terminal server instances of MyApp.
I have read that, but I've never tried it.
(I currently do not own a Win2k+3 TS license)
Am I OK?



***********************************************


To Anonymous,


>>For the love of God, please don't *broadcast* your
>>freaking messages.
I won't do that. (Never.)

>>There isn't a chance in hell that you'll know what
>>other applications are running or what they'll do with
>>your message
You are totally right. (Always or at least this time.)

>>so just send them directly to windows owned by your own
>>code that will know what to do with the messages.
I am exactly doing that. (Always.)
[I send messages to MyApp instances that know how to interpret and handle the custom formatted messages.]

>>Even if other application authors get blamed when their
>>applications crash because of your broadcasts, that
>>doesn't do anything useful for the actual user who, at
>>best, will eventually learn that your application is
>>the source of the problem.
I promise I won't bother other applications. (Never.)

Even though I wasn't doing that, I appreciate your input AND your interest in better coding behaviors.
Some day it might be helpful to other member.


Thanks a lot,
Jag


P.S. I should have been more specific with the verb *to broadcast*. My apologies.


***********************************************


Michael,

>>Although you may want to use the EnumWindows function
>>instead of a manual loop, I think it can be a bit more
>>reliable.

Yes, you are right. It could happen that window z-order changes, GetNextWindow API could miss a window.
(It would be like winning the lottery maybe, but without the money, so I won't take that risk.)

In the other hand EnumWindows wouldn't miss that kind of *random scenario*.


Thanxs again,
Jag


***********************************************


To Adrian,



>>Is there any chance you app can run at different
>>integrity levels on Vista? Is it likely that someone
>>running with UAC enabled would want to run one app as
>>admin and the others as a normal user? If yes, then
>>look at the ChangeWindowMessageFilter function.

It is very unlikely, but might happen I guess.

With Windows Integrity Control (WIC), an administrative-sender would be able to sent to admin-receivers and non-admin-receivers.
But... a non-admin can just send messages to non-admin, because messages to admin processes won't be allowed to pass thru.
Mmm... wow.


>>Additionally you might want to look at SetProp and
>>GetProp as an additionaly validation that they are you
>>windows.
Yes, that would be an extra layer of protection.
Anyway I don't think any other window could have the same ClassName and WindowText as my receiver window.
But that extra protection won't hurt.





THANKS EVERYBODY!
JagVb Send private email
Thursday, June 26, 2008
 
 
What's wrong with FindWindow() ?  Why reimplement it with a bunch of other functions when it already exists?

(Also, named pipes aren't a bad alternative either.)

Thursday, June 26, 2008
 
 
I'd rethink named pipes, I use it for logging between a service and client, it works well for me.
Tony Edgecombe Send private email
Friday, June 27, 2008
 
 
> What's wrong with FindWindow() ?

That would work great if you only wanted to find just a single window.

If you read the original question you will see that is not the problem that was stated though, quote:  "There could be several instances of MyApp.exe running".

To find all other instances, you should use EnumWindows(), FindWindow() will not work for that.
Michael G
Friday, June 27, 2008
 
 
Another way is to use HWND_BROADCAST to broadcast a message id obtained by RegisterWindowMessage ... put your own Window handle in the LPARAM of the message ... and have your applications which receive this message reply by posting an answering message (different id) with their own Window handle to your Window. As well as using RegisterWindowMessage I might also exchange some magic numbers (e.g. 0x7439A8C3) in the WPARAM (to guard against other applications unexpectedly using my message ids).
Christopher Wells Send private email
Friday, June 27, 2008
 
 
To Anonymous,

Michael is right, EnumWindows is the way to go.

***************************************

Christopher Wells,

>>Another way is to use HWND_BROADCAST to broadcast a
>>message id obtained by RegisterWindowMessage

I think HWND_BROADCAST just lets you send long messages, Am I right?
I need to send a string (or pointer to it). Well, I am almost done with my sendmessage alternative.

Jag
JagVb Send private email
Friday, June 27, 2008
 
 
> I think HWND_BROADCAST just lets you send long messages, Am I right?

No: http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx
Christopher Wells Send private email
Saturday, June 28, 2008
 
 
Hi Christopher,

>No:
>http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx

Actually quoting from that same article:

"The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling."


When you send a message to a different process, you can't just send it stuff like a pointer to a string from your own process, each process has its own individual address space and can't automatically just read any pointer that you pass from your own address space.

You could use HWND_BROADCAST to send a WPARAM and LPARAM value out to another application, but not a whole blob of data like a string.

The reason why WM_COPYDATA exists is to solve this particular problem in a convenient way without having to manage all the low level details like creating shared memory sections and stuff yourself.
Michael G
Saturday, June 28, 2008
 
 
Michael, I agree: I was suggesting HWND_BROADCAST with RegisterWindowMessage only as an alternative way (instead of EnumWindows) to *find* the window handles of your other application instance[s]; after you've found them, you then need to use WM_COPYDATA if you want to send blocks of data to them via SendMessage.
Christopher Wells Send private email
Saturday, June 28, 2008
 
 
Hi Christopher, sorry - I had originally thought you meant as a discovery mechanism but I wasn't so sure after your last message.

For discovery that would certainly work, but it kind of distributes bits of code around to a somewhat greater extent since you have to add some more stuff into your wndproc for that.
Michael G
Sunday, June 29, 2008
 
 
> I wasn't so sure after your last message

Maybe I didn't understand what he meant by "long messages" (I thought he meant "messages with many bytes of user data", for which you need WM_COPYDATA).

> it kind of distributes bits of code

True.

It's at the same conceptual level though as WM_COPYDATA, requiring a knowledge of window handles and window messages, not of window classes; whereas, depending on the programming language or framework, the programmer might perhaps not know the name of their window class (it might be something like AfxWnd42, and then you need to dig a bit to override that).

In any case, it's not illegal to "broadcast your freaking messages" provided  that they're RegisterWindowMessage messages.
Christopher Wells Send private email
Sunday, June 29, 2008
 
 
I am not able to SendMessage to a hWnd in another Session ID on Terminal Services...

I didn't know it wasn't possible to do that.

Any advice?

Thanks,
Jag
JagVb Send private email
Wednesday, July 02, 2008
 
 
I suspect it's not possible, by design. You can use another form of IPC, e.g. "pipes"; or something else like, I don't know, TCP or http://en.wikipedia.org/wiki/Local_Procedure_Call
Christopher Wells Send private email
Wednesday, July 02, 2008
 
 
>>I suspect it's not possible, by design. You can use
>>another form of IPC, e.g. "pipes"; or something else like,
>>I don't know, TCP or
>>http://en.wikipedia.org/wiki/Local_Procedure_Call

That's right Christopher, I guess it isn't possible, after a couple of days I couldn't get it to work.
WM_COPYDATA works great, but just if the processes are on the SAME session ID. So... I'm dead in a TS environment, where we can get several sessions.
(if someone knows how to bypass this limitation, please let me know)

So, I am going to use mailslots.
I already tested that and it works ok under TS.

Thanks again,
Jag
JagVb Send private email
Thursday, July 03, 2008
 
 
I would try a different approach.
Instead of, say, sending a WM_COPYDATA message directly to another window, why not:
- put data in a common location (depending on how frequent are the messages, you can use a (temp) file, MapViewOfFile, something accesible from both sender and receiver);
- use RegisterWindowsMessage to have your message in both apps;
- send this registered message as a "pulse" message (possibly as a broadcast using HWND_BROADCAST - this will also eliminate the necessity for finding the window, or at least use it at the beginning to communicate from start to sender "I am the receiver")
- this pulse message does not transmit data, but rather is a "you have new m(ail)essage"
- the receiver is informed about message arrival, and will collect itself data from the common location.

This is far from perfect, but I think the path is clear. It depends on your specific needs...

Regards,
Cristian
Cristian Amarie Send private email
Tuesday, July 15, 2008
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz