Why the PeekMessage always return TRUE? - winapi

// Main message loop
MSG msg;
ZeroMemory( &msg, sizeof( msg ) );
while(msg.message!=WM_QUIT)
{
if(PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
The "render" function hasn't been executing

The PeekMessage documentation says this regarding the return value:
If a message is available, the return value is nonzero.
If no messages are available, the return value is zero.
When the message queue is empty, it will indeed return zero, i.e. FALSE. The conclusion therefore is that the message queue is never empty. And the most likely explanation for that is that one of the messages you handle in DispatchMessage leads to that same message being posted to the queue.

Related

m_msgCur in Visual Studio 2019

I'm currently transferring old source code to Visual Studio 2019.
The original code is from VC++6 or older.
In Windows MFC, there is a class called CWinThread, and according to the old source code, m_msgCur exists in the class. However, in VS2019, it says that m_msgCur does not exist. Then I found that m_msgCur existed long ago (https://github.com/dblock/msiext/blob/master/externals/WinDDK/7600.16385.1/inc/mfc42/afxwin.h, MFC 4.2) and it is deleted in VS2019. MSG m_msgCur contains current message of the thread, but is there any alternative variable in VS2019?
// message pump for Run
MSG m_msgCur; // current message
Edited:
Project link: https://github.com/ValveSoftware/halflife/tree/master/utils/serverctrl
Class CServerCtrlDlg (inherited from CDialog) is declared in ServerCtrlDlg.h. ServerCtrlDlg.cpp contains how it works. ServerCtrlClg.cpp includes <afxpriv.h>, and <afxpriv.h> contains afxwin.h, which has CWinThread.
Part of ServerCtrlDlg that uses m_msgCur
int CServerCtrlDlg::RunModalLoop(DWORD dwFlags)
{
ASSERT(::IsWindow(m_hWnd)); // window must be created
ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
HWND hWndParent = ::GetParent(m_hWnd);
m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
MSG* pMsg = &AfxGetThread()->m_msgCur;
// acquire and dispatch messages until the modal state is done
for (;;)
{
ASSERT(ContinueModal());
int iRet = RMLPreIdle();
if (iRet < 0)
goto ExitModal;
else if (iRet > 0)
continue;
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
// call OnIdle while in bIdle state
if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
{
// send WM_ENTERIDLE to the parent
::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
}
if ((dwFlags & MLF_NOKICKIDLE) ||
!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
{
// stop idle processing next time
bIdle = FALSE;
}
}
// phase2: pump messages while available
do
{
BOOL ShouldPump = TRUE;
ASSERT(ContinueModal());
// See if we are requiring messages to be in queue?
if ( m_bOnlyPumpIfMessageInQueue )
{
// If there isn't a message, don't turn over control to PumpMessage
// since it will block
if ( !::PeekMessage( pMsg, NULL, NULL, NULL, PM_NOREMOVE ) )
{
ShouldPump = FALSE;
}
}
// pump message, but quit on WM_QUIT
if ( ShouldPump )
{
if (!AfxGetThread()->PumpMessage())
{
AfxPostQuitMessage(0);
return -1;
}
// show the window when certain special messages rec'd
if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
if (!ContinueModal())
goto ExitModal;
// reset "no idle" state after pumping "normal" message
if (AfxGetThread()->IsIdleMessage(pMsg))
{
bIdle = TRUE;
lIdleCount = 0;
}
}
} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
}
ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
return m_nModalResult;
}
Short answer is to replace:
MSG* pMsg = &AfxGetThread()->m_msgCur; // vc++ 6
with:
MSG *pMsg = AfxGetCurrentMessage(); // vc++ 2019
A better answer, however, is that if you must hack CWnd::RunModalLoop then you should do it right, and update CServerCtrlDlg::RunModalLoop to base it on the current CWnd::RunModalLoop code from VC++ 2019, instead of the old code borrowed from VC++ 6.
Comparing CServerCtrlDlg::RunModalLoop to the CWnd::RunModalLoop implementation in VC++ 6 from mfc\src\wincore.cpp shows the following lines marked with //++ as having been added.
int CServerCtrlDlg::RunModalLoop(DWORD dwFlags)
{
//...
// acquire and dispatch messages until the modal state is done
for (;;)
{
ASSERT(ContinueModal());
int iRet = RMLPreIdle(); //++
//++
if (iRet < 0) //++
goto ExitModal; //++
else if (iRet > 0) //++
continue; //++
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
//...
//...
// phase2: pump messages while available
do
{
ASSERT(ContinueModal());
BOOL ShouldPump = TRUE; //++
//++
// See if we are requiring messages to be in queue? //++
if ( m_bOnlyPumpIfMessageInQueue ) //++
{ //++
// If there isn't a message, don't turn over control to PumpMessage //++
// since it will block //++
if ( !::PeekMessage( pMsg, NULL, NULL, NULL, PM_NOREMOVE ) ) //++
{ //++
ShouldPump = FALSE; //++
} //++
} //++
if ( ShouldPump ) //++
{
/* mfc code executed conditionally */
}
//...
}
CServerCtrlDlg::RunModalLoop should be updated to use the VC++ 2019 CWnd::RunModalLoop code, instead, then those //++ lines merged into it. The MFC changes in CWnd::RunModalLoop are small enough between the two versions that merging is straightforward.

SetWindowHookEx() returns NULL

I'm trying to create an application that will be notified about each active window change in Windows so it could do some tasks like detecting window titles, therefore "punishing" bad people accessing bad content on our PC machines. So, this is really important for the application because it's purpose is to log "bad" applications from history.
So, in my main function, I started a thread for my WindowLogger.
windowThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WindowLogger,
(LPVOID) argv[0], 0, NULL );
if (windowThread)
{
// Also a bit of protection here..
return WaitForSingleObject(windowThread, INFINITE);
}
Then, here is my WindowLogger procedure:
// Function called by main function to install hook
DWORD WINAPI
WindowLogger(LPVOID lpParameter)
{
HHOOK hWinHook;
HINSTANCE hExe = GetModuleHandle(NULL);
if (!hExe)
{
return 1;
}
else
{
hWinHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, hExe, 0);
MSG msg;
// I AM UNSURE ABOUT THIS PART..
// Probably wrong code :D ..
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
if (msg.message == HCBT_ACTIVATE) {
// my code to log the window name
}
}
UnhookWindowsHookEx(hWinHook);
}
return 0;
}
And finally, my CBTProc callback function, it logs the windows using my log() function:
LRESULT CALLBACK
CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HCBT_ACTIVATE:
{
HWND foreground = GetForegroundWindow();
char window_title[50];
if (foreground)
GetWindowText(foreground, window_title, 25);
log("|");
log(&window_title[0]);
log("|");
}
}
}
So I had debugged the program and what I figured out is that hWinHook becomes NULL after SetWindowsHookEx() -- this is what probably causes my program to mailfunction..
.. Can you help me out with this?
Thanks in advance.
Passing 0 for the dwThreadId parameter to SetWindowsHookEx is used to register a hook for all threads in the system, i.e. a global hook. However to do this, your hook code needs to be located within a DLL (so that the DLL can be mapped into the address space of other processes). Since your hook code is in your main executable rather than a DLL the call is failing.

