Windows操作系统为一些常用功能提供了一些通用对话框(Common Dialog Box),比如,在不同的应用程序中进行打开文件、选择字体、选择颜色等操作时,不同程序显示的对话框的模样都是一样的。另外,把同样的应用程序放到不同版本的Windows下执行就会发现,这些对话框会随着操作系统版本的不同而不同,如图8.1所示,选择同样的“打开”文件菜单项时,在Windows XP下显示的对话框是左边的样子,而在Windows 98下显示的是右边的样子,但程序中并没有为不同版本的操作系统设计不同的对话框。造成这些现象的原因就是这些对话框是操作系统提供的,实现对话框的代码包括在Comdlg32.dll库文件中,由于不同版本的Comdlg32.dll在设计上可能有所不同,所以不同版本Windows下的对话框会有所不同。

                                                           图8.1 不同操作系统下的“打开”文件对话框

8.1 通用对话框简介

通用对话框函数由Comdlg32.dll提供,在使用之前需要在源程序中包含相应的include和includelib语句:

    include      comdlg32.incincludelib   comdlg32.lib

Windows提供多种通用对话框,每种通用对话框都使用一个专用的函数来创建和显示,另外,提供一个数据结构供初始化对话框使用,并在同一个数据结构中返回用户在对话框中输入的数据。使用这些对话框是很简单的,只需要填写结构中的初始化数据,然后调用函数并把结构地址传入就可以了。

Comdlg32.dll中提供的通用对话框如表8.1所示,表中还包括创建这些对话框使用的函数,以及数据结构名称。

                                                         表8.1 通用对话框列表

在这些对话框中,查找字符串和替换字符串的对话框是非模态的,方便用户在查找到一个字符串以后,不必关闭对话框就可以继续查找另一个字符串,其他的对话框都是模态对话框。通用对话框使用的例子可以参考所附光盘的Chapter08\CommDlg目录中的代码,包括汇编源代码CommDlg.asm和资源脚本文件CommDlg.rc。CommDlg.asm文件的内容如下:

