青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

思勤無(wú)邪

上學(xué)時(shí),因我年齡最小,個(gè)頭也最小,上課時(shí),就像大猩猩堆里的猴一般。如今,這猴偶爾也把最近的一些情況寫在這里。

   :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
  132 Posts :: 1 Stories :: 178 Comments :: 0 Trackbacks

公告

     吾日常三省吾身,曰思、曰勤、曰無(wú)邪。

積分與排名

  • 積分 - 186419
  • 排名 - 140

最新隨筆

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

Win32匯編教程之一
Win32匯編的環(huán)境和基礎(chǔ)

1.32位環(huán)境簡(jiǎn)介

  在Dos下編匯編程序,我們可以管理系統(tǒng)的所有資源,我們可以改動(dòng)系統(tǒng)中所有的內(nèi)存,如自己改動(dòng)內(nèi)存控制塊來(lái)分配內(nèi)存,自己修改中斷向量表來(lái)截獲中斷等,對(duì)其他操作也是如此,如我們對(duì)鍵盤端口直接操作就可以把鍵盤屏蔽掉,可以這樣來(lái)描述Dos系統(tǒng):系統(tǒng)只有一個(gè)特權(quán)級(jí)別,在編程上講,任何程序和操作系統(tǒng)都是同級(jí)的,所以在Dos下,一個(gè)編得不好的程序會(huì)影響其他所有的程序,如一個(gè)程序把鍵盤口中斷關(guān)掉了,所有程序就都不能從鍵盤獲得鍵入的數(shù)據(jù),直到任何一個(gè)程序重新打開鍵盤為止,一個(gè)程序陷入死循環(huán),也沒(méi)有其他程序可以把它終止掉。Dos下的編程思路是“單任務(wù)”的,你只要認(rèn)為你的程序會(huì)按照你的流程一步步的執(zhí)行下去,不必考慮先后問(wèn)題(當(dāng)然程序可能會(huì)被中斷打斷,但你可以認(rèn)為它們會(huì)把環(huán)境恢復(fù),如果中斷程序沒(méi)有把環(huán)境恢復(fù),那是他們的錯(cuò))。
  在內(nèi)存管理方式上,Dos匯編和Win32匯編也有很多的不同:Dos工作在實(shí)模式下,我們可以尋址1M的內(nèi)存,尋址時(shí)通過(guò)段寄存器來(lái)制定段的初始地址,每個(gè)段的大小為64K,超過(guò)1M的部分,就只能把他作為XMS使用,也就是說(shuō),只能用作數(shù)據(jù)存放使用而無(wú)法在其中執(zhí)行程序。
  而Windows在保護(hù)模式下執(zhí)行,這里所有的資源對(duì)應(yīng)用程序來(lái)說(shuō)都是被“保護(hù)”的:程序在執(zhí)行中有級(jí)別之分,只有操作系統(tǒng)工作在最高級(jí)--0級(jí)中,所有應(yīng)用程序都工作在3級(jí)中(Ring3), 在Ring3中,你無(wú)法直接訪問(wèn)IO端口,無(wú)法訪問(wèn)其他程序運(yùn)行的內(nèi)存,連向程序自己的代碼段寫入數(shù)據(jù)都是非法的,會(huì)在Windows的屏幕上冒出一個(gè)熟悉的藍(lán)屏幕來(lái)。只有對(duì)Ring0的程序來(lái)說(shuō),系統(tǒng)才是全開放的。
  在內(nèi)存方面,Windows使用了處理器的分頁(yè)機(jī)制,使得對(duì)應(yīng)用程序來(lái)說(shuō),所有的內(nèi)存都是“平坦”的,你不必用一個(gè)段寄存器去指定段的地址,因?yàn)樵诒Wo(hù)模式下,段寄存器的含義是不同的(可以參見80386手冊(cè)方面的書籍),你可以直接指定一個(gè)32位的地址來(lái)尋址4GB的內(nèi)存。
  在程序結(jié)構(gòu)方面,Windows程序也有很大的不同,它是“基于消息”的,你可以想象這樣一個(gè)常見的Windows窗口,上面有幾個(gè)按鈕,如果你用Dos編程的思路去考慮,你會(huì)發(fā)現(xiàn)實(shí)現(xiàn)它很困難:鼠標(biāo)移動(dòng)到窗口邊緣時(shí)拖動(dòng)會(huì)改變窗口大小,鼠標(biāo)點(diǎn)擊按鈕時(shí)再做要做的事,你會(huì)發(fā)現(xiàn),你的程序自開始執(zhí)行后就在等待,你不知道鼠標(biāo)先會(huì)點(diǎn)什么地方,實(shí)際上你是在等待所有可能的事情的發(fā)生。而在Dos下,你可以只顧自己先執(zhí)行,需要用戶輸入時(shí),再停下來(lái),你不輸入我就不再執(zhí)行,而且,我讓你輸入數(shù)據(jù)A你就不能輸入數(shù)據(jù)B。
  好了,言歸正傳,因?yàn)橐陨鲜荳in32編程的基礎(chǔ),無(wú)論對(duì)Win32匯編還是VC++,它們都是一樣的,下面我們來(lái)看看有關(guān)Win32匯編的內(nèi)容。

2.Win32A***編譯器

  Win32A***的編譯器最常用的有兩種:Borland公司的Tasm5.0和Microsoft的Masm6.11以上版本,兩種編譯器各有自己的優(yōu)缺點(diǎn),Tasm帶了一個(gè)不大不小的Import庫(kù),而Masm沒(méi)有帶,但Masm在代碼的優(yōu)化上面好象比Tasm做得好,但它卻不帶Import庫(kù)??磥?lái)使用哪一種編譯器還是比較難選擇的,但Steve Hutchesson給了我們一個(gè)答案,他為Masm建立了一個(gè)很全的Import庫(kù),基本上包括了Windows絕大部分的Api函數(shù),這些庫(kù)、include文件和其他工具還有Masm6.14版本一起做成了一個(gè) Masm32編譯器 -- Masm32V5。這樣一來(lái),我們用匯編編程就象用C一樣方便。
  因?yàn)橛辛薓asm32V5,所以就我個(gè)人而言,我推薦使用Masm作為Win32A***的編譯工具,但Masm和Tasm的宏語(yǔ)法有很多的不同,我的這個(gè)教程是以Masm格式寫的。

3.Masm32的環(huán)境設(shè)置

  在Win32編程中,由于Windows有很多的數(shù)據(jù)結(jié)構(gòu)和定義,這些都放在include文件中,還有連接時(shí)要用到Import庫(kù)(通俗的講就是Windows提供的DLL文件中的函數(shù)列表,也就是告訴程序到哪里去調(diào)用API函數(shù)),這些都放在include 和lib目錄中。我們?cè)诰幾g時(shí)要指定以下的系統(tǒng)環(huán)境:

set include=\Masm32v5\Include
set lib=\Masmv5\lib
set path=\Masmv5\Bin

這樣編譯器就會(huì)到正確的路徑中去找 include 文件和 lib 文件。你可以自己在 autoexec.bat 文件中加上以上語(yǔ)句,為了產(chǎn)生Windows的PE格式的執(zhí)行文件,在編譯和連接中要指定相應(yīng)的參數(shù):

編譯: Ml /c /coff 文件名.asm
連接: Link /SUBSYSTEM:WINDOWS OBJ文件名.obj 資源文件名.res

為了不在每次編譯時(shí)都要打這么多的參數(shù),我們可以用 nmake 文件來(lái)代為執(zhí)行,nmake 是代碼維護(hù)程序,他會(huì)檢查 .asm .obj .exe .res 等文件的時(shí)間,如果你更新了源程序,他會(huì)自動(dòng)執(zhí)行編譯程序或連接程序產(chǎn)生相應(yīng)的文件。你可以在文件名為 makefile 的文件中指定使用的編譯器和連接程序以及相應(yīng)的參數(shù),下面是一個(gè) makefile 文件的例子:

NAME = Clock
OBJS = $(NAME).obj
RES = $(NAME).res
$(NAME).exe: $(OBJS) $(RES)
Link /DEBUG /SUBSYSTEM:WINDOWS $(OBJS) $(RES)
$(RES): $(NAME).rc
Rc $(NAME).rc
.asm.obj:
Ml /c /coff $(NAME).asm

文件告訴 nmake程序,程序名為 clock,產(chǎn)生 clock.exe 文件需要 clock.obj和 clock.res 文件,而產(chǎn)生 clock.res 文件需要 clock.rc 文件,產(chǎn)生 clock.obj 文件要用到 clock.asm 文件,至于是否需要執(zhí)行 ml, link 和 rc,程序會(huì)根據(jù)文件的時(shí)間自動(dòng)判斷。

Win32匯教程二
Win32匯編程序的結(jié)構(gòu)和語(yǔ)法

Win32A***程序的結(jié)構(gòu)和語(yǔ)法

  讓我們先來(lái)看看一個(gè)最簡(jiǎn)單的Win32匯編程序:


                .386
                .model flat, stdcall
                option casemap :none   ; case sensitive

include         windows.inc
include         kernel32.inc
includelib      kernel32.lib

                .data

szCaption               db      'Win32匯編例子',0
szText          db      'Win32匯編,Simple and powerful!',0

                .code

start:
                invoke  MessageBox,NULL,addr szText,addr szCaption,MB_OK
                invoke  ExitProcess,NULL

                end     start
這就是一個(gè)能執(zhí)行的最簡(jiǎn)單的Win32匯編程序,下面我簡(jiǎn)單地介紹一下各部分的作用:

.386

這條語(yǔ)句和Dos下匯編是一樣的,是告訴編譯器我們要用到80386的指令集,因?yàn)?2位匯編程序要用到32位的寄存器如eax,ebx等,所以這一句是必須的,當(dāng)然,你也可以用.486,.586等,當(dāng)用到特權(quán)指令時(shí),還可以用 .386p,.486p等等。

.model flat,stdcall

.model告訴編譯器程序的模式,編過(guò)Dos匯編的人可能知道在Dos程序的模式有tiny,small,...huge 等,它指定了程序內(nèi)存尋址模式,在huge等模式下,內(nèi)存尋址和子程序調(diào)用將用Far的格式,但在Win32匯編中,你只能使用一個(gè)模式即 flat 模式,因?yàn)閷?duì)Win32程序來(lái)說(shuō),內(nèi)存是連續(xù)的一個(gè)4GB的段,無(wú)所謂小或大的模式。而stdcall 告訴編譯器參數(shù)的傳遞方式,在調(diào)用子程序時(shí),參數(shù)是通過(guò)堆棧傳遞的,參數(shù)的傳遞方式有三種,stdcall,c 和 pascal,stdcall 指定了參數(shù)是從右到左壓入堆棧的,比如說(shuō)對(duì)一個(gè)Windows API 如 MessageBox,在手冊(cè)中是如此定義的:

int MessageBox(

    HWND hWnd,          // handle of owner window
    LPCTSTR lpText,             // address of text in message box
    LPCTSTR lpCaption,  // address of title of message box  
    UINT uType          // style of message box
   );
那么在匯編中我們就可以這樣調(diào)用它:


        push    uType
        push    lpCaption
        push    lpText
        push    hWnd
        call    MessageBox
