How to create shortcut for virtual folder in C++ on windows 7?

流过昼夜 提交于 2021-01-29 08:44:35

问题


The platform I am using is windows 7. I need to create shortcut for the virtual folder on windows 7. I use windows 7 SDK sample to create a virtual folder under Computer:

The sample project name is called ExplorerDataProvider, it defines the CLSID for the IShellFolder class:

// add classes supported by this module here
const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
{
{ &CLSID_FolderViewImpl,            CFolderViewImplFolder_CreateInstance },
{ &CLSID_FolderViewImplContextMenu,CFolderViewImplContextMenu_CreateInstance },
};

The definition for CFolderViewImplFolder_CreateInstance is:

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

And the CFolderViewImplFolder implement IShellFolder2 amd IPersistFolder2. I found a similar code which is used to create shortcut for printer here: https://www.codeproject.com/Articles/596642/Creating-a-shortcut-programmatically-in-Cplusplus and in https://msdn.microsoft.com/en-us/library/aa969393.aspx#Shellink_Item_Identifiers

Once you have the class identifier for IShellFolder, you can call the CoCreateInstance function to retrieve the address of the interface. Then you can call the interface to enumerate the objects in the folder and retrieve the address of the item identifier for the object that you are searching for. Finally, you can use the address in a call to the IShellLink::SetIDList member function to create a shortcut to the object.

I revised

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

to

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

or

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

But the pVirtualFolder is still NULL, and it prints that "cannot find the corresponding interface".

Is there anything wrong with CoCreateInstance when I use it ? Or I shouldn't use this solution ? Any sample code for it ?


回答1:


To create a shortcut, you can use the official documentation. Here is a sample code that creates a shortcut for a children of "This PC" (aka: 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;
}

Of course, if you know an absolute parsing path or an absolute pidl, you don't have to enumerate anything, this was just for demonstration purposes.



来源:https://stackoverflow.com/questions/46961149/how-to-create-shortcut-for-virtual-folder-in-c-on-windows-7

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!