Can the Hwnd from Createwindow/Createdialog Be Getmessage'D from Another Thread

Can the HWND from CreateWindow/CreateDialog be GetMessage'd from another thread?

No.

GetMessage returns messages on the current thread's input queue. The HWND parameter is a filter, so that GetMessage only returns messages in the current thread's input queue intended for that window.

Windows have thread affinity - messages intended for a window get handled on the thread that created and therefore owns the window.

Win32 - GetMessage from another thread

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).

Get message from other window

Only the thread that creates a window can directly receive and dispatch messages for that window. GetMessage() retrieves messages from the calling thread's message queue, so it can only be used with windows that are owned by the calling thread.

Since you are trying to catch messages for a window that is not yours, you will have to use SetWindowsHookEx() or SetWinEventHook() to install a hook callback into that window's owning thread, and then that callback can intercept the desired messages/events for that window. You can use GetWindowThreadProcessId() to get the IDs of the Process and Thread that own the window.

If you use SetWindowsHookEx() and are trying to hook a window in another process, your callback must reside in a DLL so it can be injected into that process. You do not need to do that with SetWinEventHook().

How can I handle window messages from a separate thread?

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)

c++ Win32 Api GetMessage closing program inside thread

your code has several problems:

  • You create window in one thread, but try to run meesage loop in another thread. GetMessage only handles messages of windows belonging to the calling thread.
  • You never wait for background thread processing messages and instead detach from it and continue execution in main thread probably ending application.
  • You don't inspect the value returned by GetMessage and use it as boolean.

If you want to make background ui thread you need to move all window creation code there and call join on thread. And message loop should look like this:

::MSG msg;
for(;;)
{
auto const res{::GetMessage(&msg, NULL, 0, 0))};
if(0 < res)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else if(0 == res)
{ // PostQuitMessage was called...
break;
}
else
{ // an error occurred...
break;
}
}

Creating a dialog in new thread

When you use a modal dialog, it creates its own message queue, that's why it works. If you want to use modeless dialogs then you will have to create a message queue yourself.

From the documentation for DialogBox:

The DialogBox macro uses the CreateWindowEx function to create the dialog box. (snip) and starts its own message loop to retrieve and dispatch messages for the dialog box.



Related Topics



Leave a reply



Submit