如何在 Windows 7 上的 C++ 中为虚拟文件夹创建快捷方式?

Posted

技术标签:

【中文标题】如何在 Windows 7 上的 C++ 中为虚拟文件夹创建快捷方式?【英文标题】:How to create shortcut for virtual folder in C++ on windows 7? 【发布时间】:2017-10-26 18:14:13 【问题描述】:

我使用的平台是windows 7。我需要为windows 7上的虚拟文件夹创建快捷方式。 我使用 windows 7 SDK 示例在 Computer 下创建一个虚拟文件夹:

示例项目名称为ExplorerDataProvider,它定义了 IShellFolder 类的 CLSID:

// add classes supported by this module here
const CLASS_OBJECT_INIT c_rgClassObjectInit[] =

 &CLSID_FolderViewImpl,            CFolderViewImplFolder_CreateInstance ,
 &CLSID_FolderViewImplContextMenu,CFolderViewImplContextMenu_CreateInstance ,
;

CFolderViewImplFolder_CreateInstance 的定义是:

HRESULT CFolderViewImplFolder_CreateInstance(REFIID riid, void **ppv)

*ppv = NULL;
CFolderViewImplFolder* pFolderViewImplShellFolder = new (std::nothrow) CFolderViewImplFolder(0);
HRESULT hr = pFolderViewImplShellFolder ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))

    hr = pFolderViewImplShellFolder->QueryInterface(riid, ppv);
    pFolderViewImplShellFolder->Release();

return hr;

CFolderViewImplFolder 实现IShellFolder2 amd IPersistFolder2。 我在这里找到了一个用于为打印机创建快捷方式的类似代码: https://www.codeproject.com/Articles/596642/Creating-a-shortcut-programmatically-in-Cplusplus 并且在 https://msdn.microsoft.com/en-us/library/aa969393.aspx#Shellink_Item_Identifiers

一旦获得了 IShellFolder 的类标识符,就可以调用 CoCreateInstance 函数来检索接口的地址。然后您可以调用该接口来枚举文件夹中的对象并检索您正在搜索的对象的项目标识符的地址。最后,您可以在调用 IShellLink::SetIDList 成员函数时使用该地址来创建对象的快捷方式。

我修改了

hr = SHGetMalloc(&pMalloc);
hr = SHGetDesktopFolder( &pDesktopFolder );
hr = SHGetSpecialFolderLocation( NULL, CSIDL_PRINTERS, &netItemIdLst );
hr = pDesktopFolder->BindToObject( netItemIdLst, NULL, IID_IShellFolder, (void **)&pPrinterFolder );

// testFolder is the CLSID for the virtual folder implementation
hr = CoCreateInstance(testFolder, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder, (LPVOID*)&pVirtualFolder);

hr = CoCreateInstance(testFolder, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder2, (LPVOID*)&pVirtualFolder);

但是pVirtualFolder还是NULL,打印出“找不到对应的接口”。

CoCreateInstance 使用时有什么问题吗?或者我不应该使用这个解决方案?有没有示例代码?

【问题讨论】:

简短回答:你不能在 C++ 中做到这一点。您可以使用特定于操作系统/平台的 API 来执行此操作,但是您应该指定您拥有的操作系​​统、平台以及您希望使用的 API。 windows 7. 这就是你要问的吗? 您不应该直接使用 CoCreateInstance。让 shell 来做吧。 @DenisAnisimov 不明白。你能解释一下吗?还是一些代码?你是什​​么意思让shell来做? 我要求正确地提出问题,而不是提供必要的信息作为评论。您的问题可以并且应该用于其他人解决类似问题。目前听起来像是“我如何使用汽车赚钱?”你有卡车吗?你想把它出租吗?等 【参考方案1】:

要创建快捷方式,您可以使用official documentation。下面是一个示例代码,它为“这台电脑”的子代(又名:ComputerFolder)创建快捷方式

int main()

    CoInitialize(NULL);
    // I've used my Apple's iCloud as an example (name is in french)
    // it's a virtual folder, a shell namespace extension
    HRESULT hr = CreateComputerChildShortCut(L"Photos iCloud", L"c:\\temp\\my icloud");
    printf("hr:0x%08X\n", hr);
    CoUninitialize();
    return 0;


HRESULT CreateComputerChildShortCut(LPWSTR childDisplayName, LPWSTR path)

    // get My Computer folder's ShellItem (there are other ways for this...)
    CComPtr<IShellItem> folder;
    HRESULT hr = SHCreateItemInKnownFolder(FOLDERID_ComputerFolder, 0, NULL, IID_PPV_ARGS(&folder));
    if (FAILED(hr)) return hr;

    // enumerate children
    CComPtr<IEnumShellItems> items;
    hr = folder->BindToHandler(NULL, BHID_EnumItems, IID_PPV_ARGS(&items));
    if (FAILED(hr)) return hr;

    for (CComPtr<IShellItem> item; items->Next(1, &item, NULL) == S_OK; item.Release())
    
        // get parsing path (if's often useful)
        CComHeapPtr<wchar_t> parsingPath;
        item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &parsingPath);
        wprintf(L"Path: %s\n", parsingPath);

        // get display name
        CComHeapPtr<wchar_t> displayName;
        item->GetDisplayName(SIGDN_NORMALDISPLAY, &displayName);
        wprintf(L" Name: %s\n", displayName);

        if (!lstrcmpi(childDisplayName, displayName))
        
            // get pidl
            // it's the unambiguous way of referencing a shell thing
            CComHeapPtr<ITEMIDLIST> pidl;
            hr = SHGetIDListFromObject(item, &pidl);
            if (FAILED(hr)) return hr;

            // create an instance of the standard Shell's folder shortcut creator
            CComPtr<IShellLink> link;
            hr = link.CoCreateInstance(CLSID_FolderShortcut);
            if (FAILED(hr)) return hr;

            // just use the pidl
            hr = link->SetIDList(pidl);
            if (FAILED(hr)) return hr;

            CComPtr<IPersistFile> file;
            hr = link->QueryInterface(&file);
            if (FAILED(hr)) return hr;

            // save the shortcut (we could also change other IShellLink parameters)
            hr = file->Save(path, FALSE);
            if (FAILED(hr)) return hr;
            break;
        
    
    return S_OK;

当然,如果你知道绝对解析路径或绝对pidl,你就不必枚举任何东西,这只是为了演示目的。

【讨论】:

以上是关于如何在 Windows 7 上的 C++ 中为虚拟文件夹创建快捷方式?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中为 Windows 编写屏幕保护程序?

如何在 Linux 上的 C++ 程序中使用共享库(在本例中为 JsonCpp)?

在 C++ 中为 Windows CE 在 Linux 中开发

如何像处理语言一样轻松地在 c++ 中为 windows 和 linux 绘制原始像素? [关闭]

如何从 Windows 上的 c++ 控制台应用程序打印 UTF-8

Windows 7 上的 C++ 内存泄漏