Update Tortoise.pot
[TortoiseGit.git] / src / TortoiseShell / TortoiseStub.cpp
blobc0c2defa315924b5f950c93aff43dd484e1a9cdd
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2014, 2016-2019, 2021 - TortoiseGit
4 // Copyright (C) 2007, 2009, 2013-2014, 2018 - 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 <SDKDDKVer.h>
21 #include <Windows.h>
22 #include "Debug.h"
24 const HINSTANCE NIL = reinterpret_cast<HINSTANCE>((static_cast<char*>(0)-1));
26 static HINSTANCE hInst = nullptr;
28 static HINSTANCE hTortoiseGit = nullptr;
29 static LPFNGETCLASSOBJECT pDllGetClassObject = nullptr;
30 static LPFNCANUNLOADNOW pDllCanUnloadNow = nullptr;
32 static wchar_t DebugDllPath[MAX_PATH] = { 0 };
34 static BOOL DebugActive()
36 static const WCHAR TGitRootKey[] = L"Software\\TortoiseGit";
37 static const WCHAR DebugShellValue[] = L"DebugShell";
38 static const WCHAR DebugShellPathValue[] = L"DebugShellPath";
40 DWORD bDebug = 0;
42 HKEY hKey = HKEY_CURRENT_USER;
43 LONG Result = ERROR;
44 DWORD Type = REG_DWORD;
45 DWORD Len = sizeof(DWORD);
47 BOOL bDebugActive = FALSE;
50 TRACE(L"DebugActive() - Enter\n");
52 if (IsDebuggerPresent())
54 Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TGitRootKey, 0, KEY_READ, &hKey);
55 if (Result == ERROR_SUCCESS)
57 Result = RegQueryValueEx(hKey, DebugShellValue, nullptr, &Type, reinterpret_cast<BYTE*>(&bDebug), &Len);
58 if ((Result == ERROR_SUCCESS) && (Type == REG_DWORD) && (Len == sizeof(DWORD)) && bDebug)
60 TRACE(L"DebugActive() - debug active\n");
61 bDebugActive = TRUE;
62 Len = sizeof(wchar_t)*MAX_PATH;
63 Type = REG_SZ;
64 Result = RegQueryValueEx(hKey, DebugShellPathValue, nullptr, &Type, reinterpret_cast<BYTE*>(DebugDllPath), &Len);
65 if ((Result == ERROR_SUCCESS) && (Type == REG_SZ) && bDebug)
66 TRACE(L"DebugActive() - debug path set\n");
69 RegCloseKey(hKey);
72 else
74 Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TGitRootKey, 0, KEY_READ, &hKey);
75 if (Result == ERROR_SUCCESS)
77 Len = sizeof(wchar_t)*MAX_PATH;
78 Type = REG_SZ;
79 Result = RegQueryValueEx(hKey, DebugShellPathValue, nullptr, &Type, reinterpret_cast<BYTE*>(DebugDllPath), &Len);
80 if ((Result == ERROR_SUCCESS) && (Type == REG_SZ) && bDebug)
81 TRACE(L"DebugActive() - debug path set\n");
82 RegCloseKey(hKey);
86 TRACE(L"WantRealVersion() - Exit\n");
87 return bDebugActive;
90 /**
91 * \ingroup TortoiseShell
92 * Check whether to load the full TortoiseGit.dll or not.
94 static BOOL WantRealVersion()
96 static const WCHAR TGitRootKey[] = L"Software\\TortoiseGit";
97 static const WCHAR ExplorerOnlyValue[] = L"LoadDllOnlyInExplorer";
99 static const WCHAR ExplorerEnvPath[] = L"%SystemRoot%\\explorer.exe";
102 DWORD bExplorerOnly = 0;
103 WCHAR ModuleName[MAX_PATH] = {0};
105 HKEY hKey = HKEY_CURRENT_USER;
106 DWORD Type = REG_DWORD;
107 DWORD Len = sizeof(DWORD);
109 BOOL bWantReal = TRUE;
111 TRACE(L"WantRealVersion() - Enter\n");
113 LONG Result = RegOpenKeyEx(HKEY_CURRENT_USER, TGitRootKey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
114 if (Result == ERROR_SUCCESS)
116 Result = RegQueryValueEx(hKey, ExplorerOnlyValue, nullptr, &Type, reinterpret_cast<BYTE*>(&bExplorerOnly), &Len);
117 if ((Result == ERROR_SUCCESS) && (Type == REG_DWORD) && (Len == sizeof(DWORD)) && bExplorerOnly)
119 TRACE(L"WantRealVersion() - Explorer Only\n");
121 // check if the current process is in fact the explorer
122 Len = GetModuleFileName(nullptr, ModuleName, _countof(ModuleName));
123 if (Len)
125 TRACE(L"Process is %s\n", ModuleName);
127 WCHAR ExplorerPath[MAX_PATH] = {0};
128 Len = ExpandEnvironmentStrings(ExplorerEnvPath, ExplorerPath, _countof(ExplorerPath));
129 if (Len && (Len <= _countof(ExplorerPath)))
131 TRACE(L"Explorer path is %s\n", ExplorerPath);
132 bWantReal = !lstrcmpi(ModuleName, ExplorerPath);
135 // we also have to allow the verclsid.exe process - that process determines
136 // first whether the shell is allowed to even use an extension.
137 Len = lstrlen(ModuleName);
138 if ((Len > wcslen(L"\\verclsid.exe")) && (lstrcmpi(&ModuleName[Len - wcslen(L"\\verclsid.exe")], L"\\verclsid.exe") == 0))
139 bWantReal = TRUE;
143 RegCloseKey(hKey);
146 TRACE(L"WantRealVersion() - Exit\n");
147 return bWantReal;
150 static void LoadRealLibrary()
152 static const char GetClassObject[] = "DllGetClassObject";
153 static const char CanUnloadNow[] = "DllCanUnloadNow";
155 WCHAR ModuleName[MAX_PATH] = {0};
156 DWORD Len = 0;
157 HINSTANCE hUseInst = hInst;
158 DebugDllPath[0] = 0;
160 if (hTortoiseGit)
161 return;
163 if (!WantRealVersion())
165 TRACE(L"LoadRealLibrary() - Bypass\n");
166 hTortoiseGit = NIL;
167 return;
169 // if HKCU\Software\TortoiseGit\DebugShell is set, load the dlls from the location of the current process
170 // which is for our debug purposes an instance of usually TortoiseProc. That way we can force the load
171 // of the debug dlls.
172 if (DebugActive())
173 hUseInst = nullptr;
174 Len = GetModuleFileName(hUseInst, ModuleName, _countof(ModuleName));
175 if (!Len)
177 TRACE(L"LoadRealLibrary() - Fail\n");
178 hTortoiseGit = NIL;
179 return;
182 // truncate the string at the last '\' char
183 while(Len > 0)
185 --Len;
186 if (ModuleName[Len] == '\\')
188 ModuleName[Len] = L'\0';
189 break;
192 if (Len == 0)
194 TRACE(L"LoadRealLibrary() - Fail\n");
195 hTortoiseGit = NIL;
196 return;
198 #ifdef _WIN64
199 lstrcat(ModuleName, L"\\TortoiseGit.dll");
200 #else
201 lstrcat(ModuleName, L"\\TortoiseGit32.dll");
202 #endif
203 if (DebugDllPath[0])
204 lstrcpy(ModuleName, DebugDllPath);
205 TRACE(L"LoadRealLibrary() - Load %s\n", ModuleName);
207 hTortoiseGit = LoadLibraryEx(ModuleName, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
208 if (!hTortoiseGit)
210 TRACE(L"LoadRealLibrary() - Fail\n");
211 hTortoiseGit = NIL;
212 return;
215 TRACE(L"LoadRealLibrary() - Success\n");
216 pDllGetClassObject = nullptr;
217 pDllCanUnloadNow = nullptr;
218 pDllGetClassObject = reinterpret_cast<LPFNGETCLASSOBJECT>(GetProcAddress(hTortoiseGit, GetClassObject));
219 if (!pDllGetClassObject)
221 TRACE(L"LoadRealLibrary() - Fail\n");
222 FreeLibrary(hTortoiseGit);
223 hTortoiseGit = NIL;
224 return;
226 pDllCanUnloadNow = reinterpret_cast<LPFNCANUNLOADNOW>(GetProcAddress(hTortoiseGit, CanUnloadNow));
227 if (!pDllCanUnloadNow)
229 TRACE(L"LoadRealLibrary() - Fail\n");
230 FreeLibrary(hTortoiseGit);
231 hTortoiseGit = NIL;
232 return;
236 static void UnloadRealLibrary()
238 if (!hTortoiseGit)
239 return;
241 if (hTortoiseGit != NIL)
242 FreeLibrary(hTortoiseGit);
244 hTortoiseGit = nullptr;
245 pDllGetClassObject = nullptr;
246 pDllCanUnloadNow = nullptr;
249 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID /*Reserved*/)
251 #ifdef _DEBUG
252 // if no debugger is present, then don't load the dll.
253 // this prevents other apps from loading the dll and locking
254 // it.
256 BOOL bInShellTest = FALSE;
257 wchar_t buf[MAX_PATH + 1] = {0}; // MAX_PATH ok, the test really is for debugging anyway.
258 DWORD pathLength = GetModuleFileName(nullptr, buf, _countof(buf) - 1);
260 if (pathLength >= 14)
262 if ((lstrcmpi(&buf[pathLength-14], L"\\ShellTest.exe")) == 0)
264 bInShellTest = TRUE;
266 if ((_wcsicmp(&buf[pathLength-13], L"\\verclsid.exe")) == 0)
268 bInShellTest = TRUE;
272 if (!IsDebuggerPresent() && !bInShellTest)
274 TRACE(L"In debug load preventer\n");
275 return FALSE;
277 #endif
279 switch(Reason)
281 case DLL_PROCESS_ATTACH:
282 hInst = hInstance;
283 DebugDllPath[0] = 0;
284 break;
286 /*case DLL_THREAD_ATTACH:
287 break;
289 case DLL_THREAD_DETACH:
290 break;
292 case DLL_PROCESS_DETACH:
293 break;*/
296 return TRUE;
299 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
301 TRACE(L"DllGetClassObject() - Enter\n");
303 LoadRealLibrary();
304 if (!pDllGetClassObject)
306 if (ppv)
307 *ppv = nullptr;
309 TRACE(L"DllGetClassObject() - Bypass\n");
310 return CLASS_E_CLASSNOTAVAILABLE;
313 TRACE(L"DllGetClassObject() - Forward\n");
314 return pDllGetClassObject(rclsid, riid, ppv);
317 STDAPI DllCanUnloadNow()
319 TRACE(L"DllCanUnloadNow() - Enter\n");
321 if (pDllCanUnloadNow)
323 TRACE(L"DllCanUnloadNow() - Forward\n");
324 HRESULT Result = pDllCanUnloadNow();
325 if (Result != S_OK)
326 return Result;
329 TRACE(L"DllCanUnloadNow() - Unload\n");
330 UnloadRealLibrary();
331 return S_OK;