My friend told me that when he opened his resource monitor (Win8 x64) my program (32bit) crashed. I took a look into this issue with MSVS2012 Ultimate where my program also crashed when the resource monitor was opened (Win7 Pro x64) and noticed that the stack trace was only about ntdll.dll and is related to CreateTimerQueueTimer.
This is the code where it fails (commenting the timer out stops the crashes):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
void CalculationTimerCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
// stuff to calculate
if (Keyboard::IsKeyPressed(VK_ESCAPE))
exit(0);
}
PHANDLE* CalcTimer = NULL;
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{
cWindow(hInstance, nCmdShow); // create window
// causes ntdll.dll to crash when resource monitor is opened
CreateTimerQueueTimer((PHANDLE)&CalcTimer, CreateTimerQueue(), (WAITORTIMERCALLBACK)CalculationTimerCallback, NULL, 0, 10, WT_EXECUTEDEFAULT);
return (int) mainloop().wParam; // goes to a while loop for rendering and stuff
}
I didn't see any examples with VOID CALLBACK before... or I was blind, could be too. The previous callback was also a modified example and did work well all the time but when the resource monitor was open. A bit weird but okay, learned something new.
The reason is, usually a function (by default) uses cdecl calling convention.
WinAPI uses stdcall.
CALLBACK is defined as "stdcall".
Mistaking a call convention is usually fatal.
This means a crash could have been occurring at any time, and it was pure luck if it didn't crash on a test run.
To make sure you never fall in these holes, NEVER cast a function pointer.