;CommDlg.asm-------------“打开文件”、“打印”、“查找文本”等通用对话框的使用例子
;使用 nmake 或下列命令进行编译和链接:
;ml /c /coff CommDlg.asm
;rc CommDlg.rc
;Link /subsystem:windows CommDlg.obj CommDlg.res
.386
.model flat,stdcall
option casemap:none 
;include文件定义 
include 	c:/masm32/include/windows.inc 
include 	c:/masm32/include/user32.inc 
includelib 	c:/masm32/lib/user32.lib 
include 	c:/masm32/include/kernel32.inc 
includelib 	c:/masm32/lib/kernel32.lib 
include 	c:/masm32/include/Comdlg32.inc 
includelib 	c:/masm32/lib/Comdlg32.lib 
;equ 等值定义 
ICO_MAIN 	equ 1000
DLG_MAIN 	equ 1000
IDM_MAIN 	equ 1000
IDM_OPEN 	equ 1101
IDM_SAVEAS 	equ 1102 
IDM_PAGESETUP equ 1103 
IDM_EXIT 	equ 1104 
IDM_FIND 	equ 1201
IDM_REPLACE equ 1202
IDM_SELFONT equ 1203 
IDM_SELCOLOR equ 1204
;数据段
.data?
hInstance 	dword ?
hWinMain	dword ?
dwFontColor dword ?
dwBackColor dword ?
dwCustColors dword 16 dup(?)
stLogFont	LOGFONT <?>
szFileName 	dword MAX_PATH dup(?)
szBuffer 	dword 1024 dup(?)
;查找替换对话框使用
idFindMessage dword ?
stFind FINDREPLACE <?>
szFindText byte 100 dup(?)
szReplaceText byte 100 dup(?)
.const 
FINDMSGSTRING byte 'commdlg_FindReplace',0
szSaveCaption byte '请输入保存的文件名',0
szFormatColor byte '您选择的颜色值:%08x',0
szFormatFont  byte '您的选择:',0dh,0ah,'字体名称:%s',0dh,0ahbyte '字体颜色值:%08x,字体大小:%d',0
szFormatFind  byte '您按下了“%s”按钮',0dh,0ah,'查找字符串:%s',0dh,0ahbyte '替换字符串:%s',0
szFormatPrt   byte '您选择的打印机:%s',0
szCaption 	  byte '执行结果',0
szFindNext    byte '查找下一个',0
szReplace     byte '替换',0
szReplaceAll  byte '全部替换',0
szFilter 	  byte 'Text Files(*.txt)',0,'*.txt',0,'All Files(*.*)',0,'*.*',0,0
szDefExt 	  byte 'txt',0
;代码段
.code 
;页面设置对话框
_PageSetup proc local @stPS:PAGESETUPDLG invoke RtlZeroMemory, addr @stPS, sizeof @stPS mov @stPS.lStructSize, sizeof @stPS push hWinMain pop @stPS.hwndOwner invoke PageSetupDlg, addr @stPS .if eax && @stPS.hDevMode mov eax, @stPS.hDevMode mov eax, [eax]invoke wsprintf, addr szBuffer, addr szFormatPrt, eax invoke MessageBox, hWinMain, addr szBuffer, addr szCaption, MB_OK .endif ret 
_PageSetup endp 
;显示“保存文件”对话框
_SaveAs proc local @stOF:OPENFILENAME invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF.lStructSize, sizeof @stOF push hWinMain pop @stOF.hwndOwner mov @stOF.lpstrFilter, offset szFilter mov @stOF.lpstrFile, offset szFileName mov @stOF.nMaxFile, MAX_PATH mov @stOF.Flags, OFN_PATHMUSTEXIST mov @stOF.lpstrDefExt, offset szDefExt mov @stOF.lpstrTitle, offset szSaveCaption invoke GetSaveFileName, addr @stOF .if eax invoke MessageBox, hWinMain, addr szFileName, addr szCaption, MB_OK .endif ret 
_SaveAs endp 
;显示“打开文件”对话框
_OpenFile proc local @stOF:OPENFILENAME invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF.lStructSize, sizeof @stOF push hWinMainpop @stOF.hwndOwner mov @stOF.lpstrFilter, offset szFilter mov @stOF.lpstrFile, offset szFileName mov @stOF.nMaxFile, MAX_PATH mov @stOF.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST invoke GetOpenFileName, addr @stOF .if eax invoke MessageBox, hWinMain, addr szFileName, addr szCaption, MB_OK .endif ret 
_OpenFile endp 
;选择颜色
_ChooseColor proc local @stCC:CHOOSECOLOR invoke RtlZeroMemory, addr @stCC, sizeof @stCC mov @stCC.lStructSize, sizeof @stCC push hWinMain pop @stCC.hwndOwner push dwBackColor pop @stCC.rgbResult mov @stCC.Flags, CC_RGBINIT or CC_FULLOPEN mov @stCC.lpCustColors, offset dwCustColors invoke ChooseColor, addr @stCC .if eax push @stCC.rgbResult pop dwBackColor invoke wsprintf, addr szBuffer, addr szFormatColor, dwBackColor invoke MessageBox, hWinMain, addr szBuffer, addr szCaption, MB_OK .endif ret 
_ChooseColor endp ;选择字体
_ChooseFont proc local @stCF:CHOOSEFONT invoke RtlZeroMemory, addr @stCF, sizeof @stCF mov @stCF.lStructSize, sizeof @stCF push hWinMain pop @stCF.hwndOwner mov @stCF.lpLogFont, offset stLogFont push dwFontColor pop @stCF.rgbColors mov @stCF.Flags, CF_SCREENFONTS or CF_INITTOLOGFONTSTRUCT or CF_EFFECTS invoke ChooseFont, addr @stCF .if eax push @stCF.rgbColors pop dwFontColor invoke wsprintf, addr szBuffer, addr szFormatFont, addr stLogFont.lfFaceName, \dwFontColor, @stCF.iPointSize invoke MessageBox, hWinMain, addr szBuffer, addr szCaption, MB_OK .endif ret 
_ChooseFont endp ;--------------------------------------------------------------------
_ProcDlgMain proc uses ebx edi esi hWnd, wMsg, wParam, lParam local @szBuffer[128]:byte mov eax, wMsg .if eax == WM_CLOSE invoke EndDialog, hWnd, NULL .elseif eax == WM_INITDIALOG ;注册“查找”对话框消息,初始化“查找”对话框的结构mov eax, hWnd mov hWinMain, eax mov stFind.hwndOwner, eax mov stFind.lStructSize, sizeof stFindmov stFind.Flags, FR_DOWN mov stFind.lpstrFindWhat, offset szFindText mov stFind.wFindWhatLen, sizeof szFindTextmov stFind.lpstrReplaceWith, offset szReplaceText mov stFind.wReplaceWithLen, sizeof szReplaceText invoke RegisterWindowMessage, addr FINDMSGSTRING mov idFindMessage, eax .elseif eax == WM_COMMAND mov eax, wParam .if ax == IDM_EXIT invoke EndDialog, hWnd, NULL 				;关闭对话框.elseif ax == IDM_OPEN invoke _OpenFile 							;打开文件.elseif ax == IDM_SAVEASinvoke _SaveAs								;保存文件 .elseif ax == IDM_PAGESETUP						invoke _PageSetup 							;页面设置对话框.elseif ax == IDM_FIND and stFind.Flags, not FR_DIALOGTERM invoke FindText, addr stFind 				;查找文本 .elseif ax == IDM_REPLACE and stFind.Flags, not FR_DIALOGTERM 		invoke ReplaceText, addr stFind 			;替换字符串:%s.elseif ax == IDM_SELFONT invoke _ChooseFont 							;选择字体 .elseif ax == IDM_SELCOLOR invoke _ChooseColor 						;选择颜色.endif .elseif eax == idFindMessage xor ecx, ecx .if stFind.Flags & FR_FINDNEXT mov ecx, offset szFindNext .elseif stFind.Flags & FR_REPLACE mov ecx, offset szReplace .elseif stFind.Flags & FR_REPLACEALL mov ecx, offset szReplaceAll .endif .if ecx invoke wsprintf, addr szBuffer, addr szFormatFind, \ecx, addr szFindText, addr szReplaceText invoke MessageBox, hWinMain, addr szBuffer, addr szCaption, MB_OK .endif .else mov eax, FALSE ret .endif mov eax, TRUE ret 
_ProcDlgMain endp  ;main函数
main proc invoke GetModuleHandle, NULL mov hInstance, eax invoke DialogBoxParam, hInstance, DLG_MAIN, NULL, offset _ProcDlgMain, NULL invoke ExitProcess, 0 
main endp 
end main 

