Windows中使用精確計時器

來源:互聯網
上載者:User

1.前言。 

我們知道,在Windows中,可以通過調用SetTimer函數為應用程式分配一個計時器。當 

指定了一個時間間隔以後,Windows系統將每隔指定的時間嚮應用發送一條WM_TIMER消 

息,從而使應用程式能夠實現許多與時間相關的動作。 

然而需要指出的是,由系統發給應用程式的WM_TIMER訊息並不是非同步,這條訊息被 

放在常規的訊息佇列中,並與其它訊息一起排序。因此,即使我們在調用SetTimer() 

時設定了1000毫秒的時間間隔,應用程式卻不一定保證每隔一秒鐘接受到一條 

WM_TIMER訊息,如果另一個程式的忙碌時間超過一秒鐘,那麼我們的應用程式在那段 

時間內就不能接收到任何WM_TIMER訊息。 

顯然,這種情況的存在對那些需要精確時間間隔的應用(如某些監控程式)來說是致命 

的。所幸的是,在Windows中隱藏著某些機制,使得我們能夠獲得精確計時器服務。 

  

2.系統計時器. 

在Windows的SYSTEM.DRV驅動程式中提供了幾個鮮為人知的系統計時器函數(這幾個函 

數未寫入Windows.h中,但卻被SYSTEM.DRV輸出了),這幾個函數可以協助我們獲得精 

確計時器服務,即系統計時器。這其中最重要的是CreateSystemTimer()和 

KillSystemTimer(),這兩個函數允許我們安裝非同步計時器的回呼函數(Callback),有 

些類似於在DOS環境中截取INT   8中斷處理常式。這個回調是真正非同步,完全避開了 

Windows的訊息工具,因而具有重要意義。事實上,Microsoft   Excel和Windows   COMM 

驅動程式都用到了系統計時器,而由SetTimer()安裝的一般計時器也是由系統計時器 

來實現的。 

這兩個函數的原型如下: 

WORD   CreateSystemTimer(wMsecInterval,lpfnTimerProc); 

WORD   wMsecInterval;   /*以毫秒為單位的時間間隔,系統將每隔此時間調用一   次回呼函數 

*/ 

FARPROC   lpfn   TimerProc;/*指向回呼函數的指標*/ 

WORD   KillSystemTimer(hTimer); 

WORD   hTimer;/*欲釋放的系統計時器控制代碼*/ 

  

其中,CreateSystemTimer()用於安裝一個系統計時器回呼函數,SYSTEM   INT8處理常式將 

按wMsecInterval指定的時時間間隔調用此回呼函數。當然,這個指定的回調頻率也是有 

限的,同SetTimer()一樣,每秒鐘調用回呼函數次數不能超過18.2次,即wMsecInterval> 

55。該函數返回一個系統計時器控制代碼。若安裝失敗,則返回NULL。KillSystemTimer()則 

用於撤銷一個已安裝的系統計時器hTimer。若成功,則返回;出錯則返回傳給它的參數 

hTimer。 

  

3.使用系統計時器應注意的問題。 

系統計時器回呼函數雖然不是中斷處理常式,但由於它直接被中斷處理常式調用,因此也 

必將它看作中斷代碼。這也就決定了在使用過程中必須注意以下幾個問題: 

(1).在回函數中應包括盡量少的代碼,以使得頻繁回調的該函數不至於佔用太多的CPU時 

間。一般情況下,系統計時器總是用來監視或設定某些變數的值。 

(2).由於該回呼函數屬於中斷代碼,因此大多數Windows   API函數調用都不適用了,只有 

幾個簡單的函數仍然可以使用,如PostMessage(),GetCurrentTask()和MessageBeep() 

等。 

(3).由於該回呼函數由中斷處理常式直接調用,因此該函數必須放在一個固定的程式碼片段 

中,並且調用前必須裝載DS寄存器,這可由形實替換函數MakeProcInstance()來做到。 

另外,由於這兩個函數在Windows.h中沒有給出(即Windows預設輸入庫不含此兩函數),因 

此在調用之前必須進行連結。這可採用運行時動態連結,即通過GetModuleHandle()和 

GetProcAddress()來連結;也可在程式模組定義檔案中用IMPORTS語句來引入,此時則必 

