Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostMessage(hwnd, WM_SETTEXT,..) does not work while PostMessage(hwnd, WM_QUIT,..) does

I have 2 apps,one is hidden window ("hW"), another is console app ("CA"),from which i suppose to send commands to hW. In console app i'm getting hW handle,and here is a question: if i'm running:

PostMessage(hwnd, WM_QUIT, NULL, NULL);

everything works fine, message gets to hW and turns it off .But if i'm sending

PostMessage(hwnd, WM_SETTEXT, NULL, (LPARAM)"texttext");

message does not get to hW at all. Spy++ also shows that message does not get to hW. Is there something specific about WM_SETTEXT , which prevents it? Thanks in advance.

OK. found answer here http://cboard.cprogramming.com/windows-programming/72589-wm_settext-postmessage.html

Turns out the API tries to protect me against scope issues; PostMessage() 
always fails with WM_SETTEXT, or any other system-defined message that has
a pointer as a parameter.Which gets me to SendMessage(), which is not good,
because i wanted asynchronous messaging....


P.P.S.
Also, looks like

SendMessage(hwnd, WM_QUIT, NULL, NULL);

does not do anything to target app.Even in simple test app like

 HWND hNote;
 if (!(hNote=FindWindow(L"Notepad",NULL)))
        exit(1);
 SendMessage(hNote, WM_QUIT, NULL, NULL);

while

PostMessage(hNote, WM_QUIT, NULL, NULL);

works.
All that looks so not logical for me... Is there some universal function which works properly with any kind of message?

like image 683
user1821599 Avatar asked Nov 13 '12 18:11

user1821599


2 Answers

Different messages have different requirements. Some need to be posted to the queue. And some need to be delivered synchronously. So the system is designed to need both delivery mechanisms.

In the case of WM_SETTEXT, it always needs to be delivered synchronously. That's because the window manager needs to be able to manage the lifetime of the text data. Raymond Chen talked about this issue: Why can't I PostMessage the WM_COPYDATA message, but I can SendMessageTimeout it with a tiny timeout?

There is a peril with calling SendMessage when the window is in another process. If the other process is hung, that your process will not also become hung. Because SendMessage is synchronous.

The solution is to call SendMessageTimeout. This will marshal your string data into the other process. And you can set a timeout to ensure that, in the eventuality of the other process being hung, your process can avoid that fate.

like image 154
David Heffernan Avatar answered Nov 20 '22 08:11

David Heffernan


Starting with your last question: no there is not an universal message function that will do what you want.

Let's analyze your cases:

  1. WM_SETTEXT: That message takes a pointer, so you cannot post it safely between processes, as they will have separated memory addresses, and a pointer from one process would be meaningless to the other. You can use SendMessage() because Windows knows about the message, copies the data behind the scenes and does the additional hacking. But with PostMessage() there is not (cannot be) such magic.

  2. WM_QUIT: This is a special message that makes message loops break. Making it short, all it does is making GetMessage return FALSE so the standard message loop(1) finishes. But, ah! that will only work if you PostMessage() it. When you SendMessage() a message, it is sent directly to the relevant window function, without even stopping in the message queue. And windows do nothing with WM_QUIT, because they are simply not expecting it. Actually, even when posted, this message will not reach the window, as the usual loop does not call DispatchMessage() for it. That's why it is usually posted to the thread, without window, and so a functions exists that does all that: PostQuitMessage().

(1) Standard message loop:

while (GetMessage(&msg, 0, 0, 0))
    DispatchMessage(&msg);

As a footnote, you can use several tricks to move data between processes:

  1. Use WM_COPYDATA. AFAIK it cannot be used with PostMessage(), but maybe you can create two threads in the target process so that the first one receives the WM_COPYDATA and returns quickly, and then posts it to be queued by the second thread.

  2. Use shared memory (search for CreateFileMapping()) and PostMessage() an offset into that memory. You should probably use some WM_APP + x user defined message instead of a system one. However, beware of synchronization problems, you will need a mutex or something.

  3. Named pipes! (my favourite)

  4. Sockets.

like image 29
rodrigo Avatar answered Nov 20 '22 09:11

rodrigo