#define WIN32_LEAN_AND_MEAN #include #include #pragma comment(lib, "winmm.lib") DWORD g_tls = 0; DWORD WINAPI Thread(PVOID p) { ULONGLONG count = 0; g_tls = TlsAlloc(); TlsSetValue(g_tls, &count); while(InterlockedCompareExchange((LONG*)p, 0, 0)) { Sleep(500); } DWORD time = timeGetTime(), endTime; SleepEx(0, TRUE); endTime = timeGetTime(); printf("Thread dispatched %I64u apcs, took %lu ms\n", count, endTime - time); TlsFree(g_tls); return 0; } VOID CALLBACK TimerApc(PVOID p, DWORD timerLow, DWORD timerHigh) { ULONG* pTimes = (ULONG*)p; ++(*pTimes); if(*pTimes == 1) { printf("First SWT callback at %lu, sleeping for a second\n", timeGetTime()); Sleep(1000); } else { printf("SWT ran again at %lu\n", timeGetTime()); } } DWORD WINAPI ThreadTimer(PVOID p) { ULONG count = 0; HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL); LARGE_INTEGER li = {0}; li.QuadPart = -10000; SetWaitableTimer(hTimer, &li, 150, &TimerApc, &count, FALSE); while(InterlockedCompareExchange((LONG*)p, 0, 0)) { SleepEx(500, TRUE); } NtTestAlert(); CancelWaitableTimer(hTimer); CloseHandle(hTimer); printf("Despite sleeping, SWT callback ran %lu times\n", count); return 0; } VOID NTAPI Routine(PVOID, PVOID, PVOID) { ULONGLONG* pLong = (ULONGLONG*)TlsGetValue(g_tls); ++(*pLong); } void CALLBACK Callback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { int* pTimesCalled = (int*)dwUser; ++(*pTimesCalled); if(*pTimesCalled == 1) { printf("First timer thread call at %lu, sleeping for a second\n", timeGetTime()); Sleep(1000); } else { printf("Ran again at %lu\n", timeGetTime()); } } void PrintCurrentTimerResolution() { const ULONG REFTIMES_PER_MILLISEC = 10000UL; ULONG curResIn100NsUnits = 0, minResDummy, maxResDummy; NtQueryTimerResolution(&maxResDummy, &minResDummy, &curResIn100NsUnits); printf( "NtQueryTimerResolution returned min %lu, max %lu, cur %lu (%lu ms)\n", minResDummy, maxResDummy, curResIn100NsUnits, curResIn100NsUnits / REFTIMES_PER_MILLISEC ); } int main() { long runningVal = 1; HANDLE hThread1 = CreateThread(NULL, 0, &ThreadTimer, &runningVal, 0, NULL); int timesCalled = 0; UINT mmTimerId = timeSetEvent(150, 150, &Callback, (DWORD_PTR)×Called, TIME_PERIODIC | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS); Sleep(50); PostMessage(NULL, WM_COMMAND, 0, 0); int loopCount = 0; UINT_PTR timerId = SetTimer(NULL, 0, 150, NULL); MSG msg = {0}; UINT startRange = WM_COMMAND, endRange = WM_HSCROLL; while(GetMessage(&msg, NULL, startRange, endRange)) { printf("Got message of value %#x\n", msg.message); if(loopCount < 9) { PostMessage(NULL, WM_COMMAND, 0, 0); } if(++loopCount == 11) { KillTimer(NULL, timerId); startRange = endRange = 0; } if(msg.message == WM_TIMER) { break; } Sleep(100); } PrintCurrentTimerResolution(); Sleep(350); timeKillEvent(mmTimerId); _InterlockedExchange(&runningVal, 0); WaitForSingleObject(hThread1, INFINITE); CloseHandle(hThread1); printf("Despite sleeping, the multimedia timer ran %d times\n", timesCalled); return 0; }