如何修改IFileDialog中AddPlace添加的文件夹显示名称?
问题描述
使用IFileDialog接口实现自定义文件对话框并添加Places时,遇到两个路径末尾文件夹名称相同的Place在“Application Links”下均显示为“MyAppName”,无法区分。需求是为Place设置自定义显示名称:
- Place 1:显示名称“My application files”,对应路径
C:\Users\Me\OneDrive\Documents\MyAppName - Place 2:显示名称“Shared application files”,对应路径
C:\Users\Public\Documents\MyAppName
尝试用SHSetTemporaryPropertyForItem设置PKEY_FileName等属性未生效,相关代码如下:
// Code above here sets nameW to the Place name, and pathW to its full path // These are both CStringW variables // Create the IShellItem for the folder CComPtr<IShellItem> folder; SHCreateItemFromParsingName(pathW, NULL, IID_PPV_ARGS(&folder)); // This section is trying to change what is displayed... but doesn't work! PROPVARIANT pv = {0}; PropVariantInit(&pv); pv.vt = VT_LPWSTR; pv.pwszVal = nameW.GetBuffer(); // Here, I have tried various other properties such as PKEY_FileDescription, PKEY_FolderNameDisplay, etc. SHSetTemporaryPropertyForItem(folder, PKEY_FileName, pv); // Add the place _FileDialog->AddPlace(folder, FDAP_TOP);
解决方案
要实现自定义Place的显示名称,需解决两个核心问题:使用正确的属性键,以及正确处理字符串内存管理,具体方案如下:
方案一:修正SHSetTemporaryPropertyForItem调用
关键要点
- 使用正确的属性键:
IFileDialog的Place列表读取的是PKEY_ItemNameDisplay属性,而非PKEY_FileName或其他属性,这是之前设置无效的主要原因。 - 正确管理字符串内存:不能直接将
CStringW::GetBuffer()的结果赋值给PROPVARIANT的pwszVal,因为PropVariantClear会尝试释放该内存,而CStringW的内存由自身管理,会导致内存错误。需通过CoTaskMemAlloc分配独立内存并复制字符串。
修正后的代码
// 假设nameW和pathW已正确赋值为CStringW类型 CComPtr<IShellItem> folder; SHCreateItemFromParsingName(pathW, NULL, IID_PPV_ARGS(&folder)); PROPVARIANT pv = {0}; PropVariantInit(&pv); pv.vt = VT_LPWSTR; // 分配内存并复制自定义名称 const int nameLen = nameW.GetLength(); pv.pwszVal = static_cast<LPWSTR>(CoTaskMemAlloc((nameLen + 1) * sizeof(WCHAR))); if (pv.pwszVal) { wcscpy_s(pv.pwszVal, nameLen + 1, nameW.GetString()); // 设置正确的显示名称属性 SHSetTemporaryPropertyForItem(folder, PKEY_ItemNameDisplay, pv); } // 将自定义Place添加到对话框 _FileDialog->AddPlace(folder, FDAP_TOP); // 清理PROPVARIANT,释放分配的内存 PropVariantClear(&pv);
方案二:使用IShellLink包装目标路径
如果方案一仍不生效,可以通过创建IShellLink对象来包装目标文件夹路径,直接设置链接的显示名称,再转换为IShellItem添加到Place列表:
// 假设nameW和pathW已正确赋值为CStringW类型 CComPtr<IShellLinkW> shellLink; HRESULT hr = shellLink.CoCreateInstance(CLSID_ShellLink); if (SUCCEEDED(hr)) { // 设置目标文件夹路径 shellLink->SetPath(pathW); // 设置自定义显示名称 shellLink->SetDescription(nameW); // 将IShellLink转换为IShellItem CComPtr<IPersistFile> persistFile; hr = shellLink.QueryInterface(&persistFile); if (SUCCEEDED(hr)) { CComPtr<IShellItem> folder; hr = SHCreateItemFromObject(persistFile, NULL, IID_PPV_ARGS(&folder)); if (SUCCEEDED(hr)) { // 添加到Place列表 _FileDialog->AddPlace(folder, FDAP_TOP); } } }
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

