FASM--Win32彙編學習6

                         FASM--Win32彙編學習6

本節學習目標:windows時間

 

                     很多人看到“定時器”就會聯想到時鐘,筆者也曾經也是。但是在上節課程中我們已經說過,定時器是不能用來構造定時器的,定時器用於時鐘程序中只能是在定時刷新屏幕這個功能上。因爲我們調用SetTimer函數實質windows內核也是截獲我們時鐘中斷的,時鐘中斷每55ms發生一次,且我們設定間隔時間總是時鐘中斷頻率的倍數。 所以它不是很準確,那麼今天就讓我們來學習下我們如何來獲得windows的時間。

 

                     在win32編程中,常用的獲取系統時間的函數有兩個:

                    invoke GetLocalTime, lpSystemTime

                    invoke GetSystemTime,lpSystemTime

 

                   它們的區別是GetlocalTime返回的是當前的時間,GetSystemTime返回的是當前的格林威治標準時間,這兩閣函數返回的時間數據包括 年、月、日、時、分、秒、毫秒、以及星期。由於數據較多所以無法放在eax寄存器中返回,應用程序必須預先設置一個SYSTEMTIME結構的緩衝區,並將緩衝區地址lpSystemTime當參數傳遞給函數,函數會把時間數據返回到這個緩衝區中。

 

struct SYSTEMTIME
    WORD wYear;年
    WORD wMonth; 月
    WORD wDayOfWeek ;指定星期幾,例如Sunday = 0, Monday = 1
    WORD wDay;日,也就是本月的幾號
    WORD wHour;小時
    WORD wMinute; 分
    WORD wSecond; 秒
    WORD wMilliseconds; 毫秒
ends

 

那麼我們來看一段代碼。這個例子是在消息框上顯示當前的年月日以及星期幾。


    format PE GUI 4.0
    include 'win32ax.inc'
   
    ;**********************數據*****************************
    systime SYSTEMTIME
    szBuffer db 30 dup ?
   
    entry $
        invoke GetLocalTime, systime
        mov ebx, systime
        movzx eax, word [ebx];年
        movzx esi, word [ebx+2];月
        movzx edx, word [ebx+4];星期
        movzx edi, word [ebx+6];日
        invoke wsprintf,szBuffer, '%d年%d月%d日 星期%d ', eax, esi, edi,edx
        invoke MessageBox,NULL, szBuffer, '提示', MB_OK
        invoke ExitProcess,NULL
   
   
    section '.import' data import readable
        library kernel32, 'kernel32.dll',/
            user32, 'user32.dll'
        include 'api/kernel32.inc'
        include 'api/user32.inc'   

那麼此刻大家把這段代碼編譯運行,看是不是顯示出當前的時間以及星期。好我們現在來解剖這段代碼。

invoke GetLocalTime, systime

我們調用GetLocalTime函數,這個函數的參數就是剛剛我們聲明的SYSTEMTIME結構的緩衝區地址。

然後將systime這個結構的變量的地址傳送給ebx寄存器。因爲等一下要用它來進行間接尋址。這些基礎大家去之前黑防論壇也有相應的板塊。

因爲下面我們要用wsprintf函數來格式化我們的這個結構中的成員,因爲此時我們獲得是相應的16進制數值,我們需要轉換成10進制,這樣顯示出來的纔是我們真正的時間以及日期。我們可以調用wsprintf函數來格式化,那麼我們來看下這個函數的參數。

int wsprintf(

LPTSTR lpOut,    // pointer to buffer fo
LPCTSTR lpFmt,     // pointer to format-control string
...    // optional arguments
);   

首先第一個參數是指定我們輸出的緩衝區的地址 。

第二個參數是指定我們輸出的格式,這個函數其實和我們的c語言sprintf很相似,沒辦法誰讓windows是C寫的呢。所以第二個參數是指向輸出格式字符串的地址。

第三個參數則指定需輸出的參數(也就是要格式化的參數)。

 

那麼我們來看下由於我們是通過%d參數來格式化,%d是整數類型,佔4個字節。。我們的SYSTEMTIME結構每個成員是word類型,兩個字節。所以我們在進行格式化之前,我們一定要想辦法把它擴展成4個字節的。這時候我們就要用到我們的mozx指令。movzx指令是擴展指令,是將源操作數擴展成4閣字節並存放到目的操作數種,其餘擴展的數值位用0填充。。那麼很明確,我們可以利用movzx將我們的SYSTEMTIME結構的成員一部分擴展到相應的寄存器中,然後後面用寄存器來進行格式化字符串。。

        movzx eax, word [ebx];年
        movzx esi, word [ebx+2];月
        movzx edx, word [ebx+4];星期
        movzx edi, word [ebx+6];日

 

    首先我們取得systime結構變量的緩衝區地址,然後將這個地址賦值給我們的ebx寄存器,然後後面我們利用[ebx+常數]來進行變址尋址。

    我們將格式化的後的字符串保存到之前我們聲明的緩衝區中,也就是szBuffer裏,這個是我們聲明的50個字節的緩衝區。。

 

    最後通過調用MessageBox函數將其顯示出來。。

    invoke MessageBox,NULL, szBuffer, '提示', MB_OK

 

   很簡單吧。 好的,獲取本地時間,我們就講到這裏。接下來我們來學習下如何計算時間間隔。

   Windows提供給我們了一個獲取時間戳的函數,GetTickCount。GetTickCount函數返回的是windows本次啓動以來的ms數,得到的時間數值直接在eax寄存器返回。這是一個32位的證書,可以表示的範圍是1 - ffffffffh ms,所以當windows連續運行49.7天以後,計數器會清0,重新開始,雖然這個函數無法用來判斷當前的具體時間,但是計算兩個時間點的時間間隔是最合適不過了。。

        invoke GetTickCount
        mov [dwCount], eax
        invoke GetTickCount
        sub eax, [dwCount]

  在win9x系統下,GetTickCount函數的精度爲55ms,任何調用兩次GetTickCount函數相減後得到的時間間隔幺麼是0,要麼是55ms的整數倍。在windows NT/2000/xp系統下,這個函數的精度爲10ms。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章