显示不同目录中文件的文件属性对话框
Display file properties dialog for files in different directories
我正在尝试打开默认文件属性对话框,但无法使其对不同目录中的文件正常工作属性。
我需要为不同目录(甚至驱动器)中的文件获取 IContextMenu*
接口指针。
我希望在属性对话框中看到 "Various folders"。
这是我天真的做法:
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 的父级,但它也不起作用。
有什么想法吗?
IShellFolder::GetUIObjectOf()
仅适用于 single-level PIDL,这些 PIDL 与被查询的 IShellFolder
相关。这在 GetUIObjectOf()
documentation:
中有明确说明
The address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object or subfolder relative to the parent folder. Each item identifier list must contain exactly one SHITEMID structure followed by a terminating zero.
您正在将 2 个绝对 PIDL 转换为它们各自文件夹的相对 PIDL,但是您正在使用 Windows\System32
文件夹的 IShellFolder
来检索两个文件的 IContextMenu
.这不适用于属于 Windows\
文件夹的相关 PIDL,因为 Windows\System32
文件夹的 IShellFolder
只知道 Windows\System32
文件夹中的文件。
网上各种例子显示,涉及多个文件时,从桌面IShellFolder
查询IContextMenu
。该方法仅在文件位于同一父文件夹中时才有效(如 Raymond Chen's example 中所示)。当文件位于不同的文件夹中时,事情会变得更加复杂。
您的代码中也有一些内存泄漏。
正确处理这种情况的方法是使用SHMultiFileProperties()
函数:
Displays a merged property sheet for a set of files. Property values common to all the files are shown while those that differ display the string (multiple values).
使用桌面的 IShellFolder
获取绝对 PIDL 的 IDataObject
(这是允许 GetUIObjectOf()
违反“每个项目标识符列表必须包含恰好一个 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;
}
我正在尝试打开默认文件属性对话框,但无法使其对不同目录中的文件正常工作属性。
我需要为不同目录(甚至驱动器)中的文件获取 IContextMenu*
接口指针。
我希望在属性对话框中看到 "Various folders"。
这是我天真的做法:
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 的父级,但它也不起作用。
有什么想法吗?
IShellFolder::GetUIObjectOf()
仅适用于 single-level PIDL,这些 PIDL 与被查询的 IShellFolder
相关。这在 GetUIObjectOf()
documentation:
The address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object or subfolder relative to the parent folder. Each item identifier list must contain exactly one SHITEMID structure followed by a terminating zero.
您正在将 2 个绝对 PIDL 转换为它们各自文件夹的相对 PIDL,但是您正在使用 Windows\System32
文件夹的 IShellFolder
来检索两个文件的 IContextMenu
.这不适用于属于 Windows\
文件夹的相关 PIDL,因为 Windows\System32
文件夹的 IShellFolder
只知道 Windows\System32
文件夹中的文件。
网上各种例子显示,涉及多个文件时,从桌面IShellFolder
查询IContextMenu
。该方法仅在文件位于同一父文件夹中时才有效(如 Raymond Chen's example 中所示)。当文件位于不同的文件夹中时,事情会变得更加复杂。
您的代码中也有一些内存泄漏。
正确处理这种情况的方法是使用SHMultiFileProperties()
函数:
Displays a merged property sheet for a set of files. Property values common to all the files are shown while those that differ display the string (multiple values).
使用桌面的 IShellFolder
获取绝对 PIDL 的 IDataObject
(这是允许 GetUIObjectOf()
违反“每个项目标识符列表必须包含恰好一个 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;
}