須在程式源檔案中說明CreateSystemTimer()和KillSystemTimer()為外部函數。本文給出 

的例子採用第二種方案。 

  

4.一個例子。 

本文最後給出一個簡單的例子,以說明系統計時器是如何工作的。 

在本例中,我們安裝了一個每秒鐘調用一次的回呼函數,該回呼函數發出一聲蜂鳴。為了 

測試該系統計時器,我們特意編寫了一段較長時間的迴圈語句。在這段迴圈中,由 

SetTimer() 

安裝的通常計時器是不能工作的(因為Windows是一個非搶先的系統),而我們安裝的系統 

計時器仍然能每隔一秒鐘發出一聲蜂鳴。 

該例子在MSVC++1.5中調試通過,運行良好。 

//SystemT.c 

#include <windows.h>  

  

extern   WORD   WINAPI   CreateSystemTimer(WORD   wTimeOut,FARPROC   lpfnTimerProc); 

extern   WORD   WINAPI   KillSystemTimer(WORD   hTimer); 

  

void   FAR   PASCAL_export   MyTimerProc(void); 

WORD   SetUpSystemTimer(WORD   wTimeOut); 

BOOL   ClearSystem   Timer(WORD   hTm); 

  

FARPROC   fpTimerProc=NULL; 

WORD   hTimer=NULL; 

char   szAppName[]= "SystemTimer "; 

  

int   PASCAL   WinMain(HANDLE   hInstance,HANDLE   hPrevInstance, 

LPSTR   lpszCmdParam,int   nCmdShow) 

WNDCLASS   wc; 

HWND   hWndMain; 

int   i,j; 

HCURSOR   hcurSave; 

  

if(hPrevInstance=NULL){ 

wc.lpszMenuName   =NULL;   wc.lpszClassName   =szAppName;   wc.hInstance   =hInstance;   wc.hIcon   =LoadIcon(NULL,IDI_APPLICATION); 

wc.hCursor   =LoadCursor(NULL,IDC_ARROW); 

wc.hbrBackground   =(HBRUSH)COLOR_WINDOW+1; 

wc.style   =0;   wc.lpfnWndproc   =DefWindowProc; 

wc.cbClsExtra   =0;   wc.cbWndExtra   =0; 

if(!RegisterClass(&wc)) 

return(0);

}

if(hWndMain=CreateWindow(szAppName,

szAppName,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,

CW_USEDEFAULT,CW_USEDEFAULT, 

NULL,NULL,hInstance,NULL))=NULL) 

return(0); 

ShowWindow(hWndmain,nCmdShow); 

Update   Window(hWndMain); 

  

fpTimerProc=MakeProcInstance((FARPROC)MyTimerProc,hInstance); 

if(hTimer=SetUpSystemTimer(1000))=NULL{ 

MessageBox(hwndMain, "Set   System   Timer   Error ", 

szAppName,MB_ICONEXCLAMATION:MB_OK); 

return   0; 

hcurSave=SetCursor(LoadCursor(NULL,IDC_WAIT)); 

for(i=0;i <10000;i++) 

for(j=0;j <10000;j++) 

SetCursor(hcurSave); 

ClearSystemTime(hTimer); 

WORD   SetUpSystemTime(WORD   wTimeOut) 

WORD   hTm; 

if((hTm=CreateSystemTimer(wTimeOut,fpTimerProc))=NULL){ 

fpTimerProc=NULL: 

return   NULL 

}else   return   hTm; 

BOOL   ClearSystemTimer(WORD   hTm) 

if(hTm){ 

if(KillSystemTimer(hTm)!=0) 

return   FALSE; 

hTm=NULL; 

return   TRUE 

voidFAR   PASCAL_export   MyTimerProc(void) 

MessageBeep(0); 

//////////////////////////////////// 

//SystemT.def 

NAME   SystemTimer 

DESCRIPTION 'System   Timer ' 

EXETYPE   WINDOWS 

STUB   'WINSTUB ' 

CODE   PRELOAD 

DATA   PRELOAD   MOVABLE   MULTIPLE 

HEAPSIZE   1024 

STACKSIZE   8192 

EXPORTS   MyTimerProc 

IMPORTS   CreateSystemTimer=SYSTEM.CREATESYSTEMTIMER 

KillSystemTimer=SYSTEM.KILLSYSTEMTIMER

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.