Win32彙編教程三 一個簡單的對話方塊 --- 兼談資原始檔的使用 (轉)

worldblog發表於2007-12-02
Win32彙編教程三 一個簡單的對話方塊 --- 兼談資原始檔的使用 (轉)[@more@]




--------------------------------------------------------------------------------

的資源

不管在Dos下還是在Windows下程式設計,我們總是要用到除了可檔案外的很多其他資料,如資料,圖形資料,文字等等,在Dos下程式設計,我們可以自己定義這些檔案的格式,但這樣一來就造成了很多資源共享的問題,大家可能還記的Dos下的很多遊戲,它們的圖形都是按自己的格式存放的,你無法用標準的看圖來看。也無法把它另存為其他格式。雖然在程式設計中,我們仍然可以這樣做,但Win32程式設計給了我們一個方案 ---- 就是格式統一的資原始檔,把字串、圖形、對話方塊包括上面的按鈕,文字等定義到一個資原始檔中,就可以方便的在不同的檔案中使用它,最重要的是,如果我們用自己的檔案格式,使用時就要涉及到這些檔案的讀寫操作,比較複雜,但使用資原始檔時,Windows提供了一系列的來裝入資源。非常方便。現在,讓我們來看一個很簡單的資原始檔的原始檔,它的副檔名是 .rc,當它用資源編譯以後產生 .res 檔案就可以在 link的時候連入.exe 檔案中:


#include
#define DLG_MAIN 1

DLG_MAIN DIALOGEX 0, 0, 236, 185
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "對話方塊模板"
FONT 9, "宋體"
BEGIN
DEFPUSHBUTTON "退出",IDOK,177,163,50,14
CONTROL "",-1,"Static",SS_ETCHEDHORZ,7,155,222,1
END

現在我簡單解釋一下 .rc檔案的語法:

#include -- resource.h檔案包括資原始檔的一些常量定義,如下面的 WS_POPUP,WS_VISIBLE 等視窗的風格等等

#define DLG_MAIN 1 -- 類似於 .asm 檔案的 equ 語句,和源一樣,這些定義是為了程式的可讀性。

DLG_MAIN DIALOGEX 0,0,236,185

Windows的.rc檔案可以定義 BITMAP(點陣圖),CURSOR(游標),ICON(圖示),ACCELERATORS(加速鍵),DIALOG(對話方塊),MENU(選單),STRINGTABLE(字串表),RCDATA(自定義資源)等8種資源,詳細的描述可以參考有關MFC的書籍,在Win32ASM中的資源編譯器的語法中,一般格式是這些資源的定義方法是:

點陣圖定義: nameID BITMAP [load-mem] filename
游標定義: nameID CURSOR [load-mem] filename
圖示定義: nameID ICON [load-mem] filename
加速鍵定義:
acctablename ACCELERATORS [optional-statements]
BEGIN event, idvalue, [type] [options]
. . .
END

等等,具體的定義和引數可以參考 Masm32v5 中的 Rc.hlp 幫助檔案。(可以在程式設計工具中),我們可以用資源編輯器來所見即所得地編輯資源,也可以在文字編輯器中用上面這些語句自己定義資源。

在程式中使用資源

在程式中,要使用資源之前必須先裝如,Windows定義了一系列的API來裝入資源,如 LoadMenu,LoadString,Loaitmap 等等,如 LoadBitmap 的定義:
HBITMAP LoadBitmap(
HINSTANCE hInstance, // handle of application instance
LPCTSTR lpBitmapName // address of bitmap resource name
);
這些Load的返回值是一個控制程式碼,引數中一般至少為兩項: hInstance 和 ResouceName,這個 ResouceName(如BitmapName,MenuName)就是在資原始檔中的 #define 指定的值,如果你用 #define MY_ICON 10/ MY_ICON ICON "Main.ico" 定義了一個圖示,那麼在程式中要使用 Main.ico 圖示就可以用 LoadIcon(hInstance,10) 來裝入已經定義為10號的圖示檔案。另一個引數 hInstance 是執行檔案的控制程式碼,它對應資源所在的檔名,你可以在程式開始執行時用 invoke GetModuleHandle,NULL 獲得 hInstance。另外一些資源並不是顯式地裝入的,如對話方塊資源,它是在建立對話方塊的函式中由Windows自己裝入的,如下面例子中的 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0 ,是在螢幕上顯示一個資原始檔中已經定義好了的對話方塊,就並不存在 LoadDialogBox 之類的API來先裝入對話方塊。

Win32ASM - 顯示一個對話方塊

介紹了這麼多相關的東西,現在讓我們來看看如何顯示一個對話方塊,源程式如下:


.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 :D,: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


看了前面幾篇文章以後,這兒的大部分語句應該是很熟悉了,我來講解幾句新的語句:

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

PROTO 語句類似於C語言中的函式定義,在Win32彙編中,如果子程式的定義在引用以後,你就必須先定義,當然,這個定義是針對 invoke 語句和其他帶引數的呼叫的,如果你的子程式沒有引數,你就可以用 call 指令去呼叫它而不是用宏指令 invoke,這時候你就不必宣告這個函式。

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

這個定義 proc 的語句應該是不陌生的,要重複講解一下的是 uses 和 下面的引數,uses 下的暫存器表示要編譯器自動插入儲存及恢復這些暫存器的指令, 是在 Masm32 中接下一行的符號,表示下一行是本行的繼續內容,以避免一行中的內容過長。下面的 hWnd:DWORD 等語句定義了呼叫這個子程式的引數,如果有以下定義 MyProc proc dwPara1:DWORD,dwPara2:DWORD,dwPara3:DWORD,然後你用 invoke MyProc 1,2,3 來呼叫它,那麼,1,2,3 將分別被賦值給 dwPara1,dwPara2,dwPara3,你可以在子程式中使用這些傳遞過來的引數。如果引數的型別是雙字,那麼:DWORD 可以省略。

.if/.else/.elseif/.endif

這些語句是宏指令,實際上不說你也知道它們的意思,有了這些宏指令,我們就可以把彙編編得象C一樣結構清晰,而不必老是看到 jmp 指令了,當然,這只不過編譯器幫你做了這些事情而已,如果你去反彙編一下,你開始會看到一大堆 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 這個API了,在Windows中,所有的視窗都要指定一個子程式,當Windows檢測到滑鼠、定時器等和這個視窗有關的動作時,它回撥用這個子程式,這就是Windows基於訊息的體系的最基本的概念,換句話說,在Dos下,我們透過INT指令呼叫,而在Windows 下,有很多時候是你指定子程式地址讓Windows來呼叫你。 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0中的 offset _ProcDlgMain 就指定了如果有訊息發生,Windows就來執行這個子程式,引數中的 DLG_MAIN 就是在資原始檔中定義的對話方塊模板編號。 hInstance 是對話方塊所在的資原始檔的控制程式碼。
另外,在_ProcDlgMain 子程式中,Windows傳給我們4個引數hWnd,wMsg,wParam,lParam,其中,hWnd是對話方塊的視窗控制程式碼,wMsg表示現在發生的訊息事件,如這個對話方塊初始化時Windows會以WM_INITDIALOG為訊息呼叫,關閉時為WM_CLOSE,按下對話方塊上的按鈕時為WM_COMMAND等,wParam和lParam是附加的引數,對應不同的訊息對應不同定義,具體可以參考Win32 Programmer's reference。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987439/,如需轉載,請註明出處,否則將追究法律責任。

相關文章