Example #1
0
/**
 * Makes sure a library named "Subversion" exists and has our template
 * set to it.
 * If the library already exists, the template is set.
 * If the library doesn't exist, it is created.
 */
void EnsureSVNLibrary(bool bCreate /* = true*/)
{
    // when running the 32-bit version of TortoiseProc on x64 OS,
    // we must not create the library! This would break
    // the library in the x64 explorer.
    BOOL bIsWow64 = FALSE;
    IsWow64Process(GetCurrentProcess(), &bIsWow64);
    if (bIsWow64)
        return;

    CComPtr<IShellLibrary> pLibrary = NULL;
    if (FAILED(OpenShellLibrary(L"Subversion", &pLibrary)))
    {
        if (!bCreate)
            return;
        if (FAILED(SHCreateLibrary(IID_PPV_ARGS(&pLibrary))))
            return;

        // Save the new library under the user's Libraries folder.
        CComPtr<IShellItem> pSavedTo = NULL;
        if (FAILED(pLibrary->SaveInKnownFolder(FOLDERID_UsersLibraries, L"Subversion", LSF_OVERRIDEEXISTING, &pSavedTo)))
            return;
    }

    if (SUCCEEDED(pLibrary->SetFolderType(IsWindows8OrGreater() ? FOLDERTYPEID_Documents : FOLDERTYPEID_SVNWC)))
    {
        // create the path for the icon
        CString path;
        CString appDir = CPathUtils::GetAppDirectory();
        if (appDir.GetLength() < MAX_PATH)
        {
            TCHAR buf[MAX_PATH] = {0};
            PathCanonicalize(buf, (LPCTSTR)appDir);
            appDir = buf;
        }
        path.Format(L"%s%s,-%d", (LPCTSTR)appDir, L"TortoiseProc.exe", IsWin10OrLater() ? IDI_LIBRARY_WIN10 : IDI_LIBRARY);
        pLibrary->SetIcon((LPCTSTR)path);
        pLibrary->Commit();
    }
}
    // Loads the IShellLibrary interface for the specified item, calls the derived class to perform an operation on
    // the library, and commits/saves any changes as needed.
    HRESULT v_ExecuteCommand()
    {
        HRESULT hr;
        if (_fCreate)
        {
            // If we're in 'create' mode, instantiate a new IShellLibrary in memory.
            hr = SHCreateLibrary(IID_PPV_ARGS(&_plib));
        }
        else
        {
            // Otherwise, load it from the specified IShellItem.
            const DWORD grfMode = _fReadOnly ? (STGM_READ | STGM_SHARE_DENY_WRITE) : (STGM_READWRITE | STGM_SHARE_EXCLUSIVE);
            hr = SHLoadLibraryFromItem(_psiLibrary, grfMode, IID_PPV_ARGS(&_plib));
        }

        if (SUCCEEDED(hr))
        {
            // Call the derived class to execute the operation on the library.
            hr = v_ExecuteLibCommand();
            if (SUCCEEDED(hr) && !_fReadOnly)
            {
                if (_fCreate)
                {
                    // We created a new library in memory; now save it to disk.
                    // The IShellLibrary::Save API takes the destination in the form of the parent folder, and the name
                    // of the library (without any file extension).  However, the argument is in the form of a full file
                    // system path, possibly including the extension.  So, we need to parse it into that form.  For example:
                    //   "C:\some\folder\stuff.library-ms" => "C:\some\folder", "stuff"
                    PWSTR pszName = PathFindFileNameW(_pszSavePath);
                    if (StrCmpICW(PathFindExtensionW(pszName), L".library-ms") == 0)
                    {
                        PathRemoveExtensionW(pszName);
                    }
                    PathRemoveFileSpec(_pszSavePath);

                    // Save the library with the specified name in the specified folder.
                    PWSTR pszSavedToPath;
                    hr = SHSaveLibraryInFolderPath(_plib, _pszSavePath, pszName, _lsfSaveOptions, &pszSavedToPath);
                    if (SUCCEEDED(hr))
                    {
                        // The API returns the full file system path that the library was saved to.
                        // (This may or may not match the original argument, depending on whether LSF_MAKEUNIQUENAME was specified.)
                        Output(L"Library saved to path: %s\n", pszSavedToPath);
                        CoTaskMemFree(pszSavedToPath);
                    }
                    else
                    {
                        RuntimeError(L"Error %#08x saving library to path: %s\\%s.library-ms\n", hr, _pszSavePath, pszName);
                    }
                }
                else
                {
                    // We're operating on an existing library; commit the changes to disk.
                    hr = _plib->Commit();
                    if (SUCCEEDED(hr))
                    {
                        Output(L"Changes successfully committed.\n");
                    }
                }
            }
        }
        else
        {
            RuntimeError(L"Error %#08x loading library from path: %s\n", hr, _pszSavePath);
        }
        return hr;
    }