目录选择 API

SHBrowseForFolder 显示目录选择对话框
SHGetPathFromIDList 取得目录全路径

SHBrowseForFolder 函数

LPITEMIDLIST SHBrowseForFolder( LPBROWSEINFO lpbi )
参数 描述
lpbi BROWSEINFO 结构地址
返回值 ITEMIDLIST 结构地址(如按取消,返回 NULL)

SHGetPathFromIDList 函数

BOOL SHGetPathFromIDList(
  LPCITEMIDLIST pidl,
  LPSTR pszPath
);
取得选择的目录全路径
参数 描述
pidl ITEMIDLIST 结构地址
pszPath 输出目录路径缓冲区,默认长度 MAX_PATH
返回值 成功:TRUE,失败:FALSE

LPBROWSEINFO 结构

struct LPBROWSEINFO {
  HWND hwndOwner;
  LPCITEMIDLIST pidlRoot;
  LPTSTR pszDisplayName;
  LPCTSTR lpszTitle;
  UINT ulFlags;
  BFFCALLBACK lpfn;
  LPARAM lParam;
  int iImage;
}
参数 描述
hwndOwner 设置目录选择对话框的父窗口句柄
pidlRoot 用于指定可选择的目录范围, 一般设为 NULL
pszDisplayName 接收目录显示名称的缓冲区, 如: "我的文档","System (C:)"等
lpszTitle 在对话框的目录树图上方显示的描述性文字
ulFlags 标记, 指定对话框的显示方式
lpfn 回调函数地址 BrowseCallbackProc, 每次目录变更时调用
lParam 回调参数, 直接传给回调函数的 lpData 参数
iImage 返回目录图标位于系统图像列表中的序号

BrowseCallbackProc 回调函数

BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData)
参数 描述
hwnd 对话框的句柄,用于发送控制消息
uMsg 回调消息, 如 BFFM_SELCHANGED
lParam ITEMIDLIST 指针
lpData 回调参数

ulFlags

常量 描述
BIF_EDITBOX 在目录树图上方显示输入框, 可以手动输入目录路径
BIF_STATUSTEXT 显示一个状态文本, 可以由回调函数用发送 BFFM_SETSTATUSTEXT 消息的方法设置内容
BIF_VALIDATE 对于手工输入的路径, 如果是非法的, 则使回调函数的消息参数是 BFFM_VALIDATEFAILED

控制消息

处理者 常量 描述
回调函数 BFFM_SELCHANGED 所选的目录发生变化
对话框 BFFM_SETSTATUSTEXT 设置状态文本内容
对话框 BFFM_ENABLEOK 设置确定按钮可用状态

BFFM_SETSTATUSTEXT 消息

参数 描述
wParam 0
lParam 状态字符串

BFFM_ENABLEOK 消息

参数 描述
wParam 0
lParam 可用状态(1:可用,0:禁用)

示例:

var
  SelDirInitPath : WideString; // 初始目录,在回调函数中通过发送消息设定

function BrowseCallbackProc(hwnd: HWND;uMsg: UINT;lParam: Cardinal;lpData: Cardinal): integer; stdcall;
begin 
    if uMsg=BFFM_INITIALIZED then
        result :=SendMessageW(Hwnd,BFFM_SETSELECTIONW,Ord(TRUE),longint(PWideChar(SelDirInitPath)))
    else 
        result :=1
end;

function SelDir(h:THandle; const Root: WideString):WideString;
var
    WindowList: Pointer;
    BrowseInfo: TBrowseInfoW;
    Buffer: PWideChar;
    RootItemIDList, ItemIDList: PItemIDList;
    ShellMalloc: IMalloc;
    IDesktopFolder: IShellFolder; 
    Eaten, Flags: LongWord; 
begin 
    Result := '';
    FillChar(BrowseInfo, SizeOf(BrowseInfo), 0); 
    if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nil) then
    begin
        Buffer := ShellMalloc.Alloc(MAX_PATH);
        try
            RootItemIDList := nil;
            if Root <> '' then begin // 设定目录选择对话框中的顶级目录,默认为桌面
                SHGetDesktopFolder(IDesktopFolder);
                IDesktopFolder.ParseDisplayName(Application.Handle, nil, POleStr(Root), Eaten, RootItemIDList, Flags);
            end;
            with BrowseInfo do begin
                hwndOwner := h;
                pidlRoot := RootItemIDList; 
                pszDisplayName := Buffer; 
                lpszTitle := '选择歌曲所在的目录:';
                ulFlags := BIF_RETURNONLYFSDIRS;
                lpfn :=@BrowseCallbackProc;
                lParam :=BFFM_INITIALIZED;
            end; 
            WindowList := DisableTaskWindows(0); 
            try 
                ItemIDList := ShBrowseForFolderW(BrowseInfo);
            finally
                EnableTaskWindows(WindowList);
            end;
            if ItemIDList <> nil then begin
                ShGetPathFromIDListW(ItemIDList, Buffer);
                ShellMalloc.Free(ItemIDList);
                Result := Buffer;
            end; 
        finally 
            ShellMalloc.Free(Buffer);
        end; 
    end; 
end;
		
int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData)
{
	HWND hh = GetDlgItem(hwnd, lpData);

	switch(uMsg)
	{
	case BFFM_SELCHANGED :
		char path[256];
		SHGetPathFromIDList((LPITEMIDLIST)lParam,path);
		::SetWindowText( GetDlgItem(hwnd, lpData), path);
		return 0;
	default:
		return 0;
	}
}

void SelectDirectory( HWND hwnd, LPCTSTR title, LONG editid)
{

	BROWSEINFO bi;
	char path[MAX_PATH]={"C:\\"};
	bi.hwndOwner =hwnd;
	bi.lpszTitle =title;
	bi.pszDisplayName =path;
	bi.ulFlags =BIF_RETURNONLYFSDIRS;
	bi.lpfn =BrowseCallbackProc;
	bi.pidlRoot =NULL;
	bi.lParam =editid;

	InitCommonControls();
	LPITEMIDLIST a = SHBrowseForFolder(&bi);
	if( a != NULL )
	{
		char path[MAX_PATH];
		SHGetPathFromIDList( a, path);

		::SetWindowText(GetDlgItem(hwnd,editid),path);
	}

}

void CCopyexDlg::OnBTNSource()
{
	SelectDirectory( this->m_hWnd, "Source Directory", IDC_EDIT_Source );
}