大家要注意最右面的參數(shù)是最后一個(gè)進(jìn)堆棧的,當(dāng)然,我們不必這樣麻煩的調(diào)用一個(gè) API,因?yàn)镸asm中的一個(gè)宏語(yǔ)句不但幫助我們完成了所有的壓棧操作,還幫我們檢查參數(shù)的個(gè)數(shù)是否正確,那就是 invoke 語(yǔ)句,我們可以把上面的語(yǔ)句換成 invoke MessageBox,hWnd,lpText,lpCaption,uType 就行了。如本程序中代入實(shí)際參數(shù)就成了 invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK。

include 語(yǔ)句

include 語(yǔ)句包含了一些系統(tǒng)的定義和API函說(shuō)明,其中所有的Windows 數(shù)據(jù)結(jié)構(gòu)定義和常量定義包含在 windows.inc 中,而其他 API函數(shù)的說(shuō)明包含在 xxx.inc 中, 如查 Microsoft Win32 Programmer's Reference 知道 ExitProcess包含在kernel32.dll 中,那么我們就要在程序中包括 include kernel32.inc 和 includelib kernel32.lib語(yǔ)句,否則在編譯時(shí)會(huì)出現(xiàn) API 函數(shù)未定義的錯(cuò)誤。而 MessageBox 在 user32.dll 中,那么我們就要在程序中包括 include user32.inc 和 includelib user32.lib語(yǔ)句

.data 或 .data?

指明了接下來(lái)是數(shù)據(jù)段,.data 定義了預(yù)定義的變量,.data?定義了未初始化的變量,兩者的不同之處是 .data? 定義的變量并不占用 .exe 文件的大小,而是在程序執(zhí)行時(shí)動(dòng)態(tài)分配,所以開始是不指定初始值的數(shù)據(jù)可以放在 .data? 段中,如一個(gè)1K大小的緩沖區(qū),放在 .data?中,程序?qū)⒉粫?huì)增加一個(gè)字節(jié)。

.code

指明了接下來(lái)是代碼段,我們的所有代碼都放在這里。最后的一句 start 語(yǔ)句指定了程序開始執(zhí)行的語(yǔ)句。程序中的 ExitProcess 是一個(gè)標(biāo)準(zhǔn)的 Win32 API,對(duì)應(yīng) Dos匯編中的 int 20h 或 mov ah,4ch/int 21h,也就是程序退出。而 MessageBox 也是一個(gè)標(biāo)準(zhǔn)的 API,功能是在屏幕上顯示一個(gè)消息框,具體的參數(shù)上面已經(jīng)解釋過(guò)了還有要注意的是 invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK 語(yǔ)句中, MB_OK 和 NULL 已經(jīng)預(yù)定義在 Windows.inc 中。

Win32匯編教程三
一個(gè)簡(jiǎn)單的對(duì)話框 --- 兼談資源文件的使用

Windows 的資源文件

    不管在Dos下編程還是在Windows下編程,我們總是要用到除了可執(zhí)行文件外的很多其他數(shù)據(jù),如聲音數(shù)據(jù),圖形數(shù)據(jù),文本等等,在Dos下編程,我們可以自己定義這些文件的格式,但這樣一來(lái)就造成了很多資源共享的問(wèn)題,大家可能還記的Dos下的很多游戲,它們的圖形都是按自己的格式存放的,你無(wú)法用標(biāo)準(zhǔn)的看圖軟件來(lái)看。也無(wú)法把它另存為其他格式。雖然在Win32編程中,我們?nèi)匀豢梢赃@樣做,但Win32編程給了我們一個(gè)方案 ---- 就是格式統(tǒng)一的資源文件,把字符串、圖形、對(duì)話框包括上面的按鈕,文本等定義到一個(gè)資源文件中,就可以方便的在不同的文件中使用它,最重要的是,如果我們用自己的文件格式,使用時(shí)就要涉及到這些文件的讀寫操作,比較復(fù)雜,但使用資源文件時(shí),Windows提供了一系列的API來(lái)裝入資源。非常方便。現(xiàn)在,讓我們來(lái)看一個(gè)很簡(jiǎn)單的資源文件的源文件,它的擴(kuò)展名是 .rc,當(dāng)它用資源編譯器編譯以后產(chǎn)生 .res 文件就可以在 link的時(shí)候連入.exe 文件中:


#i nclude        <Resource.h>
#define         DLG_MAIN        1

DLG_MAIN        DIALOGEX 0, 0, 236, 185
STYLE           DS_MODALFRame | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SY***ENU
CAPTION         "對(duì)話框模板"
FONT            9, "宋體"
BEGIN
        DEFPUSHBUTTON   "退出",IDOK,177,163,50,14
        CONTROL         "",-1,"Static",SS_ETCHEDHORZ,7,155,222,1
END
現(xiàn)在我簡(jiǎn)單解釋一下 .rc文件的語(yǔ)法:

#i nclude <resource.h> -- resource.h文件包括資源文件的一些常量定義,如下面的 WS_POPUP,WS_VISIBLE 等窗口的風(fēng)格等等

#define DLG_MAIN 1 -- 類似于 .asm 文件的 equ 語(yǔ)句,和匯編源程序一樣,這些定義是為了程序的可讀性。

DLG_MAIN DIALOGEX 0,0,236,185

Windows的.rc文件可以定義 BITMAP(位圖),CURSOR(光標(biāo)),ICON(圖標(biāo)),ACCELERATORS(加速鍵),DIALOG(對(duì)話框),MENU(菜單),STRINGTABLE(字符串表),RCDATA(自定義資源)等8種資源,詳細(xì)的描述可以參考有關(guān)MFC的書籍,在Win32A***中的資源編譯器的語(yǔ)法中,一般格式是這些資源的定義方法是:

位圖定義: nameID BITMAP [load-mem] filename
光標(biāo)定義: nameID CURSOR [load-mem] filename
圖標(biāo)定義: nameID ICON [load-mem] filename
加速鍵定義:
acctablename ACCELERATORS [optional-statements]
BEGIN event, idvalue, [type] [options]
. . .
END

等等,具體的定義和參數(shù)可以參考 Masm32v5 中的 Rc.hlp 幫助文件。我們可以用資源編輯器來(lái)所見即所得地編輯資源,也可以在文本編輯器中用上面這些語(yǔ)句自己定義資源。

在程序中使用資源

    在程序中,要使用資源之前必須先裝如內(nèi)存,Windows定義了一系列的API來(lái)裝入資源,如 LoadMenu,LoadString,LoadBitmap 等等,如 LoadBitmap 的定義:
HBITMAP LoadBitmap(
HINSTANCE hInstance, // handle of application instance
LPCTSTR lpBitmapName // address of bitmap resource name
);
    這些Load函數(shù)的返回值是一個(gè)句柄,調(diào)用參數(shù)中一般至少為兩項(xiàng): hInstance 和 ResouceName,這個(gè) ResouceName(如BitmapName,MenuName)就是在資源文件中的 #define 指定的值,如果你用 #define MY_ICON 10/ MY_ICON ICON "Main.ico" 定義了一個(gè)圖標(biāo),那么在程序中要使用 Main.ico 圖標(biāo)就可以用 LoadIcon(hInstance,10) 來(lái)裝入已經(jīng)定義為10號(hào)的圖標(biāo)文件。另一個(gè)參數(shù) hInstance 是執(zhí)行文件的句柄,它對(duì)應(yīng)資源所在的文件名,你可以在程序開始執(zhí)行時(shí)用 invoke GetModuleHandle,NULL 獲得 hInstance。另外一些資源并不是顯式地裝入的,如對(duì)話框資源,它是在建立對(duì)話框的函數(shù)中由Windows自己裝入的,如下面例子中的 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0 ,是在屏幕上顯示一個(gè)資源文件中已經(jīng)定義好了的對(duì)話框,就并不存在 LoadDialogBox 之類的API來(lái)先裝入對(duì)話框。

Win32A*** - 顯示一個(gè)對(duì)話框

介紹了這么多相關(guān)的東西,現(xiàn)在讓我們來(lái)看看如何顯示一個(gè)對(duì)話框,源程序如下:


                .386
                .model flat, stdcall
                option casemap :none   ; case sensitive

include         windows.inc
include         user32.inc
include         kernel32.inc
include         comctl32.inc
include         comdlg32.inc

includelib      user32.lib
includelib      kernel32.lib
includelib      comctl32.lib
includelib      comdlg32.lib

DLG_MAIN        equ             1

                .data?

hInstance       dd      ?
szBuffer        db      256 dup (?)

_ProcDlgMain    PROTO   :DWORD,:DWORD,:DWORD,:DWORD

                .data

                .code

;********************************************************************
_ProcDlgMain    proc    uses ebx edi esi, \
                hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD

                mov     eax,wMsg
                .if     eax == WM_CLOSE
                        invoke  EndDialog,hWnd,NULL
                .elseif eax == WM_INITDIALOG
                .elseif eax == WM_COMMAND
                        mov     eax,wParam
                        .if     eax == IDOK
                                invoke  EndDialog,hWnd,NULL
                        .elseif eax == IDCANCEL
                                invoke  EndDialog,hWnd,NULL
                        .endif
                .else
                        mov     eax,FALSE
                        ret
                .endif            
                mov     eax,TRUE
                ret
                
_ProcDlgMain    endp
;********************************************************************
start:
                invoke  InitCommonControls
                invoke  GetModuleHandle,NULL
                mov     hInstance,eax
                invoke  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0
                invoke  ExitProcess,NULL

                end     start

看了前面幾篇文章以后,這兒的大部分語(yǔ)句應(yīng)該是很熟悉了,我來(lái)講解幾句新的語(yǔ)句:

_ProcDlgMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

PROTO 語(yǔ)句類似于C語(yǔ)言中的函數(shù)定義,在Win32匯編中,如果子程序的定義在引用以后,你就必須先定義,當(dāng)然,這個(gè)定義是針對(duì) invoke 語(yǔ)句和其他帶參數(shù)的調(diào)用的,如果你的子程序沒(méi)有參數(shù),你就可以用 call 指令去調(diào)用它而不是用宏指令 invoke,這時(shí)候你就不必聲明這個(gè)函數(shù)。

_ProcDlgMain proc uses ebx edi esi, \
hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD

這個(gè)定義 proc 的語(yǔ)句應(yīng)該是不陌生的,要重復(fù)講解一下的是 uses 和 下面的參數(shù),uses 下的寄存器表示要編譯器自動(dòng)插入保存及恢復(fù)這些寄存器的指令,\ 是在 Masm32 中接下一行的符號(hào),表示下一行是本行的繼續(xù)內(nèi)容,以避免一行中的內(nèi)容過(guò)長(zhǎng)。下面的 hWnd:DWORD 等語(yǔ)句定義了調(diào)用這個(gè)子程序的參數(shù),如果有以下定義 MyProc proc dwPara1:DWORD,dwPara2:DWORD,dwPara3:DWORD,然后你用 invoke MyProc 1,2,3 來(lái)調(diào)用它,那么,1,2,3 將分別被賦值給 dwPara1,dwPara2,dwPara3,你可以在子程序中使用這些傳遞過(guò)來(lái)的參數(shù)。如果參數(shù)的類型是雙字,那么:DWORD 可以省略。

.if/.else/.elseif/.endif

這些語(yǔ)句是宏指令,實(shí)際上不說(shuō)你也知道它們的意思,有了這些宏指令,我們就可以把匯編編得象C一樣結(jié)構(gòu)清晰,而不必老是看到 jmp 指令了,當(dāng)然,這只不過(guò)編譯器幫你做了這些事情而已,如果你去反匯編一下,你開始會(huì)看到一大堆 jmp 指令,.if 的格式如下
.if eax == 1 如果eax等于1
.if eax != 1 如果eax不等于1
.if eax != 1 && ebx != 2 如果eax不等于1且ebx不等于2
.if eax == 1 || ebx == 2 如果eax等于1或者ebx等于2
其他的宏指令還有 .while/.endw .break 等等,可以參考 Masm32V5 的幫助文件 Masm32.hlp

    最后要講到的就是 DialogBoxParam 這個(gè)API了,在Windows中,所有的窗口都要指定一個(gè)子程序,當(dāng)Windows檢測(cè)到鼠標(biāo)、定時(shí)器等和這個(gè)窗口有關(guān)的動(dòng)作時(shí),它回調(diào)用這個(gè)子程序,這就是Windows基于消息的體系的最基本的概念,換句話說(shuō),在Dos下,我們通過(guò)INT指令調(diào)用系統(tǒng),而在Windows 下,有很多時(shí)候是你指定子程序地址讓W(xué)indows來(lái)調(diào)用你。 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0中的 offset _ProcDlgMain 就指定了如果有消息發(fā)生,Windows就來(lái)執(zhí)行這個(gè)子程序,參數(shù)中的 DLG_MAIN 就是在資源文件中定義的對(duì)話框模板編號(hào)。 hInstance 是對(duì)話框所在的資源文件的句柄。
    另外,在_ProcDlgMain 子程序中,Windows傳給我們4個(gè)參數(shù)hWnd,wMsg,wParam,lParam,其中,hWnd是對(duì)話框的窗口句柄,wMsg表示現(xiàn)在發(fā)生的消息事件,如這個(gè)對(duì)話框初始化時(shí)Windows會(huì)以WM_INITDIALOG為消息調(diào)用,關(guān)閉時(shí)為WM_CLOSE,按下對(duì)話框上的按鈕時(shí)為WM_COMMAND等,wParam和lParam是附加的參數(shù),對(duì)應(yīng)不同的消息對(duì)應(yīng)不同定義,具體可以參考Win32 Programmer's reference。

Win32匯編教程四
編寫一個(gè)簡(jiǎn)單的窗口

有關(guān)窗口的基本知識(shí)

    窗口是屏幕上的矩形區(qū)域。一個(gè)窗口可以從鍵盤或者鼠標(biāo)接受用戶的輸入,并在其內(nèi)部顯示圖形輸出。一個(gè)應(yīng)用程序窗口通常包含程序的標(biāo)題條、菜單、邊框,滾動(dòng)條。其中,對(duì)話框也是一種窗口。不同的是,對(duì)話框表面通常包含幾個(gè)其它窗口,稱之為“子窗口”。這些子窗口的形式有壓入按鈕、單選按鈕、復(fù)選框、文本輸入?yún)^(qū)域、列表框和滾動(dòng)條等。 用戶將這些窗口看成屏幕上的對(duì)象,可以通過(guò)按下一個(gè)按鈕或者滾動(dòng)一個(gè)滾動(dòng)條與這些對(duì)象直接交互。
    窗口以“消息”的形式接收窗口的輸入,窗口也用消息與其它窗口通訊。比如在程序窗口的大小改變時(shí),字處理器會(huì)重新格式化其中的文本。窗口大小改變的細(xì)節(jié)是由操作系統(tǒng)處理的,但程序能夠響應(yīng)這個(gè)系統(tǒng)功能。當(dāng)用戶改變窗口的大小時(shí),Windows給程序發(fā)送一條消息指出新窗口的大小。然后,程序就可以調(diào)整窗口中的內(nèi)容,以響應(yīng)大小的變化。程序創(chuàng)建的每一個(gè)窗口都有相關(guān)的窗口過(guò)程。也就是給這個(gè)窗口指定一個(gè)子程序(窗口過(guò)程),Windows通過(guò)調(diào)用它來(lái)給窗口發(fā)送消息。窗口過(guò)程再根據(jù)此消息進(jìn)行處理,然后將控制返回給Windows。
    窗口在“窗口類”的基礎(chǔ)上創(chuàng)建的。Windows定義了確省的窗口過(guò)程,如果你對(duì)所有的消息都讓W(xué)indows自己處理,那么你就能得到一個(gè)標(biāo)準(zhǔn)的窗口,同樣,你也可以選擇處理自己感興趣的消息,這樣,相當(dāng)于產(chǎn)生了不同的子類,也就形成了不同的應(yīng)用程序。同樣,子窗口也是基于同一個(gè)窗口類,并且使用同一個(gè)窗口過(guò)程。例如,所有Windows 程序中的所有按鈕都基于同一窗口類。這個(gè)窗口類有一個(gè)處理所有按鈕消息的窗口過(guò)程,但是,如果你按自己的設(shè)想設(shè)計(jì)一個(gè)按鈕,如想把按鈕的表面換成位圖,你就可以自己處理按鈕窗口的 WM_PAINT 消息,當(dāng) Windows 需要畫按鈕表面的時(shí)候,你就可以隨自己的意思去畫。
    Windows程序開始執(zhí)行后,Windows為該程序創(chuàng)建一個(gè)“消息隊(duì)列”。這個(gè)消息隊(duì)列用來(lái)存放該程序可能創(chuàng)建的各種不同窗口的消息。程序中有一段代碼,叫做“消息循環(huán)”, 它用來(lái)從隊(duì)列中取出消息,并且將它們發(fā)送給相應(yīng)的窗口過(guò)程。在沒(méi)有消息發(fā)生的時(shí)候,你的程序?qū)嶋H上就在消息循環(huán)中轉(zhuǎn)圈子。
    創(chuàng)建一個(gè)窗口的過(guò)程如下:

取得程序的實(shí)例句柄(hInstance)
注冊(cè)窗口類,實(shí)際上就是為你的窗口指定處理消息的過(guò)程,定義光標(biāo),窗口風(fēng)格,顏色等參數(shù)
創(chuàng)建窗口
顯示窗口
然后進(jìn)入消息循環(huán),也就是不停地檢測(cè)有無(wú)消息,并把它發(fā)送給窗口進(jìn)程去處理。
創(chuàng)建一個(gè)窗口的代碼在不同的程序中實(shí)際上是幾乎一模一樣的,所以你編一個(gè)新的程序時(shí)可以把這一段拷來(lái)拷去,稍微修改一下就行,程序的大部分代碼實(shí)際上是用在窗口過(guò)程中,因?yàn)檫@才是不同程序的不同之處。窗口過(guò)程的編程要點(diǎn)如下:

從Windows傳給窗口過(guò)程的參數(shù) uMsg 得到消息類型,并轉(zhuǎn)到不同的分枝去處理。
對(duì)自己已經(jīng)處理的消息,返回 Windows 時(shí)必須在eax 中返回0。
自己不處理的消息,必須調(diào)用 DefWindowProc 處理,并把返回值傳回Windows,否則,Windows會(huì)無(wú)法顯示。
uMsg 參數(shù)中指定的消息有280多種,實(shí)際上我們需要處理的只有重要的幾種,如Windows在創(chuàng)建的時(shí)候會(huì)發(fā)送 WM_CREATE 消息,我們就可以在這時(shí)候初始化,分配內(nèi)存等等,而退出時(shí)會(huì)發(fā)送 WM_CLOSE,我們就可以進(jìn)行釋放內(nèi)存等清除工作,當(dāng)Windows上的菜單或按鈕被按下時(shí)發(fā)送 WM_COMMAND 消息等等,具體可以參考 Win32 Programmer's Reference。下面,我們來(lái)看一個(gè)創(chuàng)建窗口的簡(jiǎn)單程序。

一個(gè)創(chuàng)建窗口的程序


                .386
                .model flat, stdcall
                option casemap :none   ; case sensitive

include         windows.inc
include         user32.inc
include         kernel32.inc
include         comctl32.inc
include         comdlg32.inc
include         gdi32.inc

includelib      user32.lib
includelib      kernel32.lib
includelib      comctl32.lib
includelib      comdlg32.lib
includelib      gdi32.lib

IDI_MAIN        equ             1000            ;icon

IDM_MAIN        equ             4000            ;menu
IDM_EXIT        equ             4001

                .data?

hInstance       dd              ?
hWinMain        dd              ?
hMenu           dd              ?
szBuffer        db      256 dup (?)

                .data

szClassName     db      "Windows Template",0
szCaptionMain   db      '窗口模板',0

                .code

start:
                call    _WinMain
                invoke  ExitProcess,NULL

_WinMain        proc
                local   @stWcMain:WNDCLASSEX
                local   @stMsg:MSG

                invoke  InitCommonControls
                invoke  GetModuleHandle,NULL
                mov     hInstance,eax
                invoke  LoadIcon,hInstance,IDI_MAIN
                mov     hIcon,eax
                invoke  LoadMenu,hInstance,IDM_MAIN
                mov     hMenu,eax
;*************** 注冊(cè)窗口類 *****************************************
                invoke  LoadCursor,0,IDC_ARROW
                mov     @stWcMain.hCursor,eax
                mov     @stWcMain.cbSize,sizeof WNDCLASSEX
                mov     @stWcMain.hIconSm,0
                mov     @stWcMain.style,CS_HREDRAW or CS_VREDRAW
                mov     @stWcMain.lpfnWndProc,offset WndMainProc
                mov     @stWcMain.cbClsExtra,0
                mov     @stWcMain.cbWndExtra,0
                mov     eax,hInstance
                mov     @stWcMain.hInstance,eax
                mov     @stWcMain.hIcon,0
                mov     @stWcMain.hbrBackground,COLOR_WINDOW + 1
                mov     @stWcMain.lpszClassName,offset szClassName
                mov     @stWcMain.lpszMenuName,0
                invoke  RegisterClassEx,addr @stWcMain
;*************** 建立輸出窗口 ***************************************
                invoke  CreateWindowEx,WS_EX_CLIENTEDGE,\
                        offset szClassName,offset szCaptionMain,\
                        WS_OVERLAPPEDWINDOW OR WS_VSCROLL OR WS_HSCROLL,\
                        0,0,550,300,\
                        NULL,hMenu,hInstance,NULL

                invoke  ShowWindow,hWinMain,SW_SHOWNORMAL
                invoke  UpdateWindow,hWinMain
;*************** 消息循環(huán) *******************************************
                .while  TRUE
                        invoke  GetMessage,addr @stMsg,NULL,0,0
                        .break  .if eax == 0
                        invoke  TranslateMessage,addr @stMsg
                        invoke  DispatchMessage,addr @stMsg
                .endw
                ret

_WinMain        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
WndMainProc     proc    uses ebx edi esi, \
                hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

                mov     eax,uMsg
                .if     eax ==  WM_CREATE
                        mov     eax,hWnd
                        mov     hWinMain,eax
                        call    _Init
;********************************************************************
                .elseif eax ==  WM_COMMAND
                   .if  lParam == 0
                        mov     eax,wParam
                        .if     ax == IDM_EXIT
                                call    _Quit
                        .endif
                   .endif
;********************************************************************
                .elseif eax ==  WM_CLOSE
                        call    _Quit
;********************************************************************
                .else
                        invoke  DefWindowProc,hWnd,uMsg,wParam,lParam
                        ret
                .endif
                xor     eax,eax
                ret

WndMainProc     endp

_Init           proc

                invoke  SendMessage,hWinMain,WM_SETICON,ICON_***ALL,hIcon

                ret

_Init           endp
;********************************************************************
_Quit           proc

                invoke  DestroyWindow,hWinMain
                invoke  PostQuitMessage,NULL
                ret

_Quit           endp
;********************************************************************
                end     start
窗口程序的分析

    讓我們來(lái)簡(jiǎn)單分析一下這個(gè)程序,首先程序調(diào)用 _WinMain,在_WinMain 中定義了兩個(gè)局部變量 @stMsg 和 @stWinMain,數(shù)據(jù)類型分別是 MSG 和 WNDCLASSEX結(jié)構(gòu),在參考手冊(cè)中,可以看到WNDCLASSEX定義了一個(gè)窗口的所有參數(shù),如使用的菜單、光標(biāo)、顏色、窗口過(guò)程等,接下來(lái)的一大堆 mov 指令實(shí)際上就是在填寫這個(gè)數(shù)據(jù)結(jié)構(gòu),填寫完成后,最重要的兩句是 mov @stWcMain.lpfnWndProc,offset WndMainProc 定義了處理消息的窗口過(guò)程, mov @stWcMain.lpszClassName,offset szClassName 定義了你要?jiǎng)?chuàng)建的類的名稱,然后就是使用 RegisterClassEx 注冊(cè)這個(gè)窗口類,注意,這時(shí)候窗口并沒(méi)有創(chuàng)建,你只不過(guò)是定義好了一個(gè)子類,接下去你要用你定義的類去創(chuàng)建一個(gè)窗口。也就是使用 CreateWindowEx 函數(shù)去創(chuàng)建它。在手冊(cè)中,CreateWindowEx 是這樣定義的:

HWND CreateWindowEx(
DWORD dwExStyle, // extended window style
LPCTSTR lpClassName, // pointer to registered class name
LPCTSTR lpWindowName, // pointer to window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu, or child-window identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // pointer to window-creation data );

其中的參數(shù) dwExStyle 是窗口的風(fēng)格,lpClassName 就是我們自己定義的類的名字。如果大家要?jiǎng)?chuàng)建一個(gè)已經(jīng)定義好的類,如 RichEdit 類等等,只要把 lpClassName 指向 "RichEdit32" 字符串就行了,當(dāng)然這時(shí)就不用 RegisterClass 以及編寫自己的窗口過(guò)程了。執(zhí)行 CreateWindowEx 后,得到一個(gè)返回值就是窗口句柄,這個(gè)值在以后是要經(jīng)常用到了,所以要先保存下來(lái)。這時(shí)窗口并沒(méi)有在屏幕上顯示出來(lái),而是處于隱藏狀態(tài),我們要用 ShowWindow 來(lái)顯示出窗口并用UpdateWindow 來(lái)繪窗口的內(nèi)容。
    窗口顯示出來(lái)后,程序就進(jìn)入一個(gè)循環(huán)----消息循環(huán),前面我已經(jīng)說(shuō)過(guò),作用是不停地接收 Windows 消息并發(fā)送給窗口過(guò)程去處理。GetMessage 從消息隊(duì)列中取出一條消息,如果取得的消息不是 WM_QUIT,那么 GetMessage 返回一個(gè)非零值,否則返回零,這時(shí)候循環(huán)結(jié)束,程序執(zhí)行 ExitProcess退回操作系統(tǒng)。TranslateMessage 將消息進(jìn)行一些鍵盤轉(zhuǎn)換,用于處理一些快捷鍵,DispatchMessage 將處理后的消息發(fā)回 Windows,由Windows調(diào)用窗口進(jìn)程進(jìn)行處理,當(dāng)窗口進(jìn)程處理完返回后,程序才從 DispatchMessage 返回,從而開始下一個(gè) GetMessage 調(diào)用。這些函的參數(shù)可以參考手冊(cè)。

窗口過(guò)程的分析

    窗口過(guò)程有四個(gè)參數(shù),hWnd 是本窗口的句柄,和創(chuàng)建窗口時(shí)返回的值相同,uMsg 是本次調(diào)用的消息類型,wParam 和lParam是消息的參數(shù),其含義和數(shù)值根據(jù)消息的不同而不同。在本程序中,我們處理 WM_CREATE,WM_COMMAND 和 WM_QUIT 消息,然后返回0,對(duì)不處理的消息,使用 invoke DefWindowProc,hWnd,uMsg,wParam,lParam 來(lái)處理并直接用 ret 將返回值傳回 Windows。在響應(yīng) WM_CLOSE 消息時(shí),我們用 DestroyWindow 清除窗口并用PostQuitMessage 產(chǎn)生一條 WM_QUIT 消息,從而使程序在 消息循環(huán)調(diào)用GetMessage 時(shí)返回0,以結(jié)束消息循環(huán)并結(jié)束程序。
posted on 2006-10-09 11:17 思勤無(wú)邪 閱讀(3641) 評(píng)論(1)  編輯 收藏 引用 所屬分類: 其他與技術(shù)相關(guān)

Feedback

