显示不同目录中文件的文件属性对话框

时间:2015-12-31 17:22:16

标签: c++ winapi com

我正在尝试打开默认文件属性对话框,但无法为不同目录中的文件获取其工作属性。 我需要为不同目录(甚至驱动器)中的文件获取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的父级,但它也无法正常工作。

有什么想法吗?

screenshot 2015-12-31 002.png

screenshot 2015-12-31 001.png

1 个答案:

答案 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;
}