6

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

ProPuke
  • 158
  • 3
  • 8
  • 1
    This is almost always a terrible idea. For starters, you probably want to handle messages that *aren't actually posted* to the UI thread's input queue... Failing that, you'll at least want to *send* messages to windows owned by the UI thread, and that won't work either. Really, you should be processing messages on the UI thread, and using the separate thread for time-consuming operations, without trying to share the input queue between them. See: http://stackoverflow.com/questions/783073/processing-messages-is-too-slow-resulting-in-a-jerky-unresponsive-ui-how-can – Shog9 Dec 26 '09 at 19:20
  • For all intents & purposes I wish to use the separate thread as the ui thread. I just wish to have the ability to instigate the window creation from the primary – ProPuke Dec 26 '09 at 19:20
  • @ProPuke: and you can't do that. Windows must be owned and manipulated by one *and only one* thread: the entire system is designed with this assumption. – Shog9 Dec 26 '09 at 19:22
  • Can I pass ownership to another thread after creation? – ProPuke Dec 26 '09 at 19:24
  • 1
    @ProPuke: **no.** And what would that accomplish? You'd have to synchronize creation and manipulation anyway, so why not just create them on the thread that will be manipulating them! Keep in mind also: you shouldn't be mixing thread ownership within a given window hierarchy (top-level windows on one thread, children on another), or you'll end up with the same sort of problems. – Shog9 Dec 26 '09 at 19:32
  • @Shog9: The main thread is not a ui thread, it will be doing many other things that may involve creating windows or performing longer, blocking tasks. Thus I wish to push all message handling across, to a single worker thread, that sits in a blocking loop, waiting for window messages (it does update some local states, that are protected by critical sections) But since the creation of said windows occurs during the actions of the main thread, the windows need be created from there – ProPuke Dec 26 '09 at 19:42
  • I hate to tell you this, but... That design will give you no end of trouble. At very least, you *must* create and manipulate windows on the same thread - that could be a secondary thread, but fair warning, you might well run into problems on down the road if you try to do *anything* UI-related on your primary thread. The "main thread dispatches, other threads work" pattern is popular precisely because it's the one Windows was designed to work with; avoid it at your peril. – Shog9 Dec 26 '09 at 20:15

2 Answers2

8

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.

John Knoeller
  • 33,512
  • 4
  • 61
  • 92
  • Ahh I see. I had misinterpreted the functions purpose. I actually based the original assumption on the following answer: http://stackoverflow.com/questions/617248/can-the-hwnd-from-createwindow-createdialog-be-getmessaged-from-another-thread/621631#621631 Would you know of any alternative ways of achieving this functionality? – ProPuke Dec 26 '09 at 19:24
  • 1
    Have the original thread handle the queue, and the new thread do whatever it was you wanted the original thread to do. Alternatively, create all of your windows on the new thread. – John Knoeller Dec 26 '09 at 19:39
2

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)

ProPuke
  • 158
  • 3
  • 8