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