显示不同目录中文件的文件属性对话框 [英] Display file properties dialog for files in different directories

查看:225
本文介绍了显示不同目录中文件的文件属性对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图打开默认文件属性对话框,但无法获得它的工作属性在不同的目录中的文件。
我需要获取 IContextMenu * 不同目录(甚至驱动器)中的文件的接口指针。
我希望在属性对话框中看到各种文件夹。



这是我天真的方法:

  int main(){
CoInitialize(NULL);
LPOLESTR pszFile = OLESTR(c:\\Windows\\\\
otepad.exe);
LPOLESTR pszFile2 = OLESTR(c:\\Windows\\System32\\\\
otepad.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(pid1,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); //给出系统时间以在退出之前显示对话框
pContextMenu-> Release();
}

SHFree(pidl);

return 0;
}

我也试过了:


指向ITEMIDLIST结构的指针数组的地址,标识相对于父文件夹的文件对象或子文件夹。每个项目标识符列表必须只包含一个SHITEMID结构,后跟终止零


您正在转换2个绝对PIDL转换为其各自文件夹的相对PIDL,但是您正在使用 Windows \System32 文件夹的 IShellFolder 两个文件的 IContextMenu 。这将不适用于属于 Windows \ 文件夹的相对PIDL,因为<$ c>的 IShellFolder $ c> Windows \System32 文件夹仅了解 Windows \System32 文件夹中的文件。



各种在线示例显示当涉及多个文件时,从 IShellFolder 桌面的 IContextMenu 查询。该方法仅在文件位于同一父文件夹中时有效(例如 Raymond Chen的例子)。



您的代码中还有一些内存泄漏。



处理这种情况的正确方法是使用 SHMultiFileProperties() 函数:


显示一组文件的合并属性表。显示所有文件共有的属性值,而不同的属性值显示字符串(多个值)。


使用<$ c $ (这是一次,其中 GetUIObjectOf() c> c> / code>允许违反每个项目标识符列表必须只包含一个SHITEMID结构规则),然后将其传递给 SHMultiFileProperties()。例如:

  int main()
{
CoInitialize(NULL);

LPOLESTR pszFile = OLESTR(c:\\Windows\\\\
otepad.exe);
LPOLESTR pszFile2 = OLESTR(c:\\Windows\\System32\\\\
otepad.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);
//或者,也可以使用SHCreateDataObject()或CIDLData_CreateFromIDArray()来创建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); //给系统时间在退出之前显示对话框
}
}

CoUninitialize();
return 0;
}


I'm trying to open the default file properties dialog but unable to get it working property for files in different directories. I need to obtain IContextMenu* interface pointer for files in different directories (or even drives). I expect to see "Various folders" in the properties dialog.

This is my naive approach:

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

Also I tried this, but it also not working at all. Also I tried to use desktop IShellFolder as parent of my PIDLs, but it also not working.

Any ideas?

解决方案

IShellFolder::GetUIObjectOf() only works with single-level PIDLs that are relative to the IShellFolder being queried. This is clearly stated in the 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.

You are converting the 2 absolute PIDLs into relative PIDLs of their respective folders, but then you are using the IShellFolder of the Windows\System32 folder to retrieve the IContextMenu for both files. That will not work for the relative PIDL belonging to the Windows\ folder, since the IShellFolder of the Windows\System32 folder only knows about files in the Windows\System32 folder.

Various online examples show the IContextMenu being queried from the IShellFolder of the desktop when multiple files are involved. That approach only works when the files are in the same parent folder (such as demonstrated in Raymond Chen's example). Things get more complicated when the files are in different folders.

You also have a few memory leaks in your code.

The correct way to handle this situation is to use the SHMultiFileProperties() function:

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).

Use the IShellFolder of the desktop to get an IDataObject for the absolute PIDLs (this is one time where GetUIObjectOf() is allowed to violate the "Each item identifier list must contain exactly one SHITEMID structure" rule) and then pass that to SHMultiFileProperties(). For example:

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

这篇关于显示不同目录中文件的文件属性对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