# re: Win32匯編基礎(chǔ)教程 2012-08-27 15:50 ..
牛  回復(fù)  更多評(píng)論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            影音欧美亚洲| 午夜精品久久一牛影视| 欧美日韩国产一中文字不卡 | 亚洲一区二区三| 亚洲综合欧美日韩| 久久成人精品| 欧美成人乱码一区二区三区| 亚洲国产欧美一区二区三区同亚洲| 久久九九热免费视频| 蜜桃av一区| 亚洲精品在线一区二区| 亚洲一区欧美一区| 久久婷婷国产综合精品青草| 欧美jizzhd精品欧美巨大免费| 欧美精品v日韩精品v韩国精品v| 欧美日韩一区二区国产| 国产一区二区视频在线观看| 最新国产の精品合集bt伙计| 亚洲一区精品在线| 美日韩精品视频免费看| 亚洲欧洲日韩综合二区| 亚洲综合999| 欧美国产1区2区| 国产伦精品一区二区三区| 亚洲国产精品999| 性色av香蕉一区二区| 欧美成人精品1314www| 99伊人成综合| 蜜臀av一级做a爰片久久| 国产欧美精品日韩| 亚洲天堂偷拍| 亚洲国产精品va在线看黑人动漫| 午夜精品久久久久久99热| 欧美激情一区二区三区在线| 国产亚洲欧美在线| 亚洲综合清纯丝袜自拍| 亚洲日韩成人| 美日韩丰满少妇在线观看| 国产午夜精品理论片a级探花| 99re视频这里只有精品| 亚洲欧美久久久| 欧美日韩少妇| 日韩视频在线播放| 日韩视频在线免费| 久久久久国色av免费看影院| 欧美三级午夜理伦三级中视频| 国产亚洲精久久久久久| 亚洲深夜福利视频| 亚洲动漫精品| 久久夜色撩人精品| 一区精品在线| 久久久在线视频| 亚洲欧美日韩国产一区二区三区| 免费毛片一区二区三区久久久| 亚洲视频中文字幕| 欧美激情一区二区三区全黄| 久久精品国产精品亚洲精品| 国产女主播一区二区| 欧美影院成人| 欧美一区二区高清| 国产亚洲人成a一在线v站 | 欧美激情1区| 99国产精品久久久久久久| 亚洲激情在线视频| 欧美久久九九| 亚洲一区二区三区成人在线视频精品| 亚洲精品久久久久久下一站| 欧美女同视频| 亚洲在线免费视频| 亚洲在线播放| 国产一区在线免费观看| 久久亚洲午夜电影| 免费欧美在线视频| 在线午夜精品自拍| 亚洲一区在线观看视频 | 国产精品成人一区二区| 欧美一级久久久久久久大片| 亚欧成人精品| …久久精品99久久香蕉国产| 亚洲国产精品v| 欧美亚州一区二区三区| 欧美一区二区三区的| 久久久久成人精品免费播放动漫| 亚洲国产日韩欧美在线动漫| 日韩视频一区二区| 国产色婷婷国产综合在线理论片a| 久色婷婷小香蕉久久| 欧美a级一区二区| 亚洲欧美精品suv| 久久久久五月天| 99热精品在线| 香蕉久久久久久久av网站| 亚洲电影毛片| 亚洲亚洲精品三区日韩精品在线视频 | 久久精品中文字幕免费mv| 99ri日韩精品视频| 性伦欧美刺激片在线观看| 亚洲精品在线观看免费| 亚洲综合第一| 亚洲美女色禁图| 久久福利影视| 亚洲欧美网站| 欧美激情精品久久久久久黑人| 午夜国产欧美理论在线播放| 免费在线看一区| 久久成人资源| 国产精品都在这里| 亚洲黄色片网站| 国产精品私房写真福利视频| 亚洲第一精品福利| 麻豆久久久9性大片| 国产精品v日韩精品| 久久国产精品亚洲va麻豆| 欧美日韩不卡一区| 美女久久一区| 国产资源精品在线观看| 国产精品99久久久久久www| 亚洲国产二区| 香蕉尹人综合在线观看| 亚洲一区二区三区三| 欧美高清成人| 欧美成年人网| 怡红院精品视频| 欧美一区二区三区在| 亚洲亚洲精品在线观看| 欧美日韩喷水| 99国产精品99久久久久久| 亚洲美女免费视频| 欧美国产精品人人做人人爱| 久久综合伊人77777蜜臀| 国产美女诱惑一区二区| 亚洲天堂av综合网| 亚洲自拍电影| 欧美日韩午夜在线| 亚洲欧洲偷拍精品| 亚洲日本免费| 欧美日本高清| 亚洲精品国产视频| 亚洲美女av电影| 欧美激情视频一区二区三区不卡| 蜜臀av在线播放一区二区三区| 亚洲第一精品夜夜躁人人爽| 久久久久久有精品国产| 欧美xart系列高清| 亚洲精选中文字幕| 欧美日韩亚洲一区二| 中国成人黄色视屏| 久久精品亚洲一区二区三区浴池| 国产视频自拍一区| 久久综合五月| 亚洲毛片在线观看| 午夜精品影院| 伊人久久大香线蕉综合热线| 免费在线观看成人av| 亚洲经典自拍| 午夜欧美精品| 亚洲国产成人av| 欧美三区视频| 久久九九热免费视频| 91久久线看在观草草青青| 亚洲一区二区免费在线| 国产亚洲精品7777| 欧美国产第一页| 亚洲欧美日本国产有色| 免费观看国产成人| 亚洲视频综合在线| 极品少妇一区二区| 欧美日韩另类国产亚洲欧美一级| 性xx色xx综合久久久xx| 亚洲精品国产精品乱码不99按摩| 亚洲欧美自拍偷拍| 最新高清无码专区| 国产视频精品xxxx| 欧美伦理91| 久久综合色影院| 羞羞答答国产精品www一本 | 噜噜噜躁狠狠躁狠狠精品视频| 影音先锋日韩精品| 欧美电影免费观看高清完整版| 国产欧美日韩伦理| 欧美wwwwww| 久久久7777| 亚洲一区二区三区激情| 欧美国产成人在线| 欧美一区二区三区日韩视频| 亚洲乱码久久| 国产一区二区三区四区在线观看 | 欧美日韩直播| 免费在线观看一区二区| 欧美一区午夜视频在线观看| 一区二区欧美日韩视频| 亚洲丶国产丶欧美一区二区三区| 久久超碰97中文字幕| avtt综合网| 亚洲精品女人| 亚洲高清久久久| 伊人久久婷婷色综合98网| 国产日韩精品一区观看| 国产精品蜜臀在线观看| 欧美三级日本三级少妇99|