【问题标题】:How to get installed applicatio path for executbale in COM如何在 COM 中获取可执行文件的安装应用程序路径
【发布时间】:2018-05-10 20:15:04
【问题描述】:

我正在尝试使用 COM 获取所有应用程序的安装位置。我能够获得每个应用程序的显示名称。但我无法获得每个应用程序的安装路径。

我的代码:

CComPtr<IShellItem> spPrinters;
        CoInitialize(nullptr);
        HRESULT hresult = ::SHCreateItemFromParsingName(L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\"
            L"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", nullptr, IID_PPV_ARGS(&spPrinters));
        CComPtr<IEnumShellItems> spEnum;
        spPrinters->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spEnum));
        for (CComPtr<IShellItem> spProgram; spEnum->Next(1, &spProgram, nullptr) == S_OK; spProgram.Release())
        {
            CComHeapPtr<wchar_t> spszName;
            spProgram->GetDisplayName(SIGDN_NORMALDISPLAY, &spszName);
            CString cDisplayName = spszName;
}

知道如何从 IEnumShellItems 获取安装路径。

感谢您的建议。

【问题讨论】:

  • 安装路径是指(可选)“位置”列吗?
  • 是的;我想获取位置。

标签: visual-c++ com


【解决方案1】:

这里有一段代码可以将它转储出去。孩子的IPropertyStore没有返回这些,不知道为什么,所以我们要使用old IShellFolder2::GetDetailsEx method 具有特殊的列 ID(与 PROPERTYKEY 相同)。

CComPtr<IShellItem> cpl;
CComPtr<IShellFolder2> folder;
CComPtr<IEnumShellItems> enumerator;
PROPERTYKEY pkLocation;
SHCreateItemFromParsingName(L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", nullptr, IID_PPV_ARGS(&cpl));

// bind to IShellFolder
cpl->BindToHandler(NULL, BHID_SFObject, IID_PPV_ARGS(&folder));

// bind to IEnumShellItems
cpl->BindToHandler(NULL, BHID_EnumItems, IID_PPV_ARGS(&enumerator));

// get this property key's value
PSGetPropertyKeyFromName(L"System.Software.InstallLocation", &pkLocation);

for (CComPtr<IShellItem> child; enumerator->Next(1, &child, nullptr) == S_OK; child.Release())
{
    // get child's display name
    CComHeapPtr<wchar_t> name;
    child->GetDisplayName(SIGDN_NORMALDISPLAY, &name);
    wprintf(L"%s\n", name);

    // get child's PIDL
    CComHeapPtr<ITEMIDLIST> pidl;
    SHGetIDListFromObject(child, &pidl);

    // the PIDL is absolute, we need the relative one (the last itemId in the list)
    // get it's install location
    CComVariant v;
    if (SUCCEEDED(folder->GetDetailsEx(ILFindLastID(pidl), &pkLocation, &v)))
    {
        // it's a VT_BSTR
        wprintf(L" %s\n", v.bstrVal);
    }
}

请注意,它使用的是未记录的System.Software.InstallLocation PROPERTYKEY。为了找到它,我只是为每个孩子用这样的代码转储了所有列:

    int iCol = 0;
    do
    {
        SHCOLUMNID colId;
        if (FAILED(folder->MapColumnToSCID(iCol, &colId)))
            break; // last column

        CComHeapPtr<wchar_t> name;
        PSGetNameFromPropertyKey(colId, &name);

        CComVariant v;
        if (SUCCEEDED(folder->GetDetailsEx(ILFindLastID(pidl), &colId, &v)))
        {
            if (v.vt == VT_BSTR)
            {
                wprintf(L" %s: %s\n", name, v.bstrVal);
            }
            else
            {
                wprintf(L" %s vt: %i\n", name, v.vt);
            }
        }

        iCol++;
    } while (true);
}

PS:我没有添加太多错误检查,但你应该这样做。

【讨论】:

  • 谢谢@Simon。 :) 只是我添加了 CoInitialize(NULL);否则 SHCreateItemFromParsingName 将返回 NULL。我添加了错误检查的任何方式,它对我来说都很好。再次感谢。 :)
  • 是的,大多数shell函数都需要COM初始化。
  • @CrazyCoder,你应该在赏金到期之前接受这个答案
猜你喜欢
  • 1970-01-01
  • 2012-10-17
  • 2018-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
相关资源
最近更新 更多