So I'm using messages window for process inter-communication.
Multiple processes will send the same message to the message window when a certain event occur.
I've observed that non queued messages wait for the previous message to be returned until they get processed.
Now my question is there a way to dismiss all incoming(waiting) messages at once?
One way to dismiss all waiting message is that you could get out all messages from the message queue.
case Repeated_Message:
PostMessage(hWnd, Custom_Flag, 0, 0);
while (true)
{
GetMessage(&msg, nullptr, 0, 0);
if (msg.message == Custom_Flag)
break;
}
//To Do.
break;
Related
Is there limitations – in which threads) must be (1) created window (RegisterClassEx, CreateWindowExW) and (2) performed messages processing loop ?:
MSG msg = { 0 };
while (GetMessage(&msg, 0, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
In my implementation (1) is called from the main thread, (2) is called from the new thread, specially created to get window messages.
This is console application, so I need to manually create the new window to get window messages of certain type (messages from DirectShow; not for GUI) (Win10, VS 2022).
I am creating application with win32 GUI and I tried blocking and ignoring some window messages of the message queue in my message loop. For it, I tried this following code:
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
if (msg.message != WM_... /*to complete with messages to block*/) DispatchMessage(&msg);
}
But it does not work and I can not understand why. Normally, except some particular messages, all messages pass by the message loop, so the messages that I block should be ignored! What is not wrong with my code? Mayby I shoud try to rethink my message loop?
Thanks for reading and your help.
I have a main thread that fires off several other threads to complete various items of work based on what the user choose from the main UI. Normally I'd use WaitForMultipleObjects() with bWaitAll set to TRUE. However, in this case those other threads will log output to another window that uses a mutex to ensure the threads only output one at a time. Part of that process uses SendMessage() to send get the text size and send the text to the windows which will hang if using WaitForMultipleObjects() since it's running from the main UI thread. So I moved over to use MsgWaitForMultipleObjects with QS_SENDMESSAGE flag, only it's problem is the logic for bWaitAll which states it will only return if all objects are signaled AND an input event occurred (instead of returning when all objects are signaled OR an input event occurred). Had the logic been OR this should have worked:
DWORD waitres=WAIT_FAILED;
while (1)
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
// mfc message pump
if (!theApp.PumpMessage()) {
// program end request
// TO DO
}
}
// MFC idel processing
LONG lidlecount = 0;
while (theApp.OnIdle(lidlecount++));
// our wait
waitres = ::MsgWaitForMultipleObjects(threadcount, threadhandles, TRUE, INFINITE, QS_SENDMESSAGE);
// check if ended due to message
if (waitres!=WAIT_OBJECT_0+threadcount) {
// no, exit loop
break;
}
}
Rather than fire off a thread that then fires off the other threads I wondered what is the correct way to handle this from the main thread? I thought about using bWaitAll FALSE then using WaitForMultipleObjects() with bWaitAll set to TRUE and the dwMilliseconds set to 0 (or 1) and checking the result to see if completed. If not, it would need to loop back to the top of the loop and then to MsgWaitForMultipleObjects() which when using bWaitAll FALSE could return right away if one of the many threads completed (say 1 thread of 10 completed, I could check as mentioned above if all completed, but when going back with bWaitAll FALSE it will just return and not wait).
So what is the proper way to handle waiting for multiple threads (that use SendMessage()) to complete in the main thread of an MFC application?
Thanks.
So what is the proper way to handle waiting for multiple threads to
complete
need create some structure, with reference count and pass pointer to this structure to every thread. here also probably exist sense have some common task data. and HWND of some window in main(GUI) thread. when worked thread exit - it release reference on object. when last thread exit - delete object and post some message to window, from main thread.
so we not need store thread handles (can just close it) and wait om multiple handles. instead we got some window message when all thread finish task
example of code
struct Task
{
HWND _hwnd;
LONG _dwRefCount = 1;
// some common task data probably ..
Task(HWND hwnd) : _hwnd(hwnd) {}
~Task() {
PostMessageW(_hwnd, WM_USER, 0, 0);// WM_USER as demo only
}
void AddRef(){
InterlockedIncrementNoFence(&_dwRefCount);
}
void Release(){
if (!InterlockedDecrement(&_dwRefCount)) delete this;
}
};
ULONG CALLBACK WorkThread(void* pTask)
{
WCHAR sz[16];
swprintf_s(sz, _countof(sz), L"%x", GetCurrentThreadId());
MessageBoxW(0, L"working...", sz, MB_ICONINFORMATION|MB_OK);
reinterpret_cast<Task*>(pTask)->Release();
return 0;
}
void StartTask(HWND hwnd, ULONG n)
{
if (Task* pTask = new Task(hwnd))
{
do
{
pTask->AddRef();
if (HANDLE hThread = CreateThread(0, 0, WorkThread, pTask, 0, 0))
{
CloseHandle(hThread);
}
else
{
pTask->Release();
}
} while (--n);
pTask->Release();
}
}
I spent some time trying to research a definitive answer for this and couldn't find a reliable source.
My scenario is fairly straightforward. I have a thread with a message pump setup that is processing a recurring event from a timer. Here is the message pump source:
// create timer that goes off every 500 ms
UINT_PTR myTimerID = SetTimer(NULL, 0, 500, TimerCallback);
// message structure
MSG msg;
// process and handle messages for this thread
BOOL getMessageStatus;
while((getMessageStatus = GetMessage(&msg, NULL, 0, 0)) != 0)
{
// failed get message
if(getMessageStatus == -1)
{
printf("GetMessage FAILED!\n");
}
// process timer message
else if(msg.message == WM_TIMER)
{
// invoke callback
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
If TimerCallback takes longer than 500 ms, the timer will have fired its event again. Since, the callback is being executed on the same thread as the message pump, I assume that the callback must complete before the next timer message is processed by the message pump.
Is that correct?
SetTimer() is a message-based timer. When the timer elapses, it sets a special flag inside the message queue. When you pump the queue for new messages, a WM_TIMER message will be created if that flag has been set and other higher-priority messages are not waiting in the queue. While your code is busy dispatching a generated WM_TIMER message, the timer can elapse in the background and set the flag again, generating a new WM_TIMER message the next time you pump the queue for messages. So be careful about pumping messages while inside the callback, either directly or via modal dialogs, as that can potentially lead to recursive calls of your timer callback and thus may cause a stack overflow over time. But if your message pumping is only in your main thread loop then you will be fine.
So long as there is only one entry point for processing messages, only one message can be processed at a time. You can screw things up by processing more messages in an already-running event handler, but just don't do that and you should be fine.
is there any documentation which messages are processed by DefWindowProc, and how?
I recently stumbled over WM_SETFONT/WM_GETFONT not being handled, I'm not sure if there's a mistake in my code, or if that's expected behavior, so I tried the following WinMain:
WNDCLASSEX wcx =
{
sizeof(WNDCLASSEX),
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
DefWindowProc,
0, 0, // class/wnd extra bytes
hInstance,
0,
LoadCursor(0, IDC_ARROW),
0,
0,
_T("some class"),
0
};
ATOM a = RegisterClassEx(&wcx);
_ASSERTE(a != 0);
HWND wnd = CreateWindowEx(0, wcx.lpszClassName, NULL,
WS_POPUP, 0,0,0,0, GetDesktopWindow(), 0, hInstance, 0);
_ASSERTE(wnd != 0);
HFONT font = (HFONT) GetStockObject(ANSI_VAR_FONT);
_ASSERTE(font != 0);
SendMessage(wnd, WM_SETFONT, (WPARAM) font, 0);
HFONT font2 = (HFONT) SendMessage(wnd, WM_GETFONT, 0, 0);
_ASSERTE(font2 == font); // **FAILS**, font2 is 0
As far as I am aware - no.
Each window message is a rare and unique thing that can differ in one of MANY ways. Some messages are expected to be posted, other's sent.
Some messages are notifications to the users window proc, others are commands to the DefXXXWindowProc handler(s) - DefWindowProc, DefDlgProc, DefMDIChildProc etc.
Some are handled the same in dialog and window procs, some must be handled differently.
WM_SETTEXT and WM_SETREDRAW are actually commands that DefWindowProc uses to modify internal data structures in the WND struct.
WM_SIZE is just a notification - sent BY DefWindowProc to its own window - in response to WM_WINDOWPOSCHANGED.
WM_MOUSExxx messages NEED to be posted, never sent, as windows frequently enter modal states where messages are read with GetMessage/PeekMessage and handled directly and NOT posted.
A lot of messages look like notifications, but MUST always be passed on to DefWindowProc because they're "secretly" used to implement the window manager. (WM_ACTIVATE and friends).
Most messages can be handled in a dialog proc by returning FALSE (or TRUE), some, with meaningful results need to use SetDlgResult, others are automatically handled (WM_CTLCOLOR*) as the dialog proc knows that a non zero result from the DialogProc corresponds to the LRESULT to return.
Some (WM_SYSCOMMAND) are not really messages to the window at all, and are just handled by DefWindowProc to do window manager type things (tile the desktop etc.)
There is no real attempt in the official documentation to categorize these differences.
To specifically address the WM_SET/GETFONT issue, WM_SETFONT, while a defined message, is not handled by DefwindowProc, and hence not handled by window classes that do not explicitly support it. Controls (EDIT, STATIC, etc) and Dialogs support WM_SETFONT and WM_GETFONT. To support it in a application registered class would require supplying an actual custom WindowProc and handling the message there.