Есть задача - вызвать ф-цию приблизительно через энцать милисекунд.
Я сейчас это делаю так:
1. Устанавливаю таймер с помощью ::SetTimer(), беря хенд любого окна из моего проекта.
2. В ф-ции обработчике таймера я вызываю нужную мне ф-цию.
Недостаток - привязываюсь к окну, а это меня неустраивает (я пишу независимый модуль, который не имеет никакого отношения к окнам).
Второй вариант, что мне приходит в голову:
1. Создать отдельную очередь.
2. И в этой очереди через некоторое время вызвать нужную мне ф-цию.
Недостаток - я считаю, что это слишком дорогостоящие затраты системных ресурсов.
Был бы рад выслушать прочие идеи по данному вопросу.
Оптимальный, как мне кажется, вариант - вызвать некую WinAPI'шную ф-цию, где в качестве параметров передаются моя callback ф-ция, и время через которое вызовется эта ф-ция. Т.е. почти полный аналог ::SetTimer(), но без привязки к окнам...
Аналог SetTimer() без привязки к окну
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
Серёга, любит баранью ногу.
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Если повнимательнее почитать про параметры функции ::SetTimer(), то можно увидеть что там есть четвертый параметр с указателем на функцию, которая должна быть вызвана после истечения интервала. Кроме того, чтобы не привязываться к окну (и не посылать никуда собщений), можно передать NULL вместо хендла окна
Кроме того, есть функции CreateWaitableTimer() для многопоточной среды или QueryPerformanceCounter() для спец. задач.
Кроме того, есть функции CreateWaitableTimer() для многопоточной среды или QueryPerformanceCounter() для спец. задач.
2B OR NOT(2B) = FF
Мне такое неподходит:
приводит к тому что пришедший параметр (идентификатор таймера) в ф-цию CMyClass::TimerProc недействителен...
У меня callback ф-ция - static мембер моего класса. Т.е. вызовMSDN
If hWnd parameter is NULL, no window is associated with the timer and the nIDEvent parameter is ignored.
Код: Выделить всё
HWND hWnd = NULL; // ::GetForegroundWindow();
::SetTimer(
hWnd,
(UINT)this,
0,
CMyClass::TimerProc);

Код: Выделить всё
VOID CALLBACK CMyClass::TimerProc(
HWND hwnd, // handle of window for timer messages
UINT uMsg, // WM_TIMER message
UINT idEvent, // timer identifier
DWORD dwTime // current system time
)
{
CMyClass *This = (CMyClass*)idEvent;
if (This != NULL) {
::KillTimer(hwnd, idEvent);
//This->...;
}
}
Серёга, любит баранью ногу.
Ну сделай отдельный поток тогда
Неа, всё гораздо проще.
Использую теперь multimedia timers (ф-ции timeGetDevCaps, timeBeginPeriod, timeSetEvent) или одну из ф-ций для работы с пулами потоков.
Т.е. теперь у меня реализовано так:
и соотв. callback ф-ции:
Использую теперь multimedia timers (ф-ции timeGetDevCaps, timeBeginPeriod, timeSetEvent) или одну из ф-ций для работы с пулами потоков.
Т.е. теперь у меня реализовано так:
Код: Выделить всё
#if (_WIN32_WINNT >= 0x0500)
// variant 1
bRes = ::QueueUserWorkItem(CMyClass::AsyncFunc, (PVOID)this, 0);
#else
// variant 2
TIMECAPS tc;
bRes = (TIMERR_NOERROR == ::timeGetDevCaps(&tc, sizeof(TIMECAPS)));
if (bRes) {
UINT uiTimerResolution = min(max(tc.wPeriodMin, 10), tc.wPeriodMax);
::timeBeginPeriod(uiTimerResolution);
MMRESULT uTimerID = ::timeSetEvent(uiDelay, uiTimerResolution, CMyClass::MMTimerProc, (DWORD_PTR)this, TIME_ONESHOT);
bRes = !!uTimerID;
}
#endif
Код: Выделить всё
#if (_WIN32_WINNT >= 0x0500)
DWORD CALLBACK CMyClass::AsyncFunc(LPVOID lpThreadParameter) {
CMyClass*This = (CMyClass*)lpThreadParameter;
if (This != NULL) {
//This->...
}
return 0;
}
#else
void CALLBACK CMyClass::MMTimerProc(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR)
{
CMyClass*This = (CMyClass*)dwUser;
if (This != NULL) {
//This->...
}
BOOL bRes = (TIMERR_NOERROR == ::timeKillEvent(uTimerID));
}
#endif
Серёга, любит баранью ногу.