Why does GetMessage not process WM_POWERBROADCAST messages?

I'm creating a hidden window for the purpose of handling messages. I'm experiencing that I do not receive WM_POWERBROADCAST messages in it's GetMessage loop. I do, however, receive it via my WNDPROC. I have confirmed that I do receive other messages in both locations.
Why is GetMessage not receiving WM_POWERBROADCAST?
WNDCLASSEX classInfo = {0};
classInfo.cbSize = sizeof(classInfo);
classInfo.style = WS_DISABLED;
// CustomWndProc just outputs the message and chains to DefaultWndProc
classInfo.lpfnWndProc = CustomWndProc;
classInfo.hInstance = GetModuleHandle(NULL);
classInfo.hCursor = NULL;
classInfo.hbrBackground = NULL;
classInfo.lpszMenuName = NULL;
classInfo.lpszClassName = L"MyMessageWindow";
ATOM windowClass = RegisterClassEx(&classInfo);
HWND messageWindow = CreateWindowEx(WS_EX_NOACTIVATE, L"MyMessageWindow",
L"Message Handling Window", WS_DISABLED, 0, 0, 0, 0, 0, NULL,
GetModuleHandle(NULL), NULL);
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
// This condition is never true.
if (message.message == WM_POWERBROADCAST)
std::cout << "Got WM_POWERBROADCAST" << std::endl;
}
That's because WM_POWERBROADCAST is a dispatched synchronously and so is not placed on the message queue.
In order for you to process it you need to handle it in your window procedure.

