I isolated the following code which is a Windows console application which creates a Kernel timer which will be fired every 3s then wait.
When running, if I quickly clic on No, the behavior is as expected.
But If I wait 10s or more before cliking on No, I expect all the APC in the queue (which are supposed to have been queued every 3s when I was waiting before clicking No on the first MessageBox) to be executed successively, which means to have the same number of MessageBox displayed each after each other when I click No immediatly after they are displayed. It seams that only 1 or 2 APC have been queued instead.
Any idea?
#include "stdafx.h"
#include <sdkddkver.h>
#include <stdio.h>
#include <tchar.h>
#include <time.h>
#include <string>
#include <sstream>
#include <iostream>
#include <windows.h>
class MyClass
{
public:
MyClass()
{
m_event = NULL;
}
~MyClass() {}
void do_it();
void print(const char* strMsg);
void OnTimerEvent();
int AskMessage(const char* title, const char* message);
static std::string GetCurrentTime();
private:
HANDLE m_timer;
HANDLE m_event;
};
int _tmain(int argc, _TCHAR* argv[])
{
MyClass *theMyClass;
theMyClass = new MyClass();
theMyClass->do_it();
delete theMyClass;
return 0;
}
std::string MyClass::GetCurrentTime()
{
char buff[20];
time_t now = time(NULL);
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
return buff;
}
void MyClass::print(const char* strMsg)
{
DWORD threadID = GetCurrentThreadId();
std::string str = GetCurrentTime();
str += " [Thread:";
std::stringstream ss;
ss << threadID;
ss << " (0x";
ss << std::hex << threadID;
str += ss.str().c_str();
str += ")] ";
str += strMsg;
std::cout << str << std::endl;
}
VOID CALLBACK TimerCallback(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
MyClass* thisObj = (MyClass*) lpArgToCompletionRoutine;
if (thisObj)
thisObj->OnTimerEvent();
}
void MyClass::OnTimerEvent()
{
print("Enter OnTimerEvent");
switch (AskMessage("NX Question", "Exit ?"))
{
case IDYES:
print("MessageBox NX response OK: Exit");
SetEvent(m_event);
break;
case IDNO: print("MessageBox NX response NO: Continue");
break;
default:
print("MessageBox NX response Unknown !");
break;
}
print("Exit OnTimerEvent");
}
int MyClass::AskMessage(const char* title, const char* message)
{
print("Ask MessageBox");
int response;
response = MessageBox(NULL, message, title, MB_YESNO);
return response;
}
void MyClass::do_it()
{
print("Start !");
print("Create Waitable Timer.");
m_timer = CreateWaitableTimer(NULL, TRUE, NULL);
LARGE_INTEGER liTimer = { 0 };
liTimer.QuadPart = - (__int64)(3*10000000);
print("Start Timer");
if (SetWaitableTimer(m_timer, &liTimer, 3000, TimerCallback, this, FALSE))
{
m_event = CreateEvent(NULL,FALSE,FALSE,NULL);
print("Start Waiting...");
bool exitWait = false;
while (!exitWait)
{
switch (WaitForSingleObjectEx(m_event, INFINITE, TRUE))
{
case WAIT_ABANDONED:
print("Wait Abandoned !");
exitWait = true;
break;
case WAIT_IO_COMPLETION:
print("Wait IO completion !");
break;
case WAIT_OBJECT_0:
print("Wait Object is signaled");
exitWait = true;
break;
case WAIT_TIMEOUT:
print("Wait Timeout !");
exitWait = true;
break;
case WAIT_FAILED:
print("Wait Failed !");
exitWait = true;
break;
default:
break;
}
}
print("End Waiting !");
}
CancelWaitableTimer(m_timer);
CloseHandle(m_timer);
print("End Timer");
print("End !");
}