進一步學習對話方塊(轉)

heying1229發表於2007-07-28
進一步學習對話方塊:

  本課中我們將進一步學習對話方塊。特別地我們將要探討如何把對話方塊當成輸入裝置。如果您學習了上一課,那就會發現本課的例子只有少量的改動,就是把我們的對話方塊視窗附屬到主視窗上。另外,我們還要學習通用對話方塊的用法。
理論:
把對話方塊當成一個輸入裝置來用確實是非常地簡單,建立完主視窗後,您只要呼叫函式 CreatedialogParam 或 DialogBoxParam 就可以了,前一個函式只要在對話方塊的過程處理函式中處理相關的訊息就可以,而後者你必須在訊息迴圈段中插入函式 IsDialogMessage 的呼叫讓它來處理鍵盤的按鍵邏輯。因為這兩個程式段相對來說比較容易,我們就不詳解。您可以下載並仔細研究。
下面我們來討論通用對話方塊。WINDOWS已經為您準備好了預定義的對話方塊類,您可以拿來就用,這些通用對話方塊提供給使用者以統一的介面。它們包括:開啟檔案、列印、選擇顏色、字型和搜尋等。您應該儘可能地用它們。處理這些對話方塊的程式碼在comdlg32.dll中,為了在您的應用程式中使用它們,就必須在連結階段連結庫檔案 comdlg32.lib。然後呼叫其中的相關函式即可。對於開啟檔案通用對話方塊,該函式名為 GetOpenFileName,"儲存為..."對話方塊為 GetSaveFileName,列印通用對話方塊是 PrintDlg, 等等。每一個這樣的函式都接收一個指向一個結構體的指標的引數,您可以參考WIN32 API手冊得到詳細的資料,本課中我將講解建立和使用開啟檔案對話方塊。
下面是開啟對話方塊函式 GetOpenFileName 的原型:


GetOpenFileName proto lpofn:DWORD
您可以看到,該函式只有一個引數,即指向結構體OPENFILENAME的指標。當使用者選擇了一個檔案並開啟,該函式返回TRUE,否則返回FALSE。接下來我們看看結構體OPENFILENAME的定義:


OPENFILENAME STRUCT
lStructSize DWORD ?
hwndOwner HWND ?
hInstance HINSTANCE ?
lpstrFilter LPCSTR ?
lpstrCustomFilter LPSTR ?
nMaxCustFilter DWORD ?
nFilterIndex DWORD ?
lpstrFile LPSTR ?
nMaxFile DWORD ?
lpstrFileTitle LPSTR ?
nMaxFileTitle DWORD ?
lpstrInitialDir LPCSTR ?
lpstrTitle LPCSTR ?
Flags DWORD ?
nFileOffset WORD ?
nFileExtension WORD ?
lpstrDefExt LPCSTR ?
lCustData LPARAM ?
lpfnHook DWORD ?
lpTemplateName LPCSTR ?
OPENFILENAME ENDS
好,我們再來看看該結構體中常用的成員的意義:

lStructSize 結構體OPENFILENAME的大小。
hwndOwner 擁有開啟對話方塊的視窗的控制程式碼。
hInstance 擁有該開啟檔案對話方塊的應用程式的例項控制程式碼 。
lpstrFilter 以NULL結尾的一個或多個萬用字元。萬用字元是成對出現的,前一部分是描述部分,後一部分則是萬用字元的格式,譬如:
FilterString db "All Files (*.*)",0, "*.*",0
db "Text Files (*.txt)",0,"*.txt",0,0
注意:只有每一對中的第二部分是WINDOWS用來過濾所需選擇的檔案的,另外您必須在該部分後放置一個0,以示字串的結束。

nFilterIndex 用來指定開啟檔案對話方塊第一次開啟時所用的過濾模式串,該索引是從1開始算的,即第一個萬用字元模式的索引是1,第二個是2,譬如上面的例子中,若指定該值為2,則預設顯示的模式串就是"*.txt"。
lpstrFile 需要開啟的檔案的名稱的地址,該名稱將會出現在開啟檔案對話方塊的編輯控制元件中,該緩衝區不能超過260個字元長,當使用者開啟檔案後,該緩衝區中包含該檔案的全路徑名,您可以從該緩衝區中抽取您所需要的路徑或檔名等資訊。
nMaxFile lpstrFile的大小。
lpstrTitle 指向對話方塊標題的字串。
Flags 該標誌決定決定了對話方塊的風格和特點。
nFileOffset 在使用者開啟了一個檔案後該值是全路徑名稱中指向檔名第一個字元的索引。譬如:若全路徑名為"c:windowssystemlz32.dll", 則該值為18。
nFileExtension 在使用者開啟了一個檔案後該值是全路徑名稱中指向個副檔名第一個字元的索引。


例子:
下例中,我們演示了當使用者選擇"File->Open"時,將彈出一個開啟檔案對話方塊,當使用者選擇了某個檔案開啟時,會彈出一個對話方塊,告知要開啟的檔案的全路徑名,檔名和副檔名。
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
include masm32includecomdlg32.inc
includelib masm32libuser32.lib
includelib masm32libkernel32.lib
includelib masm32libcomdlg32.lib

.const
IDM_OPEN equ 1
IDM_EXIT equ 2
MAXSIZE equ 260
OUTPUTSIZE equ 512