PostMessage with WM_USER doesn't seem to arrive when MsgWaitForMultipleObjectsEx is used to check for it

I have a program with a few thread loops that you can post tasks to. One of these thread loops is the UI thread loop. It has to handle window messages as well as the posted tasks, so I send WM_USER messages to wake the thread in the dispatch loop.
The problem is that sometimes (specifically when there's lot of other window messages like WM_PAINT or WM_RESIZE) my WM_USER message doesn't wake the thread. It seems that the PostMessage function doesn't wake the thread from the MsgWaitForMultipleObjectsEx call, though I can't figure out why.
This is what it looks like (some paraphrasing for simplicity):
#define HaveWorkMessage (WM_USER + 100)
class ThreadLoopUI {
public:
ThreadLoopUI()
: myHaveWork(0) {}
void PostTask(Task& aTask) {
{
ScopedLock lock(myMutex);
myTaskQueue.push_back(aTask);
}
ScheduleWork();
}
void ScheduleWork() {
if (InterlockedExchange(&myHaveWork, 1)) {
// No need to spam the message queue
return;
}
if (!PostMessage(myHWnd, HaveWorkMessage, reinterpret_cast<WPARAM>(this), 0)) {
std::cerr << "Oh noes! Could not post!" << std::endl;
}
}
void Run() {
for (;;) {
// SIMPLIFICATION, SEE EDIT BELOW
DWORD waitResult = MsgWaitForMultipleObjectsEx(0, NULL, (DWORD)INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
if (waitResult == WAIT_FAILED) {
std::cerr << "Well, that was unexpected..." << std::endl;
continue;
}
bool doWork = false;
MSG message;
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
if (message == HaveWorkMessage) {
doWork = true;
InterlockedExchange(&myHaveWork, 0);
}
// Send the message on to the window procedure
TranslateMessage(&message);
DispatchMessage(&message);
}
if (doWork) {
// Process all tasks in work queue
}
}
}
private:
HWND myHwnd;
Mutex myMutex;
std::vector<Task> myTaskQueue;
LONG volatile myHaveWork;
}
Edit: The direct call to MsgWaitForMultipleObjectsEx above was a simplification. I actually call a function that looks like this:
void WaitForMessages() {
DWORD waitResult = MsgWaitForMultipleObjectsEx(0, NULL, (DWORD)INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
if (waitResult == WAIT_OBJECT_O) {
// Comment from the Chromium source:
// A WM_* message is available.
// If a parent child relationship exists between windows across threads
// then their thread inputs are implicitly attached.
// This causes the MsgWaitForMultipleObjectsEx API to return indicating
// that messages are ready for processing (Specifically, mouse messages
// intended for the child window may appear if the child window has
// capture).
// The subsequent PeekMessages call may fail to return any messages thus
// causing us to enter a tight loop at times.
// The WaitMessage call below is a workaround to give the child window
// some time to process its input messages.
MSG message = {0};
DWORD queueStatus = GetQueueStatus(QS_MOUSE);
if (HIWORD(queueStatus) & QS_MOUSE &&
!PeekMessage(&message, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE))
{
WaitMessage();
}
}
}
When MsgWaitForMultipleObjects[Ex] says that it returned due to one or more messages, you must go into a loop processing all of them. Your code processes only one message, which means that the second message remains unprocessed. That's why you never get your WM_USER message: You gave up before you got a chance to see it.
Not sure if it is the culprit in your case, but you should organize the code so the PostMessage() is guaranteed to be used after the target thread already has its message loop.
New threads do not initially have any message queue, and it is only created after a first call attempting to get a message from it. I am not sure if MsgWaitForMultipleObjectsEx() counts here, so I would recommend to begin the thread with a call to PeekMessage(), just in order to create the queue.
Your app should guarantee that it never posts/sends messages to the thread before the PeekMessage() returns, or the message can simply get lost.
I have found the culprit now, and it seems that in some cases messages are dispatched from the queue by Windows outside of the message loop (i.e. they are sent to WindowProcedure automatically). To solve this I changed my WindowProcedureto be like this:
LRESULT CALLBACK
ThreadLoopUI::WindowProcedure(
HWND aWindowHandle,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam )
{
switch (aMessage)
{
case HaveWorkMessage:
// This might happen if windows decides to start dispatch messages from our queue
ThreadLoopUI* threadLoop = reinterpret_cast<ThreadLoopUI*>(aWParam);
InterlockedExchange(&threadLoop->myHaveWork, 0);
// Read the next WM_ message from the queue and dispatch it
threadLoop->PrivProcessNextWindowMessage();
if (threadLoop->DoWork())
{
threadLoop->ScheduleWork();
}
break;
}
return DefWindowProc(aWindowHandle, aMessage, aWParam, aLParam);
Thanks everyone for your help and suggestions!

Why does DebugActiveProcessStop crash my debugging app?

I have a debugging program which I've written to attach to a process and create a crash dump file. That part works fine.
The problem I have is that when the debugger program terminates, so does the program that it was debugging.
I did some Googling and found the DebugActiveProcessStop() API call. This didn't show up in my older MSDN documentation as it was only introduced in Windows XP so I've tried loading it dynamicall from Kernel32.dll at runtime.
Now my problem is that my debugger program crashes as soon as the _DebugActiveProcessStop() call is made. Can somebody please tell me what I'm doing wrong?
typedef BOOL (*DEBUGACTIVEPROCESSSTOP)(DWORD);
DEBUGACTIVEPROCESSSTOP _DebugActiveProcessStop;
HMODULE hK32 = LoadLibrary( "kernel32.dll" );
if( hK32 )
_DebugActiveProcessStop = (DEBUGACTIVEPROCESSSTOP) GetProcAddress( hK32,"DebugActiveProcessStop" );
else
{
printf( "Can't load Kernel32.dll\n" );
return;
}
if( ! _DebugActiveProcessStop )
{
printf( "Can't find DebugActiveProcessStop\n" );
return;
}
...
void DebugLoop( void )
{
DEBUG_EVENT de;
while( 1 )
{
WaitForDebugEvent( &de, INFINITE );
switch( de.dwDebugEventCode )
{
case CREATE_PROCESS_DEBUG_EVENT:
hProcess = de.u.CreateProcessInfo.hProcess;
break;
case EXCEPTION_DEBUG_EVENT:
// PDS: I want a crash dump immediately!
dwProcessId = de.dwProcessId;
dwThreadId = de.dwThreadId;
WriteCrashDump( &de.u.Exception );
return;
case CREATE_THREAD_DEBUG_EVENT:
case OUTPUT_DEBUG_STRING_EVENT:
case EXIT_THREAD_DEBUG_EVENT:
case EXIT_PROCESS_DEBUG_EVENT :
case LOAD_DLL_DEBUG_EVENT:
case UNLOAD_DLL_DEBUG_EVENT:
case RIP_EVENT:
default:
break;
}
ContinueDebugEvent( de.dwProcessId, de.dwThreadId, DBG_CONTINUE );
}
}
...
void main( void )
{
...
BOOL bo = DebugActiveProcess( dwProcessId );
if( bo == 0 )
printf( "DebugActiveProcess failed, GetLastError: %u \n",GetLastError() );
hProcess = OpenProcess( PROCESS_ALL_ACCESS, TRUE, dwProcessId );
if( hProcess == NULL )
printf( "OpenProcess failed, GetLastError: %u \n",GetLastError() );
DebugLoop();
_DebugActiveProcessStop( dwProcessId );
CloseHandle( hProcess );
}
The reason its crashing is because I missed out the WINAPI keyword on my function pointer definitions.
This works:
typedef BOOL (WINAPI *DEBUGSETPROCESSKILLONEXIT)(BOOL);

Resources