编译运行:

选择子菜单【查找字符串】

在资源脚本文件中定义了一个对话框用做主窗口,同时定义了一个菜单用来选择各种通用对话框。下面结合这个例子说明各种通用对话框的用法。

8.2 使用通用对话框

8.2.1 “打开”文件和“保存”文件对话框

“打开”文件和“保存”文件的对话框大概是读者最熟悉的,如图8.1所示。由于Windows操作系统随着版本的升级会对用户界面的风格做一些调整,不同版本的Comdlg32.dll库文件也随之改变,但不管主流的用户界面如何改变,对程序员来说,编程的接口是不会变的,从Windows 95到Windows XP,通用对话框函数的使用方式并没有什么不同。

显示“打开”文件对话框的函数是GetOpenFileName,显示“保存”文件对话框的函数是GetSaveFileName。这两个对话框可以让用户选择驱动器、目录,以及一个文件名(打开文件对话框还允许选择多个文件),但这两个对话框并不对文件进行任何操作,也就是说,它们仅给用户提供一个统一的界面来“选择”文件名,获取文件名以后,对文件的打开、读写等操作还需要程序员自己解决。

这两个函数的语法是:

    invoke  GetOpenFileName,lpofn        ;显示打开文件对话框invoke  GetSaveFileName,lpofn        ;显示保存文件对话框

lpofn参数是一个指针,指向一个OPENFILENAME结构,程序在调用函数前需要在结构中填写初始化数据,两个函数使用的结构是一样的,只是使用的初始化数据有所不同而已。OPENFILENAME结构是这样定义的:

    OPENFILENAMEA          STRUCTlStructSize          DWORD    ?    ;结构的长度,用户填写hwndOwner            DWORD    ?    ;所属窗口,可以为NULLhInstance            DWORD    ?    ;lpstrFilter          DWORD    ?    ;文件筛选字符串lpstrCustomFilter DWORD       ?nMaxCustFilter       DWORD    ?nFilterIndex         DWORD    ?lpstrFile            DWORD    ?    ;全路径的文件名缓冲区nMaxFile             DWORD    ?    ;文件名缓冲区长度lpstrFileTitle       DWORD    ?    ;不包含路径的文件名缓冲区nMaxFileTitle        DWORD    ?    ;文件名缓冲区长度lpstrInitialDir      DWORD    ?    ;初始目录lpstrTitle           DWORD    ?    ;对话框标题Flags                DWORD    ?    ;标志nFileOffset          WORD     ?    ;文件名在字符串中的起始位置nFileExtension       WORD     ?    ;扩展名在字符串中的起始位置lpstrDefExt          DWORD    ?    ;默认扩展名lCustData            DWORD    ?lpfnHook             DWORD    ?lpTemplateName       DWORD    ?OPENFILENAMEA          ENDSOPENFILENAME           equ  <OPENFILENAMEA>

结构中一些重要的字段含义如下。

● lpstrFilter——指定文件名筛选字符串,该字段决定了对话框中“文件类型”下拉式列表框中的内容,字符串可以由多组内容组成,每组包括一个说明字符串和一个筛选字符串,字符串的最后用两个0结束。如下面的字符串将在列表框中显示两项内容,选择不同项目的时候分别列出“*.txt”文件或者所有文件“*.*”:

'Text Files(*.txt)',0,'*.txt',0,'All Files(*.*)',0,'*.*',0,0

筛选字符串中也可以同时指定多个扩展名,中间用分号隔开,如'*.txt;*.doc'。

● lpstrFile——指向一个包含文件名的缓冲区。如果这个缓冲区中已经包含了一个文件名,那么对话框初始化的时候将显示这个文件名。当用户选择了一个文件的时候,函数在这里返回新的文件名。

● nMaxFile——指定lpstrFile参数指向的缓冲区的长度。

● lpstrFileTitle——指向一个缓冲区,用来接收用户选择的不含路径的文件名。这个字段可以为NULL。

● nMaxFileTitle——指明lpstrFileTitle参数指向的缓冲区的长度。

● lpstrInitialDir——对话框的初始化目录,这个字段可以为NULL。

● lpstrTitle——指向自定义的对话框标题,如果这个字段是NULL,那么“打开”对话框和“保存”对话框的默认标题是“打开”和“另存为”。

