views:

75

answers:

2

Windows messages seems a good way to notify an application on Windows OSes. It actually works well, but few question comes up to my mind:

How to specify structured data to the lparam of the SendMessage routines (like many message codes does)? I mean... of course the parameter is a pointer, but how the process access to it? Maybe is it allocated by a DLL loaded by the processes sending/receiving the message?

Is it possible to share message structured parameters (between sender and receiver)? They are marshalled between the send operation and the peeking operation? If this is the case, it is possible to return data from the caller by modifying the structured parameter? This could be usefull with SendMessage, since it is executed synchronously, instead the PostMessage routine.

Other doubts...

What the differences from PostMessage and SendNotifyMessage?

Is it possible to cause a deadlock in the case an application calls SendMessage to itself while processing the message pump?

+2  A: 

If the message is one of the standard window's messages - usually with a message id between 0 and WM_USER, then the systems window message dispatching logic contains code to marshal the struct to the any processes the message is dispatched to.

Messages above WM_USER get no such treatment - and this includes all the common control messages introduced with Windows 95 - you cannot end any of the LVM_* (list view messages) or other new control messages to a control in a different process and get a result back.

WM_COPYDATA was specifically introduced as a general purpose mechanism for user code to marshal arbitrary data between processes - outside of WM_COPYDATA (or reusing other windows standard messages) there is no way to get windows to automatically marshal structured data using the message queue mechanism into another process.

If it is your own code doing the sending AND receiving of messages, you could use a dll to define a shared memory section, instead of sending pointers (the dll might be based differently in each process) sends offsets to the shared memory block.

If you want to exchange structured data with external applications that do not marshal their data (for example to extract data from a list or tree view) then you need to perform dll injection so you can send and process the message from "in-process".


SendNofityMessage is different to PostMessage because PostMessage always puts the message in the message queue, whereas SendNotifyMessage acts like SendMessage for windows in the same process. Then, even if the target window is in another process, the message is dispatched DIRECTLY to the window proc not placed in the posted message queue for retreivel via GetMessage or PeekMessage.


Lastly it is possible to cause a deadlock - however while in a "blocking" sendmessage waiting for another thread to reply, SendMessage will dispatch messages sent (not posted) from other threads - to prevent deadlocks. This mitigates most potential deadlocks, but its still possible to create deadlocks by calling other blocking apis, or going into modal message processing loops.

Chris Becke
What about allocating memory on the heap of a shared dll?
Luca
What about it? I mentioned it. I also mentioned that its not safe as dlls and shared memory sections might be loaded at a different base address in each process - so the receiving code would have to be aware of that - which makes it not safe as a general way to communicate with 3rd party code.
Chris Becke
@Luca: a DLL in general uses the heap of its host process. Therefore a shared DLL does not imply a shared heap.
MSalters
A: 

Your concerns apply primarily in the case of messages sent between processes -- within a process, you can just send a pointer, and the sender just has to ensure the data remains valid until the receiver is finished using it.

Some interprocess messages require you to work with an HGLOBAL (e.g., the clipboard messages). Others require an explicit block size (e.g., with WM_COPYDATA). Still others send data in a pre-specified structure (e.g., a zero-terminated string) to support marshalling.

Generally speaking you can't return a value by modifying the block you received. To return a value, you need to (for example) send a reply message.

SendMessage has some (fairly complex) logic to prevent deadlocks, but you still need to be careful.

Jerry Coffin