之前一直使用SetTimer和OnTimer來定時,知道今天碰到了一個應用,運作結果反應SetTimer定時不準,研究了timeSetEvent/timeKillEvent的使用,其可以實作1ms的定時精度。
-
使用這兩個函數時,需要在頭部添加如下語句:
#include <MMSystem.h>
#pragma comment(lib, “Winmm.lib”)
-
timeSetEvent的函數聲明如下:
MMRESULT timeSetEvent(UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent);
參數說明:
uDelay:指定定時的時間,機關是毫秒;
uResolution:以毫秒指定延時的精度,數值越小,定時器事件的分辨率越高,預設值為1ms;
lpTimeProc:指向一個回調函數,該回調函數包含需要定時執行的代碼;
dwUser:存放使用者提供的回調資料;
fuEvent:指定定時器事件的類型:TIME_ONESHOT表示uDelay毫秒後隻産生一次事件,TIME_PERIODIC表示每隔uDelay毫秒周期性地産生事件。
-
回調函數的形式如下:
void CALLBACK CXXXDlg::MMTimeProc(UINT uID, UINT uMsg, DWORD dwUsers, DWORD dw1, DWORD dw2)
{
CXXXDlg pDlg = (CXXXDlg)(dwUsers);
//添加你的處理代碼
…
}
當回調函數是類裡面的函數時,一定要聲明為靜态函數。
-
例子:
MMRESULT timer_id = timeSetEvent(100, 1, (LPTIMECALLBACK)MMTimeProc, (DWORD)this, TIME_PERIODIC);
這條語句設定了一個定時器事件,定時精度是1ms,每隔100ms執行一次MMTimeProc指定的回調函數。
timer_id辨別該定時器事件,當不再使用時,可以使用timeKillEvent結束該定時器事件,即timeKillEvent(timer_id)。
-
對回調函數的編寫需要注意,如果不是類的成員函數,則可以直接這樣定義
void CALLBACK MMTimeProc(UINT uID, UINT uMsg, DWORD dwUsers, DWORD dw1, DWORD dw2)
{
//添加你的處理代碼
…
}
但是由于在MFC中使用,聲明為外部函數會導緻通路類成員的困難。是以可以将其定義為類的成員函數,但是需要将其定義為靜态成員函數,如此一來,仍舊無法直接通路類的其他成員函數,因為對非靜态成員函數的通路需要類對象。
注意到timeSetEvent的第四個參數,為使用者提供的回調資料,是以可以将目前對象的this指針傳遞給回調函數,然後從回調函數的第三個參數dwUsers解析出來。這樣,不論将其聲明為外部函數還是類的靜态成員函數,均可以對其中的成員資料或函數進行通路。
-
pDlg->UpdateData()報錯
當我将回調函數聲明為類的靜态成員函數,并将this指針傳遞給回調函數時,發現在回調函數内pDlg->UpdateData(TRUE)的執行出現如下圖所示錯誤
針對這一錯誤,存在兩種較為簡單的解決方式:多媒體定時器(timeSetEvent)及使用pDlg->UpdateData()錯誤
-
使用control變量或直接擷取控件指針對控件的變量進行更新:
pDlg->m_editCtrl.SetWindowText(pDlg->m_value2);
pDlg->GetDlgItem(IDC_EDIT2)->SetWindowText(pDlg->m_value2);
- 最簡單的辦法,将Debug改為Release即可正常運作。