● nFileOffset—返回文件名字符串中文件名的起始位置,如当用户选择了文件“c:\dir1\file.ext”时,这里将返回8。

● nFileExtension——返回文件名字符串中扩展名的起始位置,同样是上面的字符串,这里返回13。如果文件名的最后一个字符是“.”,这里返回0,表示文件没有扩展名,这个字段和nFileOffset字段为分析文件名提供了方便。

● lpstrDefExt——指定默认扩展名,如果用户输入了一个没有扩展名的文件名,那么函数会自动加上这个默认扩展名。

● Flags字段——该标志字段决定了对话框的不同行为,它可以是一些取值的组合。下面是一些比较重要的标志:

■ OFN_ALLOWMULTISELECT——允许同时选择多个文件名。

■ OFN_CREATEPROMPT——如果用户输入了一个不存在的文件名,对话框向用户提问“是否建立文件”。

■ OFN_FILEMUSTEXIST——用户只能选择一个已经存在的文件名,使用这个标志的时候必须同时使用OFN_PATHMUSTEXIST标志。

■ OFN_HIDEREADONLY——对话框中不显示“以只读方式打开”复选框。

■ OFN_OVERWRITEPROMPT——在“保存”文件对话框中使用的时候,当选择一个已存在的文件时,对话框会提问“是否覆盖文件”。

■ OFN_PATHMUSTEXIST——用户输入文件名时,路径必须存在。

■ OFN_READONLY——对话框中的“以只读方式打开”复选框初始化的时候处于选中状态。

调用显示“打开”或“保存”文件对话框函数时,函数会停留直到对话框关闭为止,当用户单击了对话框中的“确定”按钮时,函数返回TRUE,用户单击“取消”按钮退出时,函数返回FALSE,程序可以由此判断是否需要继续进行打开或保存文件的操作。具体的代码可以参考例子中的_SaveAs和_OpenFile子程序。

8.2.2 字体选择对话框

“字体”通用对话框如图8.2所示,对话框列出了系统中安装的字体,用户可以在上面选择字体名称,同时可以选择字号大小、颜色,以及一些效果如斜体、粗体、删除线或下划线等,显示选择“字体”对话框的函数是ChooseFont:

                                                            图8.2 “字体选择”对话框

invoke   ChooseFont,lpcf

lpcf指向一个CHOOSEFONT结构,这个结构是这样定义的:

    CHOOSEFONT              STRUCTlStructSize           DWORD    ?    ;结构长度hwndOwner             DWORD    ?    ;所属窗口hdc                   DWORD    ?lpLogFont             DWORD    ?    ;指向一个LOGFONT结构iPointSize            DWORD    ?    ;选择的字体大小Flags                 DWORD    ?    ;标志rgbColors             DWORD    ?    ;选择的字体颜色lCustData             DWORD    ?lpfnHook              DWORD    ?lpTemplateName        DWORD    ?hInstance             DWORD    ?lpszStyle            DWORD    ?nFontType            WORD     ?Alignment            WORD     ?nSizeMin             DWORD    ?nSizeMax             DWORD    ?CHOOSEFONT             ENDS

结构中一些重要的字段含义如下:

● hDC——当Flags字段中指定CF_PRINTERFONTS标志时,它是打印机的DC句柄。

● lpLogFont——指向一个包含LOGFONT结构的缓冲区。LOGFONT结构可以用来指定字体的名称和属性。如果Flags字段中指定CF_INITTOLOGFONTSTRUCT标志的话,对话框将根据这个结构初始化对话框,函数也在这里返回用户选择的字体名称。

● iPointSize——返回用户选择的字号大小,单位是1/10磅。

● rgbColors——如果Flags字段的CF_EFFECTS标志被设置,对话框将根据这个数值初始化“颜色”下拉式列表框。另外,函数返回时在这里返回用户选择的字体颜色。

● nFontType—返回用户选择的字体是属于哪一类的,可能返回的值有BOLD_FONTTYPE,ITALIC_FONTTYPE,PRINTER_FONTTYPE,REGULAR_FONTTYPE和SCREEN_FONTTYPE等。

另一个关键的字段是Flags字段,Flags字段的初始值决定了对话框的不同行为,函数返回的时候也会在这里返回一些用户的选择,它可以是下面取值的组合:

● CF_BOTH——对话框同时列出打印机字体和屏幕字体。

● CF_TTONLY——对话框只列出TrueType字体。

● CF_EFFECTS——对话框中显示“效果”复选框。

● CF_FIXEDPITCHONLY——对话框的字体列表中只显示等宽字体。

● CF_LIMITSIZE——对话框显示的字体尺寸限于nSizeMin和nSizeMax字段指定的数值之间。

● CF_NOSTYLESEL——对话框中不显示“字形”组合列表框。

● CF_NOSIZESEL——对话框中不显示“大小”组合列表框。

● CF_SCREENFONTS——字体列表中只显示屏幕字体。

