I have a thread that send update messages to a window, I use ::SendMessage() and ::PostMessage() APIs.
I go in and out of multiple dialogs and register the dialog that I am currently in with the thread via the window handle (m_hWnd). If I exit all the way out, the main application window doesn't handle these messages. For that reason I don't register that window. At this point the thread will have the handle of an older window which now doesn't exist.
Is it okay if it sends messages to that non-existent window? I am assuming it should not do any harm but wanted to double check.
No, it is not ok to post a message to a deleted window.
There is no guarantee noone will set up shop at that address just after the previous tennant is gone.
If you use a NULL window handle, you'll post a thread message to the current threads message queue. SendMessage as far as I could google shoul be a no-op.
Might be harmless enough.
Now, we get tricky:
Under specific cicumstances it does not matter, pre-supposing well-behaved applications.
A message like WM_NULL should not make anything happen.
A window-message you globally registered in your application using RegisterWindowMessage, if you can guarantee none of your applications windows created in the meantime will choke on it.
Related
Actually I have two questions:
Is it safe to call SendMessage from a worker thread?
Do CWnd methods, like MessageBox, call API function SendMessage behind the scene?
Per my understanding, when the worker thread calls SendMessage, it pushes the message into the message queue of the UI thread, and waits until this message is processed. In that case, it would be safe to do so.
I'm not quite sure about this. please correct me if I was wrong.
Thanks a lot.
------------------------ update ----------------------------------
As a conclusion:
It's safe to call the windows API ::SendMessage and ::PostMessage across threads.
It's not safe to call CWnd methods across threads. Some of the methods may be safe, but it's not guaranteed.
Great thanks to everyone.
Is it safe to call SendMessage from a worker thread?
Yes. The system makes sure, that message handling is serialized on the receiving thread. When sending messages across threads, the sender is blocked until the message has been handled. The receiver only handles a cross-thread sent message when it executes message retrieval code (GetMessage, PeekMessage, etc.). Sent messages are never queued in the message queue. The documentation for SendMessage has additional details.
Do CWnd methods, like MessageBox, call API function SendMessage behind the scene?
Yes. For one, the message box will receive standard window messages like WM_CREATE or WM_NCCREATE as part of the dialog construction. Also, for owned windows (like modal dialogs), the system will send WM_ACTIVATE messages to both the window being deactivated, and the window being activated. I'm not sure why this matters, though, or why you asked this question in particular.
Now the question in your title:
Is it safe to call CWnd methods from another thread?
In general, no. It does depend on the member, though. Some are safe to call, others aren't. In particular, all methods that modify window state (contents, visibility, activation, etc.) should only be called from the thread that created the window. In case the call is not safe, the system will still be in a consistent state. However, your application may not be.
The ONLY way for a thread to access the UI is by using SendMessage or PostMessage.
Consider a machine with one core, where context switching occurs and you make direct access to the UI from a worker thread, you are potentially corrupting the UI thread registers !
Basically every UI framework offers a mechanism (many times several), for making UI changes from a thread. For instance Android offers an ASyncTask and a Handler.
I need to pump COM messages while waiting for an event to fix a deadlock. It's better to pump as few messages as possible just to process that COM call. The best candidate for this role is CoWaitForMultipleHandles but starting from Vista it pumps WM_PAINT in addition to COM messages. Pumping WM_PAINT is too dangerous for me from re-entrance perspective and I don't want to install a custom shim database as a solution for this problem.
I'm trying to pump COM messages sent to the hidden message-only window manually.
I have found two ways to get HWND of the hidden window:
((SOleTlsData *) NtCurrentTeb()->ReservedForOle)->hwndSTA using ntinfo.h from .NET Core. This seems to be undocumented and not reliable solution in terms of future changes.
Find window of OleMainThreadWndClass as suggested in this question. The problem is that CoInitialize does not create the window. It is created later on first cross-apartment call which may or may not happen in my application. Running the search loop every time I need HWND is bad from performance perspective but caching HWND seems impossible because I don't know when it's created.
Is there a way to determine if the hidden window is created for the current apartment? I suppose it will be cheaper than the loop and then I could find and cache HWND.
Is there a better way to pump COM messages without pumping WM_PAINT?
Update: you can force the window creation by calling CoMarshalInterThreadInterfaceInStream for any interface. Then call CoReleaseMarshalData to release the stream pointer. This is what I end up doing along with the search for OleMainThreadWndClass.
WM_PAINT is generated when there is no other message in the message queue and you execute GetMessage or use PeekMessage.
But WM_PAINT is only sent if you Dispatch it. Also there is no new WM_PAINT message until a window is invalidated again.
So it depends on you if you dispatch a WM_PAINT message or not. But be aware, there are other chances of reentrances like a WM_TIMER message.
The details about this are in the docs for WM_PAINT.
From my point of view the best solution would be to set you application in a "wait" mode, that even can handle WM_PAINT in this undefined waiting state. You know when you are reentered. It is always after a WM_PAINT... or similar messages that arrive like other input messages. So I don't see any problems here. An STA has one thread and you always process messages to an end, until you execute GetMessage, launch a modal dialog or show a MessageBox. When you are inside some message handling, nothing will disturb you.
Maybe an other solution would be to wait inside a second thread for this event. This thread may not have any windows and you can translate the event to anything you need in your application.
So you question may not have enough information how this deadlock really appears. So this answer may not be sufficient.
After writing als this I tend to the opinion that this is an XY problem.
I have a multiple dialog MFC client app that i am working on. This client can receive a lot of messaging (>10Hz) to the main dialog, which often performs some small function, then forwards that message onto the another dialog for processing.
In my specific case, the main dialog receives messages relating to a vehicle location, updates a couple fields on that GUI, then passes it on vi a PostMessage to a window that displays all the vehicle information.
So basically, my question is this: what is the difference b/w posting the message, or just calling the dialog.update (which is a function i created)?
Well, since we don't know what your dialog.update() does, how are we to know what the difference is?
If you are doing another PostMessage, I'm not sure what the point of that is. Your program has to wait for another iteration of the message loop to retrieve your newly posted message and possibly another message could be received before that one is posted. Instead of PostMessage, you could use SendMessage which will send the message straight to the WndProc without having to iterate the message loop for another message.
I am thinking that if you are multi-threaded, then sending or posting messages will be a little more thread safe since Windows should switch contexts automatically. If you are single threaded, then it probably shouldn't matter.
I believe your application is multithreaded, and one of the thread is receivng the data, and is different than GUI thread. You should use PostMessage only from other thread to this dialog, and not SendMessage or direct call.
If you are receiving too many messages, you should buffer them - either by count (say 5000), or by some timeout. You may keep the messages into vector, list or any other collection you like. Later, when sending, post the address of this collection as WPARAM (or LPARAM) to the dialog. Dialog will get it, in a single bunch and would process it. This approach may not be correct as I am not aware about other design perspetives of your application.
You would need to trial-and-error approach, see where you get the actual performance and stability benefits.
I've got a relatively simple Window class. I've created a window, associated my this, etc etc. Now later, I've thrown an exception to indicate a problem. When I call MessageBox to pop up the error, the program crashes, because it's attempting to call my Window Proc. Now, I mean, admittedly, I failed SRP here and just writing a brief self-owning HWND class will solve this problem, as the window wasn't cleaned up properly. However, I'm really mystified as to why it's trying to process Window messages in my MessageBox call- the owner parameter is nullptr. Any suggestions?
Edit: If I call DestroyWindow appropriately, then now the message box just doesn't show up, although the app doesn't crash. It only works if I manually remove this from the window, so that if the proc were called it would forward to DefWindowProc, and then DestroyWindow. I mean, I thought that if you called MessageBox without an owner, then it would just work, regardless of what you had done to other windows in the system.
What is happening here is that there are still messages for the dud window in the queue when you show the message box. The message box runs a modal window message pump and dispatches the troublesome messages. Remember that all windows created from the same thread share a single message queue.
I have no idea how to fix your problem but that's what's going on.
By the way, passing a null owner isn't a great idea as it will result in your message box not being minimised when your main app is minimised, for example.
Is there a way to hook for a particular windows message without subclassing the window.
There is WH_GETMESSAGE but that seems create performance issues.
Any other solutions apart from these which doesn't deteriorate performance?
AFAIK there's no better solution than what you mentioned. And, of course, subclassing the window is better than hooking all the messages of the thread.
Let's think which path the message passes up until it's handled by the window:
The message is either posted or sent to the window, either by explicit call to PostMessage/SendMessage or implicitly by the OS.
Posted messages only: eventually the thread pops this message from the message queue (by calling GetMessage or similar), and then calls DispatchMessage.
The OS invokes the window's procedure by calling CallWindowProc (or similar).
The CallWindowProc identifies the window procedore associated with the window (via GetClassLong/GetWindowLong)
The above procedure is called.
Subclassing - means replacing the window procedure for the target window. This seems to be the best variant.
Installing hook with WH_GETMESSAGE flag will monitor all the messages posted to the message queue. This is bad because of the following:
Performance reasons.
You'll get notified only for windows created in the specific thread
You'll get notified only for posted messages (sent messages will not be seen)
A "posted" message doesn't necessarily means "delivered". That is, it may be filtered by the message loop (thrown away without calling DispatchMessage).
You can't see what the actual window does and returns for that message.
So that subclassing seems much better.
One more solution - in case your specific message is posted (rather than sent) you may override the message loop, and for every retrieved message you may do some pre/post-processing