1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2023 - TortoiseGit
4 // Copyright (C) 2003-2014 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
27 #include "ShellObjects.h"
28 #include "../version.h"
29 #include "I18NHelper.h"
30 #include "GitAdminDir.h"
33 extern ShellObjects g_shellObjects
;
35 // *********************** CShellExt *************************
36 CShellExt::CShellExt(FileState state
)
38 ,regDiffLater(L
"Software\\TortoiseGit\\DiffLater", L
"")
40 InterlockedIncrement(&g_cRefThisDll
);
43 AutoLocker
lock(g_csGlobalCOMGuard
);
44 g_shellObjects
.Insert(this);
47 INITCOMMONCONTROLSEX used
= {
48 sizeof(INITCOMMONCONTROLSEX
),
49 ICC_LISTVIEW_CLASSES
| ICC_WIN95_CLASSES
| ICC_BAR_CLASSES
| ICC_USEREX_CLASSES
51 InitCommonControlsEx(&used
);
55 CShellExt::~CShellExt()
57 AutoLocker
lock(g_csGlobalCOMGuard
);
58 InterlockedDecrement(&g_cRefThisDll
);
59 g_shellObjects
.Erase(this);
64 if (g_langid
!= g_ShellCache
.GetLangID() && (g_langTimeout
== 0 || g_langTimeout
< GetTickCount64()))
66 g_langid
= g_ShellCache
.GetLangID();
67 DWORD langId
= g_langid
;
68 wchar_t langDll
[MAX_PATH
* 4] = { 0 };
69 HINSTANCE hInst
= nullptr;
70 wchar_t langdir
[MAX_PATH
] = { 0 };
71 if (GetModuleFileName(g_hmodThisDll
, langdir
, _countof(langdir
))==0)
73 wchar_t* dirpoint
= wcsrchr(langdir
, L
'\\');
76 dirpoint
= wcsrchr(langdir
, L
'\\');
81 IsWow64Process(GetCurrentProcess(), &bIsWow
);
86 swprintf_s(langDll
, L
"%s\\Languages\\TortoiseProc32%lu.dll", langdir
, langId
);
88 swprintf_s(langDll
, L
"%s\\Languages\\TortoiseProc%lu.dll", langdir
, langId
);
89 if (CI18NHelper::DoVersionStringsMatch(CPathUtils::GetVersionFromFile(langDll
), _T(STRPRODUCTVER
)))
90 hInst
= LoadLibrary(langDll
);
93 if (g_hResInst
!= g_hmodThisDll
)
94 FreeLibrary(g_hResInst
);
99 DWORD lid
= SUBLANGID(langId
);
102 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
106 } while (!hInst
&& langId
!= 0);
109 // either the dll for the selected language is not present, or
110 // it is the wrong version.
111 // fall back to English and set a timeout so we don't retry
112 // to load the language dll too often
113 if (g_hResInst
!= g_hmodThisDll
)
114 FreeLibrary(g_hResInst
);
115 g_hResInst
= g_hmodThisDll
;
117 // set a timeout of 10 seconds
118 if (g_ShellCache
.GetLangID() != 1033)
119 g_langTimeout
= GetTickCount64() + 10000;
123 } // if (g_langid != g_ShellCache.GetLangID())
126 STDMETHODIMP
CShellExt::QueryInterface(REFIID riid
, LPVOID FAR
*ppv
)
133 if (IsEqualIID(riid
, IID_IShellExtInit
) || IsEqualIID(riid
, IID_IUnknown
))
134 *ppv
= static_cast<LPSHELLEXTINIT
>(this);
135 else if (IsEqualIID(riid
, IID_IContextMenu
))
136 *ppv
= static_cast<LPCONTEXTMENU
>(this);
137 else if (IsEqualIID(riid
, IID_IContextMenu2
))
138 *ppv
= static_cast<LPCONTEXTMENU2
>(this);
139 else if (IsEqualIID(riid
, IID_IContextMenu3
))
140 *ppv
= static_cast<LPCONTEXTMENU3
>(this);
141 else if (IsEqualIID(riid
, IID_IShellIconOverlayIdentifier
))
142 *ppv
= static_cast<IShellIconOverlayIdentifier
*>(this);
143 else if (IsEqualIID(riid
, IID_IShellPropSheetExt
))
144 *ppv
= static_cast<LPSHELLPROPSHEETEXT
>(this);
145 else if (IsEqualIID(riid
, IID_IShellCopyHook
))
146 *ppv
= static_cast<ICopyHook
*>(this);
147 else if (IsEqualIID(riid
, IID_IExplorerCommand
))
148 *ppv
= static_cast<IExplorerCommand
*>(this);
149 else if (IsEqualIID(riid
, IID_IObjectWithSite
))
150 *ppv
= static_cast<IObjectWithSite
*>(this);
152 return E_NOINTERFACE
;
158 STDMETHODIMP_(ULONG
) CShellExt::AddRef()
160 return InterlockedIncrement(&m_cRef
);
163 STDMETHODIMP_(ULONG
) CShellExt::Release()
165 if (InterlockedDecrement(&m_cRef
))
173 // IPersistFile members
174 STDMETHODIMP
CShellExt::GetClassID(CLSID
*pclsid
)
178 *pclsid
= CLSID_Tortoisegit_UNCONTROLLED
;
182 STDMETHODIMP
CShellExt::Load(LPCOLESTR
/*pszFileName*/, DWORD
/*dwMode*/)
188 UINT __stdcall
CShellExt::CopyCallback(HWND
/*hWnd*/, UINT wFunc
, UINT
/*wFlags*/, LPCWSTR pszSrcFile
, DWORD
/*dwSrcAttribs*/, LPCWSTR
/*pszDestFile*/, DWORD
/*dwDestAttribs*/)
195 if (pszSrcFile
&& pszSrcFile
[0] && g_ShellCache
.IsPathAllowed(pszSrcFile
))
197 const auto cacheType
= g_ShellCache
.GetCacheType();
200 case ShellCache::exe
:
201 m_remoteCacheLink
.ReleaseLockForPath(CTGitPath(pszSrcFile
));
203 case ShellCache::dll
:
204 case ShellCache::dllFull
:
207 if (GitAdminDir::HasAdminDir(pszSrcFile
, &topDir
))
208 m_CachedStatus
.m_GitStatus
.ReleasePath(topDir
);
220 // we could now wait a little bit to give the cache time to release the handles.
221 // but the explorer/shell already retries any action for about two seconds
222 // if it first fails. So if the cache hasn't released the handle yet, the explorer
223 // will retry anyway, so we just leave here immediately.
228 HRESULT __stdcall
CShellExt::SetSite(IUnknown
* pUnkSite
)
234 HRESULT __stdcall
CShellExt::GetSite(REFIID riid
, void** ppvSite
)
236 return m_site
.CopyTo(riid
, ppvSite
);