调用ChooseFont函数时,函数会停留直到对话框关闭为止,当用户单击了对话框中的“确定”按钮时,函数返回TRUE,用户单击“取消”按钮退出时,函数返回FALSE。具体的使用例子可以参考例子中的_ChooseFont子程序。

在调用ChooseFont之前,lpLogFont字段被指向一个LOGFONT结构,对话框关闭的时候,函数在LOGFONT结构的lfFaceName字段中返回字体的名称,字体的效果和字形也在LOGFONT结构中返回。

用户选择的颜色在rgbColors字段中返回,字号大小在iPointSize字段中返回,由于单位是1/10磅,所以返回的数值等于对话框中选择的字号大小乘以10。

8.2.3 “颜色”选择对话框

“颜色”选择对话框如图8.3所示,左边是基本的选择系统预定义颜色的区域,右边是扩展的区域,可以由用户自己选择或输入颜色值。

                                                     图8.3 “颜色”选择对话框

打开“颜色”选择对话框使用函数ChooseColor:

invoke   ChooseColor,lpcc

lpcc指向一个CHOOSECOLOR结构,这个结构是这样定义的:

    CHOOSECOLOR            STRUCTLStructSize          DWORD    ?    ;结构长度HwndOwner            DWORD    ?    ;所属窗口HInstance            DWORD    ?rgbResult            DWORD    ?    ;用户选择的颜色值lpCustColors         DWORD    ?    ;用户自定义颜色缓冲区Flags                DWORD    ?    ;标志lCustData            DWORD    ?lpfnHook             DWORD    ?lpTemplateName       DWORD    ?CHOOSECOLOR            ENDS

结构中几个重要的字段说明如下。

● rgbResult——如果Flags字段指定了CC_RGBINIT标志,那么创建对话框的时候使用这个字段来初始化选择框中的颜色;函数返回的时候在这里返回用户选择的颜色。

● lpCustColors——指向一个16个双字长度的缓冲区,定义16种自定义颜色。

● Flags——标志,可以是下面取值的组合:

■ CC_FULLOPEN——对话框显示右边的扩展部分,如果不指定这个标志,初始化的时候扩展部分不显示,但用户可以通过单击“规定自定义颜色”按钮将对话框展开。

■ CC_PREVENTFULLOPEN——禁止“规定自定义颜色”按钮,也就是说不允许用户展开对话框的扩展部分。

■ CC_RGBINIT——对话框显示的时候用rgbResult字段的值初始化选择框中的颜色。

如果用户单击“确定”按钮,函数返回TRUE,否则函数返回FALSE。读者可以在例子文件中的_ChooseColor子程序中找到使用这个函数的详细代码。

使用ChooseColor函数要注意的是:lpCustColors指针不能为NULL,所以必须分配一个16个双字长度缓冲区,如果指针是NULL会导致函数违规访问00000000h处的内存,就等着看“非法操作”吧!

8.2.4 “查找”和“替换”文本对话框

“查找”文本对话框如图8.4的下图所示,“替换”文本对话框如图8.4的上图所示,要显示这两种通用对话框可分别使用FindText和ReplaceText函数:

图8.4 “查找”和“替换”对话框

invoke  FindText,lpfr
invoke  ReplaceText,lpfr

这两个函数都使用同样的FINDREPLACE结构:

    FINDREPLACEA           STRUCTlStructSize          DWORD    ?    ;结构长度hwndOwner            DWORD    ?    ;所属窗口hInstance            DWORD    ?Flags                DWORD    ?    ;标志LpstrFindWhat        DWORD    ?    ;查找字符串lpstrReplaceWith     DWORD    ?    ;替换字符串wFindWhatLen         WORD     ?    ;查找字符串长度wReplaceWithLen      WORD     ?    ;替换字符串长度lCustData            DWORD    ?lpfnHook             DWORD    ?lpTemplateName       DWORD    ?FINDREPLACEA           ENDSFINDREPLACE            equ  <FINDREPLACEA>

结构中关键的字段说明如下。

● Flags——标志,创建对话框的时候,函数根据标志中的数值初始化对话框中各控件的状态,返回的时候根据用户的选择来设置标志字段的内容,标志字段可以是以下取值的组合:

■ FR_FINDNEXT,FR_REPLACE,FR_REPLACEALL,FR_DIALOGTERM——分别表示用户单击了“查找下一个”、“替换”、“全部替换”和“取消”按钮。

■ FR_HIDEUPDOWN,FR_HIDEMATCHCASE与FR_HIDEWHOLEWORD——初始化时使用,表示对话框中不显示“方向”、“区分大小写”与“全字匹配”按钮。

■ FR_NOMATCHCASE,FR_NOUPDOWN与FR_NOWHOLEWORD——初始化时将“区分大小写”、“方向”与“全字匹配”按钮灰化。

■ FR_MATCHCASE或FR_WHOLEWORD——表示用户选中了“区分大小写”或“全字匹配”复选框。

■ FR_DOWN——把“方向”单选钮设置为“向下”。

● lpstrFindWhat——指向包含查找字符串的指针,缓冲区的长度必须至少为80字节,这个字符串在初始化的时候出现在“查找内容”编辑框中,函数也在这里返回用户输入的内容。

● lpstrReplaceWith——指向包含替换字符串的指针,这个字符串在初始化的时候出现在“替换为”编辑框中,函数也在这里返回用户输入的内容。这个字段在使用FindText函数的时候可以为NULL,但在使用ReplaceText函数的时候必须设置,否则对话框不会显示。

● wFindWhatLen和wReplaceWithLen——lpstrFindWhat和lpstrReplaceWith指示缓存区的长度。

“查找”和“替换”对话框的使用有些特殊,因为这两种对话框是非模态对话框,也就是说,FindText和ReplaceText函数被调用后,系统显示对话框后马上返回,对话框保持显示状态,直到用户按下了“取消”按钮后对话框才关闭。如果用户按下了对话框中的某个按钮,对话框设置FINDREPLACE结构的相关字段并通过自定义的消息通知父窗口的窗口过程,程序中处理查找和替换的功能集中在这个自定义消息中完成。另外,由于对话框必须向父窗口发送消息,所以hwndOwner字段中必须指定父窗口的句柄,而不能像其他通用对话框一样可以把hwndOwner字段设置为NULL。

为了让对话框能够使用自定义消息,程序必须首先使用RegisterWindowMessage函数注册自定义消息,这个函数注册消息并返回消息ID,输入的参数是消息名称字符串,Microsoft的编程手册中说明要为查找和替换对话框注册FINDMSGSTRING消息,但没有任何资料说明FINDMSGSTRING究竟代表什么,是代表消息名称字符串为“FINDMSGSTRING”吗?不是,实际上它代表字符串“commdlg_FindReplace”,所以,在对话框的初始化消息中如下注册消息:

    idFindMessage    dd  ?FINDMSGSTRING    db  'commdlg_FindReplace',0...invoke  RegisterWindowMessage,addr FINDMSGSTRINGmov      idFindMessage,eax

注意:要把RegisterWindowMessage函数返回的消息ID保存下来,并在主窗口的消息循环中通过判断uMsg是否等于这个消息ID来判断对话框是否发回消息:

    mov      eax,uMsg.if      eax ==  WM_XXX....elseif eax ==  idFindMessage.if      stFind.Flags & FR_DIALOGTERM;用户按下了"取消"按钮,对话框关闭.elseif stFind.Flags & FR_FINDNEXT;用户按下了"查找下一个"按钮.elseif stFind.Flags & FR_REPLACE;用户按下了"替换"按钮.elseif stFind.Flags & FR_REPLACEALL;用户按下了"全部替换"按钮.endif

由于用户按下了“查找下一个”、“替换”、“全部替换”和“取消”等按钮时,对话框都要发回消息,所以在处理时还要根据不同的标志进行不同的处理。

因为查找和替换对话框是非模态对话框,所以使用时要把FINDREPLACE结构和字符串变量放在全局变量中,如果放在窗口过程的局部变量中,对话框还没有关闭的情况下,这些局部变量就已经被释放,以后对话框存取的就会是无效的地址。

8.2.5 “页面设置”对话框

“页面设置”对话框用来设置打印机参数,用户可以在对话框中选择打印机、打印纸张大小、页边距和纸张方向,还可以引出一个打印机属性的设置对话框。用户可以在这里完成与打印有关的所有设置工作,页面设置对话框如图8.5所示。

图8.5 “页面设置”对话框

显示“页面设置”对话框使用PageSetupDlg函数:

invoke   PageSetupDlg,lppsd

lppsd参数指向一个PAGESETUPDLG结构:

    PAGESETUPDLG     STRUCTLStructSize                   DWORD    ?    ;结构长度HwndOwner                     DWORD    ?    ;所属窗口hDevMode                      DWORD    ?    ;指向DEVMODE结构hDevNames                     DWORD    ?    ;指向DEVNAMES结构Flags                         DWORD    ?    ;标志PtPaperSize                   POINT    <>   ;返回纸张尺寸RtMinMargin                   RECT     <>   ;返回最小允许的页边距rtMargin                      RECT     <>   ;返回用户选择的页边距hInstance                     DWORD    ?lCustData                     DWORD    ?lpfnPageSetupHook             DWORD    ?lpfnPagePaintHook             DWORD    ?lpPageSetupTemplateName       DWORD    ?hPageSetupTemplate            DWORD    ?PAGESETUPDLG     ENDS

结构中的有关字段说明如下。

● hDevMode——如果用户选择了打印机,那么这里返回一个指针,指向包含DEVMODE结构的内存块地址,DEVMODE结构中包含了打印机的名称。

● hDevNames——如果用户选择了打印机,那么这里返回一个指针,指向包含DEVNAMES结构的内存块的地址,DEVNAMES结构包含了打印机的各种属性。

● Flags——标志,可以是以下取值的组合:

■ PSD_DEFAULTMINMARGINS——将页边距设置为打印机允许的最小页边距。

■ PSD_DISABLEMARGINS,PSD_DISABLEORIENTATION和PSD_DISABLEPA PER——灰化页边距设置输入框、纸张方向选择框和纸张选择框。

