我正在尝试打开默认文件属性对话框,但无法为不同目录中的文件获取其工作属性。
我需要为不同目录(甚至驱动器)中的文件获取IContextMenu*
接口指针。
我希望在属性对话框中看到“各种文件夹”。
这是我天真的做法:
int main() {
CoInitialize(NULL);
LPOLESTR pszFile = OLESTR("c:\\Windows\\notepad.exe");
LPOLESTR pszFile2 = OLESTR("c:\\Windows\\System32\\notepad.exe");
LPITEMIDLIST pidl;
LPITEMIDLIST pidl2;
LPCITEMIDLIST pidlItem;
LPCITEMIDLIST pidlItem2;
HRESULT hr;
IShellFolder* pFolder;
IContextMenu* pContextMenu;
CMINVOKECOMMANDINFO cmi;
hr = SHGetDesktopFolder(&pFolder);
if (FAILED(hr)) return 0;
hr = pFolder->ParseDisplayName(HWND_DESKTOP, NULL, pszFile, NULL, &pidl, NULL);
hr = pFolder->ParseDisplayName(HWND_DESKTOP, NULL, pszFile2, NULL, &pidl2, NULL);
pFolder->Release();
if (FAILED(hr)) return 0;
hr = SHBindToParent(pidl, IID_IShellFolder, (void **)&pFolder, &pidlItem);
if (FAILED(hr)) {
SHFree(pidl);
return 0;
}
//pFolder->Release();
hr = SHBindToParent(pidl2, IID_IShellFolder, (void **)&pFolder, &pidlItem2);
if (FAILED(hr)) {
SHFree(pidl2);
return 0;
}
LPCITEMIDLIST list[] = {pidlItem, pidlItem2};
hr = pFolder->GetUIObjectOf(HWND_DESKTOP, 2, (LPCITEMIDLIST *)list, IID_IContextMenu, NULL, (void **)&pContextMenu);
pFolder->Release();
if (SUCCEEDED(hr)) {
ZeroMemory(&cmi, sizeof(cmi));
cmi.cbSize = sizeof(cmi);
cmi.lpVerb = "properties";
cmi.nShow = SW_SHOWNORMAL;
hr = pContextMenu->InvokeCommand(&cmi);
MessageBox(0, _T("Dummy message box"), 0, 0);
Sleep(10000); // Give the system time to show the dialog before exiting
pContextMenu->Release();
}
SHFree(pidl);
return 0;
}
我也尝试了this,但它根本不起作用。 此外,我尝试使用桌面IShellFolder作为我的PIDL的父级,但它也无法正常工作。
有什么想法吗?
答案 0 :(得分:3)
IShellFolder::GetUIObjectOf()
仅适用于与被查询的IShellFolder
相关的单级PIDL。这在GetUIObjectOf()
documentation:
指向ITEMIDLIST结构的指针数组的地址,每个指针都唯一地标识相对于父文件夹的文件对象或子文件夹。每个项目标识符列表必须只包含一个SHITEMID结构,后跟一个终止零。
您正在将2个绝对PIDL转换为其各自文件夹的相对PIDL,但之后您正在使用IShellFolder
文件夹的Windows\System32
来检索这两个文件的IContextMenu
。这对于属于Windows\
文件夹的相对PIDL不起作用,因为IShellFolder
文件夹的Windows\System32
只知道Windows\System32
文件夹中的文件。
各种在线示例显示,当涉及多个文件时,从IContextMenu
桌面查询IShellFolder
。该方法仅在文件位于同一父文件夹中时才有效(如Raymond Chen's example中所示)。当文件位于不同的文件夹中时,事情变得更加复杂。
您的代码中也有一些内存泄漏。
处理这种情况的正确的方法是使用SHMultiFileProperties()
函数:
显示一组文件的合并属性表。显示所有文件共有的属性值,而不同的属性值显示字符串(多个值)。
使用桌面的IShellFolder
获取绝对PIDL的IDataObject
(这是允许GetUIObjectOf()
违反“{1}}的一次”每个项目标识符列表必须包含一个SHITEMID结构“规则”,然后将其传递给SHMultiFileProperties()
。例如:
int main()
{
CoInitialize(NULL);
LPOLESTR pszFile = OLESTR("c:\\Windows\\notepad.exe");
LPOLESTR pszFile2 = OLESTR("c:\\Windows\\System32\\notepad.exe");
LPITEMIDLIST pidl;
LPITEMIDLIST pidl2;
HRESULT hr;
IShellFolder* pDesktop;
IDataObject *pDataObject;
hr = SHGetDesktopFolder(&pDesktop);
if (FAILED(hr))
{
CoUninitialize();
return 0;
}
hr = pDesktop->ParseDisplayName(HWND_DESKTOP, NULL, pszFile, NULL, &pidl, NULL);
if (FAILED(hr)) {
pDesktop->Release();
CoUninitialize();
return 0;
}
hr = pDesktop->ParseDisplayName(HWND_DESKTOP, NULL, pszFile2, NULL, &pidl2, NULL);
if (FAILED(hr)) {
SHFree(pidl);
pDesktop->Release();
CoUninitialize();
return 0;
}
LPCITEMIDLIST list[] = {pidl, pidl2};
hr = pDesktop->GetUIObjectOf(HWND_DESKTOP, 2, (LPCITEMIDLIST *)list, IID_IDataObject, NULL, (void **)&pDataObject);
// alternatively, you can also use SHCreateDataObject() or CIDLData_CreateFromIDArray() to create the IDataObject
pDesktop->Release();
SHFree(pidl);
SHFree(pidl2);
if (SUCCEEDED(hr)) {
hr = SHMultiFileProperties(pDataObject, 0);
pDataObject->Release();
if (SUCCEEDED(hr)) {
MessageBox(0, _T("Dummy message box"), 0, 0);
Sleep(10000); // Give the system time to show the dialog before exiting
}
}
CoUninitialize();
return 0;
}