The following is a classic message loop. The TranslateMessage(const MSG*), as MSDN says, does translate the virtual-key message(WM_KEYDOWN) into character message(WM_CHAR). Then it will post this just translated WM_CHAR message into the thread message queue.
AFAIK the message queue should be a FIFO structure, and the message WM_CHAR will be sent at the end of queue when TranslateMessage returns. I make a experiment that pressing multiple keys down at the same time, e.g. 'a', 's', and 'd'. And I put a sleep(1000) to make these 3 WM_KEYDOWN messages to be queued first in the message queue before invoked TranslateMessage() .
while (GetMessage(&msg, NULL, 0, 0))
{
Sleep(1000) // make message queue receives all the WM_KEYDOWN before Translated
TranslateMessage(&msg);
DispatchMessage(&msg);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
print_the_message(uMsg, wParam);
}
I expect the ordering should be
WM_KEYDOWN('a')
WM_KEYDOWN('s')
WM_KEYDOWN('f')
/* Queued before sleep wake */
WM_CHAR('a')
WM_CHAR('s')
WM_CHAR('f')
But print_the_message actually shows this ordering
WM_KEYDOWN('a')
WM_CHAR('a')
WM_KEYDOWN('s')
WM_CHAR('s')
WM_KEYDOWN('f')
WM_CHAR('f')
Does the character message WM_CHAR created by TranslateMessage have special priority or handling to make it can follow the previous WM_KEYDOWN message and cut in the queue?
The documentation says, with my emphasis:
The character messages are posted to the calling thread's message queue, to be read the next time the thread calls the GetMessage or PeekMessage function.
This matches the observed behaviour.
Related
My App (Windows 7, Visual C++, Release-Build) needs to write some data when windows is shutting down (restarting, user logs off). After all I want to do the same stuff as on receiving WM_CLOSE-Message which gets called during a regular close of my App (Alt-f4, Closing the window,...)
I don't need any User-Input, Dialogs and so on. Just silent writing. The writing itself should last less than a second.
To do so I do the following:
LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CLOSE){
TRACE(_T("got WM_CLOSE"));
SaveMyData();
}
switch (message) {
case WM_QUERYENDSESSION:
TRACE(_T("findme: WM_QUERYENDSESSION"));
{
BOOL bShutdownBlocked = ShutdownBlockReasonCreate(theApp.m_pMainWnd->GetSafeHwnd(), _T("Save data"));
TRACE(_T("blocked: %d, GetlastError: %d"), bShutdownBlocked, GetLastError());
}
//continue shutdown-sequence
return TRUE;
case WM_ENDSESSION:
TRACE(_T("findme: WM_ENDSESSION. Store? %d"), FALSE != (BOOL)wParam);
if (FALSE != (BOOL)wParam)
{
long lTickStart = GetTickCount();
TRACE(_T(">>> Sleep..."));
::Sleep(1000); //just a Test: do something while shutting down
TRACE(_T("<<< Sleep: %d ms"), GetTickCount()-lTickStart);
BOOL bUnblockShutdown = ShutdownBlockReasonDestroy(theApp.m_pMainWnd->GetSafeHwnd());
TRACE(_T("unblock: %d"), bUnblockShutdown);
}
return 0L;
default:
return CMDIFrameWnd::WindowProc(message, wParam, lParam);
}
}
All Traces are redirected into a file which I examine.
I tested this with the Restart Manager from the Logo Testing Tools for Windows under Win7 (rmtool -S -pid) and it works fine. I get the following Trace-Output:
findme: WM_QUERYENDSESSION
blocked 1, GetlastError: 0
findme: WM_ENDSESSION. Store? 1
>>> Sleep...
<<< Sleep: 1015 ms
unblock: 1
got WM_CLOSE
Notice the "got WM_CLOSE" which calls code to save my Data.
But it does not work, when I actually shut windows down or logoff or use rmtool with the -lr option. In this case I just get the following output:
findme: WM_QUERYENDSESSION
blocked 1, GetlastError: 0
findme: WM_ENDSESSION. Store? 1
>>> Sleep...
<<< Sleep: 1000 ms
unblock: 1
Here the WM_CLOSE-Message is no received.
Is it wrong to rely on that Message when shutting down or what to I make wrong?
As MSDN says
When an application returns TRUE for WM_QUERYENDSESSION, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.
MSDN does not specify that Windows terminates your application by sending a WM_CLOSE to it. You should do the saving in the WM_ENDSESSION handler to be on the safe side.
BTW, you should remove the call to ShutdownBlockReasonCreate. What is the use of it? If it worked you would not get a WM_ENDSESSION anymore. That function should be called in advance if you want to prevent a shutdown.
I think the trick is do do everything right in WM_ENDSESSION without sending or receiving any Windows-Messages.
Also you shouldn't rely too much on the rmtool.exe, at least when used without the -l-Parameter. It just behaves diffent than shutting down windows. So to test shutdown-scenarios you really have to shutdown (logoff, restart) instead of just simulating it.
I am quite new to handling messages in c++ and after quite a bit of reading am still a bit confused.
In my program i am calculating some files crc32 values and use PeekMessage to check for messages in the queue. I am doing this so that the dialog can still be operated while the function is performing. The only problem i have is that when the messages are being received the crc32 function effectively pauses.
Is there anyway to continue to receive message (i.e. move the dialog) and continue to run the crc32 function at the same time.
The relevant code is.
CalculateCrc32Value()
{
// Code to check crc32 value here.....
// Check message queue.
MSG uMsg;
PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&uMsg);
DispatchMessage(&uMsg);
}
How can i detect when a users computer goes into sleep (laptop lid closes, sleep mode due to inactivity, etc)?
I need to do this to disconnect the users TCP connection. Basically we got a simple chat application where we want to take the user off-line.
There is no Qt way to detect when computer goes to sleep or hibernation. But there are some platform dependent ways to do it.
On Windows you can listen for the WM_POWERBROADCAST message in your WindowProc handler:
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (WM_POWERBROADCAST == message && PBT_APMSUSPEND == wParam) {
// Going to sleep
}
}
On linux you can put the following shell script in /etc/pm/sleep.d which executes a program with arguments. You can start a program and notify your main application in some way:
#!/bin/bash
case $1 in
suspend)
#suspending to RAM
/Path/to/Program/executable Sleeping
;;
resume)
#resume from suspend
sleep 3
/Path/to/Program/executable Woken
;;
esac
For OS X you can see this.
You need to use the QNetworkConfigurationManager class available in Qt 4.7 and above.
QNetworkConfigurationManager provides access to the network
configurations known to the system and enables applications to detect
the system capabilities (with regards to network sessions) at runtime.
In particular look at the void QNetworkConfigurationManager::onlineStateChanged(bool isOnline) signal.
You may use 2 QTimers. One timer to activate slot every period of time and the second is to keep time tracking. Something like this:
// Header
QTimer timerPeriod;
QTimer timerTracker;
// Source
timerPeriod.setInterval(60*1000);
connect(&timerPeriod, SIGNAL(timeout()), this, SLOT(timerTimeout()));
// Track time to the next midnight
timerTracking.setInterval(QDateTime::currentDateTime().msecsTo(QDateTime(QDate::currentDate().addDays(1), QTime(00, 00))));
timerPeriod.start();
timerTracking.start();
// SLOT
void timerTimeout() {
int difference = abs(timerTracking.remainingTime() - QDateTime::currentDateTime().msecsTo(QDateTime(QDate::currentDate().addDays(1), QTime(00, 00))));
// There are some diffrences in times but it is rather irrelevant. If
if (difference > 500) {
diffrence > 500 timerTracking should be reset
// If diffrence is > 2000 it is sure hibernation or sleep happend
if (difference > 2000) {
// Hibernation or sleep action
}
// Taking care of small and big diffrences by reseting timerTracking
timerTracking.stop();
timerTracking.setInterval(QDateTime::currentDateTime().msecsTo(QDateTime(QDate::currentDate().addDays(1), QTime(00, 00))));
timerTracking.start();
}
}
Background:
In my application written in C++, I create a worker thread which in turn creates two threads using CreateThread(). The two threads which worker thread creates, talk to WCF Service through a client which is implemented using Windows Web Services API which offers C/C++ application programming interface (API) for building SOAP based web services and clients to them. My application implements only the client using this API.
Problem:
The problem I'm facing is that all other threads exit gracefully, except the worker thread, as you can see yourself, in the image below that WorkerThreadProc uses no CPU cycles yet it doesn't exit. There are also few other threads running which are not created by me, but by the runtime.
The thread states are as follows (as reported by ProcessExplorer):
WorkerThreadProc is in Wait:WrUserRequest state.
wWinMainCRTStartup is in Wait:UserRequest state.
All TpCallbackIndependent are in Wait:WrQueue state.
What are they waiting for? What could be possible causes that I need to look into? Also, what is the difference between WrUserRequest and UserRequest? And what does WrQueue mean? I've absolutely no idea what is going on here.
Here is my WorkerThreadProc code. I've removed all the logging statements except the last one at the bottom of the function:
DWORD WINAPI WorkerThreadProc(PVOID pVoid)
{
//Initialize GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Status status = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
if ( status != Status::Ok )
{
return 1;
}
GuiThreadData *pGuiData = (GuiThreadData*)pVoid;
auto patternIdRequestQueue= new PatternIdRequestQueue();
auto resultQueue = new ResultQueue();
auto patternManager = new PatternManager(patternIdRequestQueue);
LocalScheduler *pScheduler = new LocalScheduler(resultQueue, patternManager);
bool bInitializationDone = pScheduler->Initialize(pGuiData->m_lpCmdLine);
if ( !bInitializationDone )
{
return 0;
}
//PatternIdThread
PatternIdThread patternIdThread(patternIdRequestQueue);
DWORD dwPatternIdThreadId;
HANDLE hPatternIdThread = CreateThread(NULL, 0, PatternIdThreadProc, &patternIdThread, 0, &dwPatternIdThreadId);
ResultPersistence resultPersistence(resultQueue);
DWORD dwResultPersistenceThreadId;
HANDLE hResultPersistenceThread = CreateThread(NULL, 0, ResultPersistenceThreadProc, &resultPersistence, 0, &dwResultPersistenceThreadId);
pScheduler->ScheduleWork(pGuiData->m_hWnd, pGuiData->m_hInstance, ss.str());
pScheduler->WaitTillDone();
patternIdThread.Close();
resultPersistence.Close();
delete pScheduler;
//Uninitialize GDI+
GdiplusShutdown(gdiplusToken);
dwRet = WaitForSingleObject(hPatternIdThread, INFINITE);
CloseHandle(hPatternIdThread);
dwRet = WaitForSingleObject(hResultPersistenceThread,INFINITE);
CloseHandle(hResultPersistenceThread);
SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0);
//IMPORTANT : this verbose message is getting logged!
T_VERBOSE(EvtSrcInsightAnalysis, 0, 0, "After sending message to destroy window");
delete patternManager;
delete patternIdRequestQueue;
delete resultQueue;
return 0;
}
Please see the T_VERBOSE macro, it is used to log verbose message. I see the message is getting logged, yet the thread doesn't exit!
EDIT:
I just commented the following line in my WorkerThreadProc, then worker thread exits gracefully!
SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0);
Does it mean that SendMessage is the culprit? Why would it block the thread the calling thread?
If we look at the docs for SendMessage, you can see this little quote:
To send a message and return immediately, use the SendMessageCallback
or SendNotifyMessage function. To post a message to a thread's message
queue and return immediately, use the PostMessage or PostThreadMessage
function.
and this:
Messages sent between threads are processed only when the receiving
thread executes message retrieval code. The sending thread is blocked
until the receiving thread processes the message. However, the sending
thread will process incoming nonqueued messages while waiting for its
message to be processed. To prevent this, use SendMessageTimeout with
SMTO_BLOCK set. For more information on nonqueued messages, see
Nonqueued Messages.
so from this we can see SendMessage will block till the message is processed, which may somehow lead to a deadlock in your code, as the msgproc doesn't reside in your worker thread, leading to a context switch (which is only triggered when the thread's queue is pumped for messages). Try using PostMessage, which immediately returns.
EDIT: there is also a nice little piece of info here on message deadlocks from SendMessage
In my main dialog I have a function that creates a process and waits for it to finish. It might take up to 15-20 seconds. If I simply wait using WaitForSingleObject my dialog becomes unresponsive.
I want to use a combination of EnableWindow(FALSE), and an internal message loop to make my dialog block, but without looking like the app freezes, the way MessageBox and DoModal do. But I'm not sure how to do that an internal message loop.
I'm afraid your approach won't work. Your app is single-threaded, or at least your UI is. After you call WaitForSingleObject your thread is put to sleep and it won't process windows messages. The fact that you have an internal message loop won't matter. You should probably start a new thread and use it to wait for the process to finish, then notify your UI thread and exit. Or something along those lines.
Running internal message loop is rather trivial coding.
Something like below is all:
EnableWindow(FALSE);
while ( /* check for my exit condition */ )
{
MSG msg;
if(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if( !AfxGetApp()->PumpMessage() )
{
::PostQuitMessage(0);
}
}
}
EnableWindow(TRUE);
To wait for the process exit, you could use very short(<30ms) timeout WaitForSingleObject call in the message loop. Or MsgWaitForMultipleObjects. Or GetExitCodeProcess.
I'd like to recommend another approach.
1) Show new modal popup
2) Start the process in OnInitDialog handler and start a timer
3) Check if the process is still running in OnTimer handler, by GetExitCodeProcess
4) Call EndDialog when the process is no longer running
Try MsgWaitForMultipleObjects function; it can process Windows messages while waiting for the event object.
You could:
(a bit complicated) use MsgWaitForMultipleObjects (or MsgWaitForMultipleObjectsEx) to wait for the process to finish or for a message to arrive (processing it in the normal way).
(simple) use RegisterWaitForSingleObject to register a callback that is called in a separate thread when the process exits (and perhaps have that callback just post a message to your window).
(fairly simple) create your own thread to do the waiting in.
I'd go with the 2nd option.
DWORD ec;
if(CreateProcess( NULL, // No module name (use command line).
szExe, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
procFlags, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
{
while(GetExitCodeProcess(pi.hProcess, &ec) && ec == STILL_ACTIVE)
{
MSG msg;
while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!AfxGetApp()->PumpMessage())
{
::PostQuitMessage(0);
break;
}
}
// let MFC do its idle processing
LONG lIdle = 0;
while(AfxGetApp()->OnIdle(lIdle++))
;
}
}
if(ec)
{
CloseHandle(pi.hProcess);
}