■ PSD_DISABLEPAGEPAINTING——不绘画最上方的打印示例图示。

■ PSD_DISABLEPRINTER——灰化“打印机”按钮。

■ PSD_MARGINS——函数用rtMargin字段的值初始化对话框中的数值。

■ PSD_RETURNDEFAULT——函数不显示对话框,马上返回并在hDevNames和hDevMode字段中返回默认打印机的设置情况。

■ PSD_INTHOUSANDTHSOFINCHES和PSD_INHUNDREDTHSOFMILLIMETE RS——指明ptPagerSize,rtMinMargin与rtMargin等字段使用的单位是英寸还是毫米。

● ptPaperSize——一个POINT结构,返回纸张大小。

● rtMinMargin——打印机允许的最小页边距。

● rtMargin——用户选择的页边距数据。

当用户选择了打印机时,hDevMode中返回的是一个指向内存块的指针,所以需要用下面的代码获取DEVMODE结构的地址:

mov eax,@stPS.hDevMode
mov eax,[eax]        ;现在eax是DEVMODE结构的地址

总结通用对话框的使用方法可以发现,每种通用对话框函数都使用一个特定的结构来当做输入输出的缓冲区,初始化的时候函数根据结构中的数据和标志设置对话框中的子窗口控件,返回的时候在结构的相应位置返回用户的输入或选择。另外,所有结构都有几个类似的字段,如lStructSize字段必须设置为正确的结构长度;hwndOwner指定对话框的父窗口,模态对话框在关闭之前是不允许切换到这个父窗口中去的。

8.2.6 “浏览目录”对话框

在众多的系统提供的对话框中,还有一个很常用的浏览文件夹对话框,对话框如图8.6所示,这个对话框虽然也是通用型的,但是它是由Shell32.dll提供的,而不是由Comdlg32.dll提供的,在实现的方法上也和上面介绍的通用对话框有很大的不同,由于篇幅较大,有关该对话框的详细介绍放在附录C中(以电子版方式放在附书光盘中),有兴趣的读者可以自行阅读。

                                  图8.6 “浏览文件夹”对话框

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94922.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94922.shtml
英文地址,请注明出处:http://en.pswp.cn/web/94922.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SOME/IP-SD协议中组播IP地址和端口号应从何处获取、由谁设置?

<摘要> AUTOSAR SOME/IP-SD协议中组播通信参数的核心配置规则明确规定了在服务端传输&#xff08;Server-Transmits&#xff09;和客户端传输&#xff08;Client-Transmits&#xff09;两种模式下&#xff0c;组播IP地址和端口号应从何处获取、由谁设置&#xff0c;从而确…

DAY49打卡

追到第45天内容浙大疏锦行

十四、测试 (Testing)

Rust内置了强大的测试框架,使得编写和运行测试变得非常简单。Rust的测试系统主要包括单元测试、集成测试和文档测试。 1. 单元测试 单元测试通常放在与被测试代码相同的文件中,使用#[cfg(test)]模块和#[test]属性标记。 1.1 基本测试结构 // 在src/lib.rs或任何模块中pub…

LeetCode 刷题【56. 合并区间】

56. 合并区间 自己做 解&#xff1a;排序合并 class Solution { public:static bool compare(const vector<int> &p1, const vector<int> &p2){ //按第一个数排序return p1[0] < p2[0]; }vector<vector<int>> merge(ve…

DistributedLock 实现.Net分布式锁

在分布式系统中&#xff0c;经常会遇到多个实例同时访问同一份资源的情况&#xff0c;例如&#xff1a; • 多个服务节点同时写入数据库同一行数据• 定时任务在多个节点上同时运行&#xff0c;导致重复执行• 多实例写缓存时出现数据覆盖问题 为了解决 并发冲突 和 数据一致…

Flutter:ios打包ipa,证书申请,Xcode打包,完整流程

步骤1 - 5 为 申请ios的签名文件&#xff0c;App ID&#xff0c;证书&#xff0c;描述文件&#xff0c;并添加测试打包设备。 步骤1&#xff1a;生成证书签名文件&#xff08;打开钥匙串访问>证书助理>从证书颁发机构请求证书&#xff09; 存储后得到了一个签名文件&…

Shell 秘典(卷二)——号令延展秘术 与 流程掌控心法・if 天机判语篇精解

文章目录前言一、命令扩展详解1.1 逻辑运算符1.1.1 逻辑与运算符&#xff08;&&&#xff09;1.1.2 逻辑或运算符&#xff08;||&#xff09;1.1.3 组合使用注意事项1.2 echo 命令1.2.1 基本用法1.2.2 输出到标准错误&#xff08;stderr&#xff09;1.3 标准文件描述符&…

Agent实战教程:深度解析async异步编程在Langgraph中的性能优化

在现代Python开发中&#xff0c;异步编程已经成为提高程序性能的重要手段&#xff0c;特别是在处理网络请求、数据库操作或AI模型调用等耗时操作时。本文将通过实际的LangGraph 示例&#xff0c;深入解析async的真正作用&#xff0c;并揭示一个常见误区&#xff1a;为什么异步顺…

