Click to See Complete Forum and Search --> : Creating Windows in threads
Gyannea
April 28th, 2004, 07:53 PM
I seemed to have found out the hard way that I have to have a separate message loop to create a window in a thread. This is a terrible discovery since its the last thing I want to do is to burden this critical thread with a message loop....I want to keep it exclusively for handling sound data and DSP analysis on that data.
However, when a certain event is received from the radio a procedure is to begin. The detection of the event is in the analysis of the sound data in this thread. Is there a way I can 'create ' this window in the main process?
Also, within the thread what do flags in the CreateWindow() function like HWND_DESKTOP mean? Are they defined anymore?
My window gets Created even though I use HWND_DESKTOP and the 'thisInstance' parameter is garbage. However, it freezes since there is no message loop to service the callback function.
Boy, would I like a way out of this one!
Brian
MikeAThon
April 28th, 2004, 09:33 PM
When the thread detects the event, have it PostMessage() to the app's main HWND with a private message (that you #define, like WM_APP+1). The app's main window could respond to this private message by creating a new window in which to display data.
THis way, it's the main process that creates the window and is responsible for updatting it (like you asked for).
Your main process will probably need a way to know that there's new data, obtained by the thread, that needs displaying. Again, define another private message that the thread PostMessage's to the created window's HWND, and let the created window access the data and display it. Of course there will be a need for synchroniztion so that the data is not corrupted by "simultaneous" access by the two threads.
-Mike
Gyannea
April 29th, 2004, 05:59 AM
Thanks Mike,
I was thinking of doing something like that, but could I cheat and not define my own message? I was thinking about a SendMessage() instead where I steal a WM_COMMAND message with an ID (as if the message came from a control). It would be something like:
#define RXGENDSC as something somewhere
then:
WM_COMMAND with wParam = RXGENDSC and lParam = pointer to my data I want to pass
and in the main window callback
case WM_COMMAND:
switch(LOWORD(wParam))
{
case RXGENDSC:
StartRxDSCProcedure(wParam); // Routine I want
break;
}
It seems like it should work as long as Windows doesn't get in the way when I send the message. The 'SendMEssage()' is supposed to go directly to the procedure, correct?
Brian
Gyannea
April 29th, 2004, 08:22 AM
I used the SendMessage with the WM_COMMAND and stuff and it worked. I don't know if that is proper and whether or not it will get me in trouble in the future, but right now it does the job.
I had to do the same thing for sounding an alarm. The DirectSound object was created with a cooperative level in the main thread and you have to attach it to a window or the DirectSOund object won't work, so the alarm won't sound if you try to generate it from another thread.
Why a direct sound object has to be attached to a window I don't claim to understand.
Brian
MikeAThon
April 29th, 2004, 02:12 PM
Never use SendMessage between threads. I can't say that too strongly. Never.
If you use SendMessage, the least bad thing that happens is that you lose all the benefits of multi-threading. Recall how SendMessage works: it results in a direct call to the WndProc (in MFC, a "direct" call to the message handler), and SendMessage doesn't return until the message is handled. But the handler is in another thread. So the result is that your worker thread eats up the rest of its time slice waiting for a return that simply can't happen. The thread's time slice ends and eventually the handler's thread runs, and SendMessage returns. But the worker doesn't know it's returned until it gets a new time slice and starts running again. Basically, it's a huge waste of time that completely defeats your goals of multithreading.
PostMessage, on the other hand, simply posts the message to the app's message queue and then returns immediately. The worker continues to run and can profitably use the rest of its time slice. The message is processed eventually when the main thread gets a time slice.
The worst thing that can happen if you use SendMessage is a deadlock. As before, SendMessage doesn't return until the message is handled. But maybe there's something in the handler that the handler can't get to because the thread has it (typically, a shared resource that's protected by a synchroniztion object). So the handler waits for the thread to release it before it returns. And meanwhile the thread's waiting for the handler to return before it does anything further. Deadlock.
Don't use SendMessage.
As for WM_COMMAND, I see no harm in it, but wonder if there's a reason why you don't want to define a private message. If you're simulating a button click from the thread (for example) then WM_COMMAND might actually be a good idea.
-Mike
Gyannea
April 29th, 2004, 04:01 PM
Thanks Mike!
Good thoughts. The only reason for using SendMessage() is that I was concerned about Windows messing with my message which is not a normally defined WM_COMMAND message. Otherwise, using PostMessage would be a much better idea and if WIndows laves my message alone, it would be fine. I will give it a whirl. In fact, your discussion has led me to realize that I can off load a whole section of the decoder from my high priority thread (the less on that thread the better; timing is critical).
And the only reason I don't define my own messages is that I don't know how. All I know is that it can be done. I've seen it in my Windows books but have not had to use it (yet). (Do you detect some laziness?) On the other hand, I have done lots of WM_COMMAND messages to simulate mouse clicks and things like that. So familiarity and the path of least resistance has victimized me. A poor excuse.
Brian
MrViggy
April 29th, 2004, 06:41 PM
Windows shouldn't "mess" with any user defined messages.
Creating your own messages can be as simple as:
#define WM_MYNEWMESSAGE (WM_USER+100)
...
// In some code somewhere:
::PostMessage(hWnd, WM_MYNEWMESSAGE, wParam, lParam);
...
// In your MFC CWnd message map
ON_MESSAGE(WM_MYNEWMESSAGE, OnMyNewMessage)
...
LRESULT CMyWnd::OnMyNewMessage(WPARAM, LPARAP)
{
// Do Stuff
return 0;
}
Now, this works great, as long as you are not going to pass this message to another running PROCESS (i.e. another EXE). If you want to guarentee that your message is unique, across PROCESS boundries, then you need to use the ::RegisterWindowMessage function.
However, if you are only working with threads, then the '#define' method above should be sufficient.
Viggy
Martin O
May 3rd, 2004, 09:49 AM
Originally posted by MikeAThon
...
But the handler is in another thread
...
I thought that if you use SendMessage then you'd be running the code of the handler function in the thread that called SendMessage. Am I wrong about that?
MikeAThon
May 4th, 2004, 04:52 PM
Originally posted by Martin O
I thought that if you use SendMessage then you'd be running the code of the handler function in the thread that called SendMessage. Am I wrong about that?
Yes, that's wrong. The handler runs in the thread that created the window, regardless of whether the call to the handler results from a SendMessage or a PostMessage.
I delayed a response to your question, for the reason that documentation on this point is hard to find. For PostMessage, MSDN documentation is right on point. The following is found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/MessagesandMessageQueues/AboutMessagesandMessageQueues.asp
...The system removes the messages, one at a time, from the system message queue, examines them to determine the destination window, and then posts them to the message queue of the thread that created the destination window. ...
But the documents become more hazy in the case of SendMessage. That same MSDN site says the following about sent messages:
Nonqueued messages are sent immediately to the destination window procedure, bypassing the system message queue and thread message queue. ...
which implies that sent (or, "non-queued") messages aren't constrained by threads. On the other hand, that same site later on says:
A thread that calls the SendMessage function to send a message to another thread cannot continue executing until the window procedure that receives the message returns. ...
which implies that the messages are handled by the thread that created the window.
So, I wrote a brief program to check what really happens. It's a Win32 application (attached below) that creates a thread which alternately Sends and Posts a message to the main window at one-second intervals. The handler records the threadID of the thread that's handling the message. A screen shot of the output is shown below.
As you can see, regardless of whether the message is sent or posted, it's always handled by the thread that created the main window.
Regards,
Mike
MikeAThon
May 4th, 2004, 04:53 PM
Here's the program (executable and source code). I had to do this in two messages because there can only be one attachment per message.
Martin O
May 5th, 2004, 10:45 AM
Thanks Mike. I'm gonna go fix some code now :)
codeguru.com
Copyright WebMediaBrands Inc., All Rights Reserved.