• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            luqingfei@C++

            為中華之崛起而崛起!
            兼聽則明,偏聽則暗。

            Win32匯編--定時器

             

            Win32匯編--定時器

             

            1、定時器簡介

            在應用程序需要使用定時器時,可以用SetTimer函數向Windows申請一個定時器,要求系統在指定的時間以后“通知”應用程序,如果申請成功的話,系統會以指定的時間周期調用SetTimer函數指定的回調函數,或者向指定的窗口過程發送WM_TIMER消息,和DOS操作系統固定以55ms的間隔觸發中斷服務程序相比,SetTimer函數可以指定的時間間隔更為靈活——以ms為單位,可以指定的時間周期為一個32位的整數,也就是從1~4294 967 295ms,這可是一個將近50天的范圍!

             

            但是在具體的使用中不要被這個參數所迷惑:由于Windows的定時器同樣是基于時鐘中斷的,所以雖然參數的單位是ms,但精度還是55ms,如果指定一個小于55ms的周期,不管是1ms還是54msWindows最快也只能在每個時鐘中斷的時候觸發這個定時器,也就是說,實際上這個定時器是以55ms為觸發周期的;另外,當指定一個時間間隔的時候,Windows以和這個間隔最接近的55ms的整數位時間來觸發定時器,假定建立一個周期為1000ms的定時器,定時器的觸發周期實際上不是1s而是989ms55ms*18)。

             

            使用定時器時還有一個要點就是定時器消息是一個低級別的消息,這表現在兩個方面:首先就是Windows只有在消息隊列中沒有其他消息的情況下才會發送WM_TIMER消息,如果窗口過程忙于處理某個消息沒有返回,使消息隊列中有消息積累起來,那么WM_TIMER消息就會被丟棄,在消息隊列再度空閑的時候,被丟棄的WM_TIMER消息不會被補發;其次,消息隊列中不會有多條WM_TIMER消息,如果消息隊列中已經有一條WM_TIMER消息,還沒來得及處理,又到了定時的時刻,那么兩條WM_TIMER消息會被合并成一條。

             

            所以,應用程序不能依靠定時器來保證某件事情必須在規定的時刻被處理,另外,也不能依賴對定時器消息計數來確定已經過去了多少時間。

             

             

            2、定時器的使用

            //Timer.rc

            #include <resource.h>

            #define DLG_MAIN 1

            #define ICO_1 1

            #define ICO_2 2

            #define IDC_SETICON 100

            #define IDC_COUNT 101

            //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ICO_1 ICON "1.ico"

            ICO_2 ICON "2.ico"

            //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            DLG_MAIN DIALOG 50, 50, 113, 40

            STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

            CAPTION "定時器例子"

            FONT 9 "宋體"

            {

                ICON ICO_1, IDC_SETICON, 8, 9, 18, 21

                LTEXT "計數:", -1, 35, 16, 25, 10

                LTEXT "", IDC_COUNT, 62, 16, 40, 10

            }

             

            對資源的定義讀者現在一定不會陌生了,這個文件中定義了兩個圖標和一個對話框,對話框中定義了一個圖標框和兩個文本框,其中的一個文本框中的文字為空,這是以后顯示每秒一次的計數值用的。

             

            //Timer.asm

                            .386

                            .model flat, stdcall

                            option casemap:none

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ; Include 文件定義

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            include         windows.inc

            include         user32.inc

            includelib      user32.lib

            include         kernel32.inc

            includelib      kernel32.lib

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ID_TIMER1       equ     1

            ID_TIMER2       equ     2

            ICO_1           equ     1

            ICO_2           equ     2

            DLG_MAIN        equ     1

            IDC_SETICON     equ     100

            IDC_COUNT       equ     101

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ; 數據段

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                            .data?

            hInstance       dd      ?

            hWinMain        dd      ?

            dwCount         dd      ?

            idTimer         dd      ?

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ; 代碼段

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                            .code

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ; 定時器過程

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            _ProcTimer      proc    _hWnd, uMsg, _idEvent, _dwTime

                            pushad

                            invoke GetDlgItemInt, hWinMain, IDC_COUNT, NULL, FALSE

                            inc    eax

                            invoke SetDlgItemInt, hWinMain, IDC_COUNT, eax, FALSE

                            popad

                            ret

            _ProcTimer      endp

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            ; 窗口過程

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            _ProcDlgMain    proc    uses ebx edi esi, hWnd, uMsg, wParam, lParam

                            mov eax, uMsg

            ;**********************************************************************************

                            .if     eax == WM_TIMER

                                    mov     eax, wParam

                                    .if     eax == ID_TIMER1

                                            inc     dwCount

                                            mov     eax, dwCount

                                            and     eax, 1

                                            inc     eax

                                            invoke LoadIcon, hInstance, eax

                                            invoke SendDlgItemMessage, hWnd, IDC_SETICON, STM_SETIMAGE, IMAGE_ICON, eax

                                    .elseif eax == ID_TIMER2

                                            invoke MessageBeep, -1

                                    .endif

            ;**********************************************************************************

                            .elseif eax == WM_INITDIALOG

                                    push    hWnd

                                    pop     hWinMain

                                    invoke SetTimer, hWnd, ID_TIMER1, 250, NULL

                                    invoke SetTimer, hWnd, ID_TIMER2, 2000, NULL

                                    invoke SetTimer, NULL, NULL, 1000, addr _ProcTimer

                                    mov     idTimer, eax

            ;**********************************************************************************

                            .elseif eax == WM_CLOSE

                                    invoke KillTimer, hWnd, ID_TIMER1

                                    invoke KillTimer, hWnd, ID_TIMER2

                                    invoke KillTimer, NULL, idTimer

                                    invoke EndDialog, hWnd, NULL

            ;**********************************************************************************

                            .else

                                    mov     eax, FALSE

                                    ret

                            .endif

                            mov     eax, TRUE

                            ret

            _ProcDlgMain    endp

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            start:

                            invoke GetModuleHandle, NULL

                            mov hInstance, eax

                            invoke DialogBoxParam, hInstance, DLG_MAIN, NULL, offset _ProcDlgMain, NULL

                            invoke ExitProcess, NULL

            ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                            end start

             

            這個程序的基本結構非常簡單,就是一個標準的對話框程序而已,在WM_INITDIALOG中用SetTimer申請了3個定時器,并在WM_CLOSE消息中用KillTimer撤銷這3個定時器。

             

            申請一個定時器使用SetTimer函數,函數的使用方法如下:

            invoke SetTimer, hWnd, nIDEvent, uElapse, lpTimerFunc

            hWnd參數是WM_TIMER消息發往的窗口句柄;nIDEvent參數是一個用戶指定的任意整數,用來標識一個程序中的多個定時器;uElapse是時間周期,以ms為單位,這個參數是必須指定的;lpTimerFunc是定時器過程,在下面的內容中有詳細介紹。如果定時器建立成功的話,函數的返回值是定時器的標識符。

             

            撤銷定時器的函數是KillTimer,該函數的使用方法是:

            invoke KillTimer, hWnd, uIDEvent

            參數hWnduIDEvent就是建立定時器時使用的數值。

            使用SetTimer函數的方法有兩種,第一種方法是要求WindowsWM_TIMER消息發往指定的窗口過程,這時候lpTimerFunc必須為NULL,如例子中的:

            invoke SetTimer, hWnd, ID_TIMER1, 250, NULL

            invoke SetTimer, hWnd, ID_TIMER2, 2000, NULL

            這兩個句子設置了兩個標識分別為ID_TIMER1ID_TIMER2的定時器,定時周期分別為250ms2s。在窗口過程收到WM_TIMER消息的時候,wParam中是用SetTimer建立定時器時使用的標識uIDEvent,所以程序可以建立一個分支,通過判斷wParam來處理不同的定時器引起的WM_TIMER的消息。在例子中,當wParamID_TIMER1的時候更換圖標框中的圖標,是ID_TIMER2的時候用MessageBeep函數來發出一聲“嘟”的聲音。如果要撤銷用這種方法建立的定時器,那么只需要用建立時的hWnduIDEvent參數簡單地調用KillTimer就可以了。

             

            還有一種使用定時器的方法,那就是要求Windows在時間到的時候調用指定的定時器過程,而不是某個窗口過程,那么只需要指定lpTimerFunc參數,如例子中的:

            invoke SetTimer, NULL, NULL, 1000, addr _ProcTimer

            這句語句要求系統把定時器消息發送到_ProcTimer定時器過程中去,但是,這時候沒有參數用來指定定時器標識,到最后如何用KillTimer撤銷這個定時器呢?答案是SetTimer函數會返回一個標識,程序可以保存這個標識并在KillTimer函數中使用。

             

            當然,這種用法中的定時器標識也可以自己指定,但這時候一定要同時指定hWnd,雖然這個hWnd沒有實際的用途,如果hWndNULL,那么即使指定了定時器標識,這個標識也會被忽略,如:

            invoke SetTimer, hWnd, ID_TIMER3, 1000, addr _ProcTimer

            這個語句定義了一個標識為ID_TIMER3、消息發往_ProcTimer子程序的定時器。

             

            定時器過程是如下定義的:

            TimerProc      proc        hWnd, uMsg, idEvent, dwTime

            Windows回調定時器過程的時候會有4個參數,uMsg總是WM_TIMERhWndidEvent是窗口句柄和定時器標識。由于有idEvent參數,所以我們同樣可以把多個定時器消息指向同一個定時器過程中,并且根據idEvent參數構建一個分支來處理不同定時器引發的消息。

             

            程序中還可能遇到一種情況:當在SetTimer中指定的定時器標識已經存在會怎樣呢?答案是Windows會用新的參數代替老的定時器參數,函數執行以后,這個標識的定時器消息將以新的時間周期發送。

             

            注意:例子程序的窗口過程中把WM_TIMER的消息的處理代碼放在第一個分支上,這是對程序的簡單優化,把頻繁發生的消息放到前面可以使程序少執行一系列的比較指令,像WM_CREATEWM_DESTROY等僅發生一次的消息可以放到分支的最后面。

             

             

            3、取Windows時間

            “定時器”這個詞很容易讓人聯想到時鐘,但是在前面介紹過,定時器是不能用來構造時鐘的,定時器用于時鐘程序中只能是用在定時刷新屏幕這個功能上,要得到系統的時間還是要靠別的方法。

             

            Win32編程中,和獲得系統時間相關的函數有3個:

            invoke GetLocalTime, lpSystemTime

            invoke GetSystemTime, lpSystemTime

            invoke GetTickCount

             

            它們之間的區別是:

            GetTickCout返回的是本次Windows啟動以來的ms數,得到的時間數值直接在eax中返回,由于這是一個32位的整數,可以表示的范圍是1~ffffffffms,所以當Windows連續運行49.7天以后,計數器會清零并重新開始。

             

            GetLocalTime返回當前的時間,GetSystemTime返回當前的格林威治標準時間,這兩個函數返回的時間數據包括年、月、日、時、分、秒、毫秒以及星期,數據比較多,所以無法放在eax中返回,應用程序需要預先設置一個SYSTEMTIME結構的緩沖區,并將緩沖區地址lpSystemTime當參數傳遞給函數,函數會把時間數據返回到這個緩沖區中。

             

            SYSTEMTIME結構的定義如下:

            SYSTEMTIME STRUCT

                   wYear                   WORD           ?      ;

                   wMonth                WORD           ?      ;

                   wDayOfWeek        WORD           ?      ;星期,0=星期日,1=星期一,……

                   wDay                    WORD           ?      ;

                   wHour                  WORD           ?      ;

                   wMinute                WORD           ?      ;

                   wSecond               WORD           ?      ;

                   wMilliseconds        WORD           ?      ;毫秒

            SYSTEMTIME ENDS

            需要注意的是,結構中的字段全部是word類型的,而Win32程序中用的往往是dword型變量,所以在使用這些數據之前往往要先把它們轉換為dword類型,用movzx指令就可以很方便地完成這個工作,如movzx eax, stSystemTime.wYearwYear字段擴展到32位后放在eax中。

             

            和獲得系統時間的函數相對應,可以用下面的兩個函數設置系統時間:

            invoke SetLocalTime, lpSystemTime

            invoke SetSystemTime, lpSystemTime

            同樣,SetLocalTime中的參數代表本地時間,SetSysTime中的參數代表格林威治標準時間,在調用函數之前,要把需要設置的時間放到一個SYSTEMTIME結構中并把結構地址當做參數傳遞給Windows

             

            posted on 2010-09-23 11:40 luqingfei 閱讀(1998) 評論(0)  編輯 收藏 引用 所屬分類: Win32匯編程語言序設計

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            留言簿(6)

            隨筆分類(109)

            隨筆檔案(105)

            Blogers

            Game

            Life

            NodeJs

            Python

            Useful Webs

            大牛

            搜索

            積分與排名

            最新評論

            閱讀排行榜

            評論排行榜

            久久精品国产WWW456C0M| 久久午夜综合久久| 亚洲国产成人精品女人久久久 | 色狠狠久久综合网| 91性高湖久久久久| 久久久精品一区二区三区| 色婷婷综合久久久久中文一区二区 | 成人国内精品久久久久影院VR| 亚洲国产一成人久久精品| 亚洲午夜精品久久久久久浪潮 | 久久精品极品盛宴观看| 久久婷婷色综合一区二区| 国内精品欧美久久精品| 精品无码久久久久久久久久| 国产成人AV综合久久| 狠狠人妻久久久久久综合| 国内精品久久久久久久亚洲| 日韩精品久久久久久| 一本一道久久精品综合| 精品久久久无码中文字幕天天| 伊人久久综合热线大杳蕉下载| 久久中文娱乐网| 国产激情久久久久影院老熟女| 99久久婷婷国产一区二区| 国产一区二区精品久久岳| 久久久91人妻无码精品蜜桃HD | 久久精品一本到99热免费| 久久久无码精品亚洲日韩蜜臀浪潮 | 狠色狠色狠狠色综合久久| 青青青青久久精品国产| 国产精品免费久久久久久久久| 久久久久久毛片免费看| 无码八A片人妻少妇久久| 午夜精品久久久久久中宇| 久久国产乱子伦免费精品| 亚洲欧美日韩精品久久| 亚洲国产成人精品91久久久| 久久久久久亚洲Av无码精品专口 | 亚洲欧美一级久久精品| 亚洲中文精品久久久久久不卡| 久久综合久久自在自线精品自|