Apply backgroundcolors.patch
[TortoiseGit.git] / src / TortoiseShell / ShellExt.cpp
blobf5e2c500b7fd1d2aa107e4920e4829a1344e4f61
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.
20 #include "stdafx.h"
22 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
23 #include <initguid.h>
24 #include "Guids.h"
26 #include "ShellExt.h"
27 #include "ShellObjects.h"
28 #include "../version.h"
29 #include "I18NHelper.h"
30 #include "GitAdminDir.h"
31 #undef swprintf
33 extern ShellObjects g_shellObjects;
35 // *********************** CShellExt *************************
36 CShellExt::CShellExt(FileState state)
37 : m_State(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);
52 LoadLangDll();
55 CShellExt::~CShellExt()
57 AutoLocker lock(g_csGlobalCOMGuard);
58 InterlockedDecrement(&g_cRefThisDll);
59 g_shellObjects.Erase(this);
62 void LoadLangDll()
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)
72 return;
73 wchar_t* dirpoint = wcsrchr(langdir, L'\\');
74 if (dirpoint)
75 *dirpoint = L'\0';
76 dirpoint = wcsrchr(langdir, L'\\');
77 if (dirpoint)
78 *dirpoint = L'\0';
80 BOOL bIsWow = FALSE;
81 IsWow64Process(GetCurrentProcess(), &bIsWow);
85 if (bIsWow)
86 swprintf_s(langDll, L"%s\\Languages\\TortoiseProc32%lu.dll", langdir, langId);
87 else
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);
91 if (hInst)
93 if (g_hResInst != g_hmodThisDll)
94 FreeLibrary(g_hResInst);
95 g_hResInst = hInst;
97 else
99 DWORD lid = SUBLANGID(langId);
100 lid--;
101 if (lid > 0)
102 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
103 else
104 langId = 0;
106 } while (!hInst && langId != 0);
107 if (!hInst)
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;
116 g_langid = 1033;
117 // set a timeout of 10 seconds
118 if (g_ShellCache.GetLangID() != 1033)
119 g_langTimeout = GetTickCount64() + 10000;
121 else
122 g_langTimeout = 0;
123 } // if (g_langid != g_ShellCache.GetLangID())
126 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
128 if (!ppv)
129 return E_POINTER;
131 *ppv = nullptr;
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);
151 else
152 return E_NOINTERFACE;
154 AddRef();
155 return S_OK;
158 STDMETHODIMP_(ULONG) CShellExt::AddRef()
160 return InterlockedIncrement(&m_cRef);
163 STDMETHODIMP_(ULONG) CShellExt::Release()
165 if (InterlockedDecrement(&m_cRef))
166 return m_cRef;
168 delete this;
170 return 0L;
173 // IPersistFile members
174 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid)
176 if (!pclsid)
177 return E_POINTER;
178 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
179 return S_OK;
182 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
184 return S_OK;
187 // ICopyHook member
188 UINT __stdcall CShellExt::CopyCallback(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCWSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCWSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
190 switch (wFunc)
192 case FO_MOVE:
193 case FO_DELETE:
194 case FO_RENAME:
195 if (pszSrcFile && pszSrcFile[0] && g_ShellCache.IsPathAllowed(pszSrcFile))
197 const auto cacheType = g_ShellCache.GetCacheType();
198 switch (cacheType)
200 case ShellCache::exe:
201 m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile));
202 break;
203 case ShellCache::dll:
204 case ShellCache::dllFull:
206 CString topDir;
207 if (GitAdminDir::HasAdminDir(pszSrcFile, &topDir))
208 m_CachedStatus.m_GitStatus.ReleasePath(topDir);
209 break;
211 default:
212 break;
215 break;
216 default:
217 break;
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.
224 return IDYES;
227 // IObjectWithSite
228 HRESULT __stdcall CShellExt::SetSite(IUnknown* pUnkSite)
230 m_site = pUnkSite;
231 return S_OK;
234 HRESULT __stdcall CShellExt::GetSite(REFIID riid, void** ppvSite)
236 return m_site.CopyTo(riid, ppvSite);