Win32 - GetMessage from another thread - winapi

According to this thread: Can the HWND from CreateWindow/CreateDialog be GetMessage'd from another thread?, it seems that I can't use GetMessage in another thread using the main thread's HWND.
I'm simply trying to grab the value inside an edittext using GetMessage which is called from a new thread. What are some ways I can do this?

If you want to get the value from an edit control you don't actually use GetMessage at all. GetMessage is for receiving messages, but to get the text from a window you have to send it a message - i.e. you use SendMessage.
The message to send is WM_GETTEXT (preceeded by WM_GETTEXTLENGTH). Or even easier, use one of the wrapper functions the OS provides for you - in this instance GetWindowText or GetDlgItemText. They work across thread boundaries just fine (and in fact even across process boundaries).

Related

Win32 API SendMessage with HWND_BROADCAST

I am trying to send a message using myresult=SendMessage(hWnd,...). As I understand it, SendMessage sends a Windows message to the specified target hWnd; the target's WndProc returns a long value; that value is returned by SendMessage (myresult). Am I right so far?
Ok, now if the SendMessage hWnd is HWND_BROADCAST, it is sent to all top-level windows. So which window's WndProc determines the return value?
UPDATE: 02-10-20
Just to clear up what I hoped to do...
My app consists of a small constellation of windows apps that need to communicate via Windows Messages. My plan was to broadcast a registered message, e.g., WM_IDENTIFYMYAPP, and identify all siblings by responses. That won't for the reason explained in the answer by Adrian Mole.
The return value will be that from whatever is the last of the receiving windows to process the message and return; which window this is is difficult (if not impossible) for the sending application to determine.
Generally, when you want to use HWND_BROADCAST to notify multiple windows (or to communicate with a window to which you don't have a handle), you should use the (asynchronous) PostMessage function (which returns immediately) rather than SendMessage (which waits for all receiving windows to process the message).
Using the (synchronous) SendMessage with HWND_BROADCAST as the target can cause many undesirable effects, as discussed here on Stack Overflow. But note, there are some message that cannot be sent asynchronously (via PostMessage) - WM_COPYDATA is one that I know of.

Where to group-catch thread messages WINAPI/MFC

Does anyone know where is the best place to forward thread messages to child controls?
Basically, app has to catch registered thread messages in range msg_frst...msg_last and forward them to active frame/view.
There are 3 overload points in MFC, or so it seems:
DefWndProc
OnWndMessage
PreTranslateMessage
Which is the correct one to override?
A message posted with PostThreadMessage() has a NULL window handle. So forget about any of the window methods, DispatchMessage() isn't going to deliver them. All you got is CWinThread::PreTranslateMessage().
But there's a big hazard here, this isn't going to be called anymore when any code in that thread start pumping its own message loop. Your messages now fall in the bit bucket because other code is now calling Peek/GetMessage(). That's a lot more likely then you think, MessageBox() is enough. Or the COM modal loop. Etcetera.
You can only safely use PostThreadMessage() to send messages to a thread that does not create any windows of its own. The workaround is simple enough, provide the thread with a window handle so it can call PostMessage() instead. That could be a hidden window, dedicated to handling these messages for example.

How is executed a SendMessage from a different thread?

When we send a message, "if the specified window was created by the calling thread, the window procedure is called immediately as a subroutine".
But "if the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code." (taken from MSDN documentation for SendMessage).
Now, I don't understand how (or, more appropriately, when) the target windows procedure is called. Of course the target thread will not be preempted (the program counter is not changed). I presume that the call will happen during some wait function (like GetMessage or PeekMessage), it is true? That process is documented in detail somewhere?
Update: the rationale behind it is explained by the QS_SENDMESSAGE flag of GetQueueStatus() and MsgWaitForMultipleObjects():
QS_SENDMESSAGE
A message sent by another thread or application is in the queue.
This, along with additional remarks in MSDN documentation, means that a message sent by another thread is actually posted to the queue. Then, as soon as GetMessage or PeekMessage are called, it will be processed before any other posted message by being sent directly to the window procedure.
I see some confusion here.
According to the MSDN docs, when you touch the message queue of the current thread with the intent of message processing (e.g. if you call PeekMessage or GetMessage), all pending sent (i.e. non-queued) messages from other threads are handled - passed to the WndProc - and then the message queue is checked, so:
sent messages never go through DispatchMessage and are handled as soon as possible:
in the current thread, they are simply passed to WndProc
in another thread, they are handled before any posted message processing
to be able to handle sent messages, the target thread still needs a message pump
PostThreadMessage does just what it states - posts a message in a threads queue - such messages are not directed to any window and must be handled explixitly
the only messages handled by DispatchMessage are those created by PostMessage or some system facility (timers, events, user input, etc.)
to avoid deadlocks, use SendNotifyMessage, SendMessageTimeout or SendMessageCallback instead of plain SendMessage between different threads
For further reference, study the Remarks section of the MSDN PeekMessage entry.
Short answer: When the target thread calls GetMessage (or PeekMessage) followed by DispatchMessage, then the SendMessage from the other thread is received and handled.
I am not certain if the received SendMessage preempts other messages in the queue or not. Either way, a SendMessage from one thread to another is like saying: "Post this message to the other thread's message queue. Return when that thread has finished processing it".
An now for an answer you didn't ask for:
In general, when I program interactions between the main UI thread and a worker thread, I try to avoid using SendMessage. If you aren't careful, you can get into a situation where both threads are deadlocked on each other. (Think of the case where the main thread is calling WaitForSingleObject to wait for the worker thread to complete, but the worker thread is blocked on SendMessage back to the UI thread).
Every windows is associated with a thread. You can use GetWindowThreadProcessId to retrieves the thread of every window. If you send a message to a windows from the other thread with respect of PostThreadMessage the message will be placed in the thread's message queue. The thread must have a get-message loop (with GetMessage for example) to get the messages and dispatch there to the window procedure of the window.
It you call SendMessage instead of PostThreadMessage you call the Windows Procedure directly without placing it in the message queue. Some nonqueued messages are sent also immediately to the destination window procedure, bypassing the system message queue and thread message queue. (see http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages). The main reason to use SendMessage instead of PostThreadMessage if you want to give some information from another windows (control) like read a text from an another control during processing of another message. You should do this only if it really needed. So if you use SendMessage to send a message to a windows from another thread your current thread must be blocked for some time.
It can be a good idea to use PostThreadMessage or SendMessageCallback instead of SendMessage if it is possible.

How can I handle window messages from a separate thread?

I wish to launch a separate thread for handling window messages (via a blocking GetMessage loop), but still create the windows in the initial thread, afterward.
Within the separate thread, as soon as it launches, I am calling PeekMessage with PM_NOREMOVE to ensure a message queue exists (is this necessary?), followed by..
AttachThreadInput(initial thread id,GetCurrentThreadId(),true)
..before finally entering the message loop
I am not yet using a mutex or cs to ensure this is happening in time, but am merely using a Sleep statement in my initial thread for the sake of simplicity.
Regardless, window messages do not appear to be intercepted by the separate thread.
I am a little unsure as to whether I am doing this correctly, and would appreciate any possible guidance. Both threads are in the same process
Thank you all
That's not what AttachThreadInput does. Even after you attach your input queue to another thread, Windows still have thread affinity. Messages in the queue for a given window can only be removed from the queue by that window's thread.
What AttachTheadInput does is to make two threads share an input queue. This allows them to query information about the input state and know that the other thread will get the same answer for the same query. For instance, one thread could call GetAsyncKeyState and know that the answer reflected the key state for the other thread.
It allows two or more threads to have the same relationship to the input queue and each other as processes had in Windows 3x. This is the reason that this API exists; so that complex multiprocess applications could be ported from Win 3x to Win95/WinNT.
It seems the best way to instigate window creation from the main thread, while having messages for them handled in a separate, looping thread is to use a custom message, that can be sent to the separate thread - Thus allowing it to create the window, but still allowing that action to be invoked from the initial thread:
1) Allocate a custom message, and create a structure to hold the window initialisation parameters:
message_create_window = WM_USER + 0;
class Message_create_window{
Message_create_window(...);
};
2) Instead of calling CreateWindow(Ex), use something similiar to the following, passing in the relavant window creation parameters:
PostThreadMessage(
thread.id,
message_create_window,
new Message_create_window(...),
0
);
3) Handle the custom message in the message pump of your ui handling thread, extract the creation parameters, & free afterwards:
MSG msg;
GetMessage(&msg,0,0,0);
...
switch(msg->message){
...
case message_create_window:{
Message_create_window *data=msg->wParam;
CreateWindowEx(data->...);
delete data;
}break;
...
This does, however, have the following side-effects:
The window will be created asynchronously. If it is required that the initial thread block until the window is created (or, indeed, that the window's existence can ever be asserted) then a thread synchronisation tool must be used (such as an event)
Care should be taken when interacting with the window (it is a multithreaded application, after all)
If there are any major holes in this answer, or this seems like a terrible approach, please correct me.
(This is still my question, & I am trying to find the best way to accomplish this)

How to repaint the UI inside DoDragDrop

I'm implementing my app as a drag source. When I call DoDragDrop (Win32 call, not MFC) it enters into a modal loop and I don't get repaint messages in my main window until DoDragDrop returns. Unfortunately if I do a drop in the shell (a file) and the filename is already there the shell asks if I want to replace the file. But since me app is blocked because DoDragDrop hasn't returned it isn't repainting and looks 'frozen'.
Any clues ?
Have you tried a timer? I ran into the same problem with DoDragDrop() and other blocking calls like SHFileOperation() and solved it using a call to SetTimer().
EDIT: If you want more control over DoDragDrop() then a worker thread works well. You can try calling DoDragDrop() in the worker thread, as someone suggested, but I couldn't get the mouse capture to work properly. An easier solution is to call DoDragDrop() in the main thread and have the worker thread periodically post a WM_USER message to the main thread's queue. DoDragDrop() will then retrieve the message and dispatch it to your window's WndProc(), at which time you can perform idle processing for as long as the queue remains empty. If you give the worker thread a lower priority than the main thread, then it will execute and post the WM_USER message as soon as the main thread becomes idle (i.e., as soon as DoDragDrop() finishes processing all user input and calls MsgWaitForMultipleObjects() internally). This method is better than the SetTimer() method because it gives your application full control over the CPU. You don't have to wait up to 10ms (the minimum frequency that SetTimer() allows) after returning from your WM_TIMER handler returns before the next WM_TIMER message arrives.
I suggest running the drag-and-drop operation on a different thread. That way, DoDragDrop() will block the message loop in the new thread rather than the message loop in your UI thread. If you take this approach, you should also consider (off the top of my head):
Any code that might be run from both your main thread and your drag-and-drop thread will need to be re-entrant. As a corollary, you will need to protect any data structures used by both your main thread and your drag-and-drop thread. If your application is already multi-threaded, you should be familiar with these concerns.
You should think about what happens if your user never responds to the shell's dialog box. Can he continue to interact with your UI? Can he invalidate the data that would have been 'dropped' in the pending operation? Can he quit your application?
Seems like the real answer is to implement IAsyncOperation in my data object.

Resources