coalesce在sql中什么作用

COALESCE‌是SQL中的一个函数&#xff0c;用于返回参数列表中的第一个非空值&#xff0c;若所有参数均为NULL则返回NULL&#xff0c;常用于处理数据中的空值情况。 ‌核心功能与语法‌ COALESCE函数的基本语法为&#xff1a;COALESCE(expression1, expression2, ..., express…

【Rust】 6. 字符串学习笔记

一、Rust 字符串概述 Rust 字符串是 UTF-8 编码的文本序列&#xff0c;提供两种主要类型&#xff1a; &str - 字符串切片&#xff08;通常作为引用出现&#xff09;String - 动态可变的、拥有所有权的字符串 二、字符串字面量 (&str) 编译时已知大小&#xff0c;静态分…

达梦数据库-数据文件 (二)

达梦数据库-数据文件&#xff08;二&#xff09;-自动监控达梦数据库表空间使用率的 Shell 脚本 自动监控达梦数据库表空间使用率的 Shell 脚本&#xff0c;支持&#xff1a; ✅ 实时计算每个表空间的使用率✅ 设置阈值告警&#xff08;如 >80%&#xff09;✅ 支持邮件告警&…

如何用 Android 平台开发第一个 Kotlin 小程序

安装开发环境下载并安装最新版 Android Studio&#xff08;官方 IDE&#xff09;&#xff0c;安装时勾选 Kotlin 插件。确保 JDK 版本为 11 或更高。创建新项目打开 Android Studio 选择 File > New > New Project&#xff0c;选择 Empty Activity 模板。在配置界面中&am…

Java常用工具类

异常 (Exception)。程序世界并非总是完美的&#xff0c;异常处理机制就是Java为我们提供的优雅应对错误的解决方案。一、为什么需要异常处理&#xff1f;—— 从现实世界说起 想象一下现实生活中的场景&#xff1a; 开车上班&#xff1a;你计划开车去公司&#xff08;正常流程&…

AWS亚马逊云账号注册指南

AWS是全球领先的云计算平台&#xff0c;提供广泛的云服务。账号注册是开端&#xff0c;不管是用来学习、搭建个人项目&#xff0c;还是公司项目部署上线需要&#xff0c;都需要进行这一步。提醒&#xff1a;在使用账户之前&#xff0c;必须要绑定国际的信用卡&#xff1b;通过我…

云计算学习100天-第31天

Keepalived概念keepalived 是Linux下一个轻量级的高可用解决方案主要是通过虚拟路由冗余协议(VRRP)来实现高可用功能Virtual Router Redundancy Protocol起初就是为了补充LVS功能而设计的&#xff0c;用于监控LVS集群内后端真实服务器状态后来加入了VRRP的功能&#xff0c;它出…

2025年视觉、先进成像和计算机技术论坛(VAICT 2025)

会议简介 作为人工智能大数据创新发展论坛的重要分论坛&#xff0c;2025年视觉、先进成像和计算机技术论坛聚焦人工智能感知世界的核心前沿&#xff0c;将于2025年9月18-20日在中国广州广东科学馆举行。 视觉与成像技术是智能系统理解环境的关键&#xff0c;计算机技术则…

MySQL 与 ClickHouse 深度对比:架构、性能与场景选择指南

&#x1f31f; 引言&#xff1a;数据时代的引擎之争 在当今数据驱动的企业环境中&#xff0c;选择合适的数据库引擎成为架构设计的关键决策。想象这样一个场景&#xff1a;特斯拉的实时车况分析系统需要在毫秒级延迟下处理数百万辆汽车的传感器数据&#xff0c;而某电商平台的订…

闭包与内存泄漏:深度解析与应对策略

在 JavaScript 编程中&#xff0c;闭包是一个强大且常用的特性&#xff0c;但如果使用不当&#xff0c;可能会引发内存泄漏问题&#xff0c;影响程序性能甚至导致页面卡顿。本文将深入剖析闭包导致内存泄漏的原理&#xff0c;结合实例讲解&#xff0c;并给出切实可行的避免方法…

open webui源码分析12-Pipeline

Pipeline是 Open WebUI 的一项创新&#xff0c;它 为任何支持 OpenAI API 规范的 UI 客户端带来了模块化、可定制的工作流 —— 甚至更多功能&#xff01;只需几行代码&#xff0c;你就能轻松扩展功能、集成自己的专有逻辑并创建动态工作流。 当你处理计算密集型任务&#xff0…

深入解析 Chromium Mojo IPC:跨进程通信原理与源码实战

在现代浏览器架构中&#xff0c;多进程设计已经成为标配。Chromium 浏览器作为典型的多进程浏览器&#xff0c;其浏览器进程&#xff08;Browser Process&#xff09;、渲染进程&#xff08;Renderer Process&#xff09;、GPU 进程、Utility 进程等之间的通信&#xff0c;依赖…