.data
ClassName db "SimpleWinClass",0
AppName db "Our Main Window",0
MenuName db "FirstMenu",0
ofn OPENFILENAME <>
FilterString db "All Files",0,"*.*",0
db "Text Files",0,"*.txt",0,0
buffer db MAXSIZE dup(0)
OurTitle db "-=Our First Open File Dialog Box=-: Choose the file to open",0
FullPathName db "The Full Filename with Path is: ",0
FullName db "The Filename is: ",0
ExtensionName db "The Extension is: ",0
OutputString db OUTPUTSIZE dup(0)
CrLf db 0Dh,0Ah,0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
CW_USEDEFAULT,300,200,NULL,NULL,
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.if ax==IDM_OPEN
mov ofn.lStructSize,SIZEOF ofn
push hWnd
pop ofn.hwndOwner
push hInstance
pop ofn.hInstance
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile,MAXSIZE
mov ofn.Flags, OFN_FILEMUSTEXIST or
OFN_PATHMUSTEXIST or OFN_LONGNAMES or
OFN_EXPLORER or OFN_HIDEREADONLY
mov ofn.lpstrTitle, OFFSET OurTitle
invoke GetOpenFileName, ADDR ofn
.if eax==TRUE
invoke lstrcat,offset OutputString,OFFSET FullPathName
invoke lstrcat,offset OutputString,ofn.lpstrFile
invoke lstrcat,offset OutputString,offset CrLf
invoke lstrcat,offset OutputString,offset FullName
mov eax,ofn.lpstrFile
push ebx
xor ebx,ebx
mov bx,ofn.nFileOffset
add eax,ebx
pop ebx
invoke lstrcat,offset OutputString,eax
invoke lstrcat,offset OutputString,offset CrLf
invoke lstrcat,offset OutputString,offset ExtensionName
mov eax,ofn.lpstrFile
push ebx
xor ebx,ebx
mov bx,ofn.nFileExtension
add eax,ebx
pop ebx
invoke lstrcat,offset OutputString,eax
invoke MessageBox,hWnd,OFFSET OutputString,ADDR AppName,MB_OK
invoke RtlZeroMemory,offset OutputString,OUTPUTSIZE
.endif
.else
invoke DestroyWindow, hWnd
.endif
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start

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

分析:
mov ofn.lStructSize,SIZEOF ofn
push hWnd
pop ofn.hwndOwner
push hInstance
pop ofn.hInstance
我們在此填充結構體OPENFILENAME變數ofn的有關成員。

mov ofn.lpstrFilter, OFFSET FilterString

這裡FilterString 是檔案過濾模式的字串地址,我們指定的過濾模式字串如下:

FilterString db "All Files",0,"*.*",0
db "Text Files",0,"*.txt",0,0
注意:所有的模式串都是配對的,前一個是描述,後一個才是真正的模式,次處"*.*"和"*.txt"是WIONDOWS用來尋找匹配的欲開啟的檔案的。我們當能可以指定任何模式,但是不要忘記在結尾處加0以代表字串已結束,否則您的對話方塊在操作時可能不穩定。
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile,MAXSIZE

這裡是把緩衝區的地址放到結構體中,同時必須設定大小。以後我們可以隨意編輯在該緩衝區中返回的資訊。

mov ofn.Flags, OFN_FILEMUSTEXIST or
OFN_PATHMUSTEXIST or OFN_LONGNAMES or
OFN_EXPLORER or OFN_HIDEREADONLY

Flags 中放入的是對話方塊的風格和特性值。
其中OFN_FILEMUSTEXIST和 OFN_PATHMUSTEXIST要求使用者在開啟對話方塊的編輯控制元件中輸入的檔名或路徑名必須存在。
OFN_LONGNAMES 告訴對話方塊顯示長檔名。
OFN_EXPLORER 告訴WINDOWS對話方塊的外觀必須類似資源管理器。
OFN_HIDEREADONLY 指定不要顯示只讀檔案(既使它的副檔名符合過濾模式)。
除此之外,還有許多其它的標誌位,您可以參考有關WIN32 API手冊。

mov ofn.lpstrTitle, OFFSET OurTitle

指定開啟檔案對話方塊的標題名。

invoke GetOpenFileName, ADDR ofn

呼叫GetOpenFileName函式,並傳入指向結構體ofn的指標。
這時候,開啟檔案對話方塊就顯示出來了,GetOpenFileName函式要一直等到使用者選擇了一個檔案後才會返回,或者當使用者按下了CANCEL鍵或關閉對話方塊時。
當使用者選擇了開啟一個檔案時,該函式返回TRUE, 否則返回FALSE。

.if eax==TRUE
invoke lstrcat,offset OutputString,OFFSET FullPathName
invoke lstrcat,offset OutputString,ofn.lpstrFile
invoke lstrcat,offset OutputString,offset CrLf
invoke lstrcat,offset OutputString,offset FullName

當使用者選擇開啟一個檔案時,我們就在一個對話方塊中顯示一個字串,我們先給OutputString變數分配記憶體,然後呼叫PAI 函式lstrcat,把所有的字串連到一起,為了讓這些字串分行顯示,我們必須在每個字串後面加一個換行符。

mov eax,ofn.lpstrFile
push ebx
xor ebx,ebx
mov bx,ofn.nFileOffset
add eax,ebx
pop ebx
invoke lstrcat,offset OutputString,eax

上面這幾行可能需要一些解釋。nFileOffset的值等於被開啟檔案的全路徑名中的檔名的第一個字元的索引,由於nFileOffset是一個WORD型變數,而lpstrFile是一個DWORD形的指標,所以我們就要作一轉換把nFileOffset存入ebx暫存器的底位元組,然後再加到eax暫存器中得到DWORD型的指標。

invoke MessageBox,hWnd,OFFSET OutputString,ADDR AppName,MB_OK

我們在對話方塊中顯示該字串。

invoke RtlZerolMemory,offset OutputString,OUTPUTSIZE

為了下一次能正確地顯示,必須清除緩衝區,我們呼叫函式RtlZerolMemory來做這件事。

[@more@]

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

相關文章