📄 附录a-c.txt
字号:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
externdef IID_IUnknown:IID
LPUNKNOWN typedef DWORD
LPPUNKNOWN typedef ptr LPUNKNOWN
IUnknown_QueryInterfaceProto typedef proto :DWORD, :DWORD, :DWORD
IUnknown_AddRefProto typedef proto :DWORD
IUnknown_ReleaseProto typedef proto :DWORD
IUnknown_QueryInterface typedef ptr IUnknown_QueryInterfaceProto
IUnknown_AddRef typedef ptr IUnknown_AddRefProto
IUnknown_Release typedef ptr IUnknown_ReleaseProto
IUnknown struct DWORD
QueryInterface IUnknown_QueryInterface ?
AddRef IUnknown_AddRef ?
Release IUnknown_Release ?
IUnknown ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;IMalloc 接口定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
externdef IID_IMalloc:IID
LPMALLOC typedef DWORD
LPPMALLOC typedef ptr LPMALLOC
IMalloc_AllocProto typedef proto :DWORD, :DWORD
IMalloc_ReallocProto typedef proto :DWORD, :DWORD,:DWORD
IMalloc_FreeProto typedef proto :DWORD, :DWORD
IMalloc_GetSizeProto typedef proto :DWORD, :DWORD
IMalloc_DidAllocProto typedef proto :DWORD, :DWORD
IMalloc_HeapMinimizeProto typedef proto :DWORD
IMalloc_Alloc typedef ptr IMalloc_AllocProto
IMalloc_Realloc typedef ptr IMalloc_ReallocProto
IMalloc_Free typedef ptr IMalloc_FreeProto
IMalloc_GetSize typedef ptr IMalloc_GetSizeProto
IMalloc_DidAlloc typedef ptr IMalloc_DidAllocProto
IMalloc_HeapMinimize typedef ptr IMalloc_HeapMinimizeProto
IMalloc struct DWORD
QueryInterface IUnknown_QueryInterface ?
AddRef IUnknown_AddRef ?
Release IUnknown_Release ?
Alloc IMalloc_Alloc ?
Realloc IMalloc_Realloc ?
Free IMalloc_Free ?
GetSize IMalloc_GetSize ?
DidAlloc IMalloc_DidAlloc ?
HeapMinimize IMalloc_HeapMinimize ?
IMalloc ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data ?
_BrowseFolderTmp dd ?
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.const
_szDirInfo db '请选择目录:',0
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 弹出选择目录的对话框
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_BrowseFolderCallBack proc hWnd,uMsg,lParam,lpData
local @szBuffer[260]:byte
mov eax,uMsg
.if eax == BFFM_INITIALIZED
invoke SendMessage,hWnd,BFFM_SETSELECTION,\
TRUE,_BrowseFolderTmp
.elseif eax == BFFM_SELCHANGED
invoke SHGetPathFromIDList,lParam,addr @szBuffer
invoke SendMessage,hWnd,BFFM_SETSTATUSTEXT,\
0,addr @szBuffer
.endif
xor eax,eax
ret
_BrowseFolderCallBack endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_BrowseFolder proc _hWnd,_lpszBuffer
local @stBrowseInfo:BROWSEINFO
local @stMalloc
local @pidlParent,@dwReturn
pushad
;********************************************************************
; 初始化COM库
;********************************************************************
invoke CoInitialize,NULL
invoke SHGetMalloc,addr @stMalloc
.if eax == E_FAIL
mov @dwReturn,FALSE
jmp @F
.endif
invoke RtlZeroMemory,addr @stBrowseInfo,sizeof @stBrowseInfo
;********************************************************************
; SHBrowseForFolder 选择一个目录,把不含路径的目录名放入
; stBrowseInfo.pszDisplayName 中,SHGetPathFromIDList 把
; stBrowseInfo.pszDisplayName 转换成含全部路径的目录名
;********************************************************************
push _hWnd
pop @stBrowseInfo.hwndOwner
push _lpszBuffer
pop _BrowseFolderTmp
mov @stBrowseInfo.lpfn,offset _BrowseFolderCallBack
mov @stBrowseInfo.lpszTitle,offset _szDirInfo
mov @stBrowseInfo.ulFlags,\
BIF_RETURNONLYFSDIRS or BIF_STATUSTEXT
invoke SHBrowseForFolder,addr @stBrowseInfo
mov @pidlParent,eax
.if eax != NULL
invoke SHGetPathFromIDList,eax,_lpszBuffer
mov eax,TRUE
.else
mov eax,FALSE
.endif
mov @dwReturn,eax
;********************************************************************
; 释放COM库
;********************************************************************
mov eax,@stMalloc
mov eax,[eax]
invoke (IMalloc PTR [eax]).Free,@stMalloc,@pidlParent
mov eax,@stMalloc
mov eax,[eax]
invoke (IMalloc PTR [eax]).Release,@stMalloc
@@:
invoke CoUninitialize
popad
mov eax,@dwReturn
ret
_BrowseFolder endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
C.2 使用浏览目录对话框
浏览目录对话框的实现分为两个部分:初始化部分和对话框功能部分。
1. 初始化COM 库
浏览目录对话框要用到COM 接口,所以必须首先调用CoInitialize 函数来初始化COM
库并调用SHGetMalloc 函数来获取一个IMalloc 类型的接口,这个接口实际上是一个内存块,
中间包含各种COM 功能模块的入口地址。在对话框返回的时候,再调用接口中的Free 模块
释放接口,并调用CoUninitialize 函数释放COM 库。
COM 编程是一个很大的课题,有关COM 组件中的IUnknown 接口和IMalloc 接口等工
作机理的内容本身就是一个比较深奥的问题,在本章中读者不必深入研究_BrowseFolder.asm
文件中关于这两种接口的定义,只要将定义部分和代码中初始化和释放COM 库的代码直接
拿过来用就是了。
COM 库的相关函数包含在ole32.dll 中,所以源程序中必须包含下列语句:
include ole32.inc
includelib ole32.lib
2. 显示对话框
显示对话框的功能函数包含在Shell32.dll 中,所以在源程序的头部也应该有下列包含语
句:
include shell32.inc
includelib shell32.lib
显示对话框的功能由SHBrowseForFolder 函数实现,函数的用法如下:
invoke SHBrowseForFolder,lpbi
mov lpItemIDList,eax ;返回一个ITEMIDLIST 结构指针
参数lpbi 指向一个包含对话框初始化数据的BROWSEINFO 结构,如下所示:
BROWSEINFO STRUCT
HwndOwner dd ? ;对话框的父窗口
PidlRoot dd ? ;用来表示起始目录的ITEMIDLIST 目录
PszDisplayName dd ? ;用来接收用户选择目录的缓冲区
LpszTitle dd ? ;对话框中的用户定义文字
ulFlags dd ? ;标志
lpfn dd ? ;回调函数地址
lParam dd ? ;传给回调函数的参数
iImage dd ? ;用来接收选中目录的图像
BROWSEINFO ENDS
结构的各个重要字段说明如下。
● lpszTitle——对话框中的自定义文字,如例子中显示的是“请选择目录”。
● lpfn——回调函数的地址。
● ulFlags——用来定义对话框类型的标志,下面是一些重要的标志:
■ BIF_BROWSEFORPRINTER ——对话框中只能选择打印机。
■ BIF_BROWSEINCLUDEFILES——同时显示目录中的文件。
■ BIF_RETURNONLYFSDIRS——只返回文件系统中的目录。
■ BIF_STATUSTEXT ——对话框中显示一个状态栏。
■ BIF_EDITBOX——显示一个编辑框供用户手工输入目录。
■ BIF_VALIDATE——显示编辑框的时候检测用户输入目录的合法性。
3. 对话框的回调函数
当函数执行后,将显示对话框,当对话框初始化以及每当用户选择不同的目录的时候,
函数调用lpfn 指定的回调函数,回调函数的参数有4 个,分别是父窗口句柄hWnd 、消息类
型uMsg 、消息参数lParam 和自定义数据lpData,回调函数的语法如下:
_BrowseFolderCallBack proc hWnd,uMsg,lParam,lpData
mov eax,uMsg
.if eax == BFFM_INITIALIZED
...
.elseif eax == BFFM_SELCHANGED
...
.endif
xor eax,eax
ret
_BrowseFolderCallBack endp
回调函数可能收到的消息有3 种,如下所示:
● BFFM_INITIALIZED ——在对话框初始化的时候收到。
● BFFM_SELCHANGED——在用户选择了一个目录的时候收到,这时lParam 参数指向
一个表示当前被选择目录的ITEMIDLIST结构。
● BFFM_VALIDATEFAILED ——用户输入了一个不合法的目录名。
在回调函数中,程序可以根据情况向对话框发送控制消息,当收到
BFFM_SELCHANGED 消息时,可以根据选择情况决定是否允许用户单击对话框中的“确定”
按钮,通过发送BFFM_ENABLEOK 消息可以控制“确定”按钮的状态:
invoke SendMessage,hWnd, BFFM_ENABLEOK,0,TRUE ;允许“确定”按钮
invoke SendMessage,hWnd, BFFM_ENABLEOK,0,FALSE ;灰化“确定”按钮
程序也可以通过发送BFFM_SETSELECTION 消息来设定目录:
invoke SendMessage,hWnd,BFFM_SETSELECTION,TRUE,lpPath
如果消息的wParam 参数为TRUE,则目录用lParam 参数指定的字符串表示;如果wParam
为FALSE ,则目录用lParam 指定的ITEMIDLIST 结构表示。由于用字符串表示比较方便,
所以例子程序在收到初始化消息的时候用上面的语句设置初始目录。
调用SHBrowseForFolder 函数的时候,通过BROWSEINFO 结构的pidlRoot 字段也可以
设置初始目录,但设置ITEMIDLIST 结构比较麻烦,所以一般不使用这种方法。
另外,在回调函数中可以通过BFFM_SETSTATUSTEXT 消息设置状态栏的文字,对话
框的状态栏并不是指一般窗口底部的状态栏,而是指自定义文字下面的那一行文字,在图8.6
中就是显示被选择目录名的地方,使用BFFM_SETSTATUSTEXT 消息的格式如下:
invoke SendMessage,hWnd,BFFM_SETSTATUSTEXT,0,lpsz
例子程序中,回调函数每次在收到用户选择目录的BFFM_SELCHANGED 消息后,在状
态栏中显示目录的名称。
4. 获取返回的目录
当SHBrowseForFolder 返回的时候,如果用户单击的是“取消”按钮,那么函数的返回
值是0,否则的话,函数返回一个指向ITEMIDLIST结构的指针,对于这个结构可以不必去深
究,因为使用SHGetPathFromIDList 函数可以很方便地将它转换成目录字符串:
invoke SHGetPathFromIDList,lpItemIDList,addr szPath
函数执行后,szPath 中就是字符串格式的用户选择的目录名称了。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -