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>
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";
42 HKEY hKey
= HKEY_CURRENT_USER
;
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");
62 Len
= sizeof(wchar_t)*MAX_PATH
;
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");
74 Result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, TGitRootKey
, 0, KEY_READ
, &hKey
);
75 if (Result
== ERROR_SUCCESS
)
77 Len
= sizeof(wchar_t)*MAX_PATH
;
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");
86 TRACE(L
"WantRealVersion() - Exit\n");
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
));
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))
146 TRACE(L
"WantRealVersion() - Exit\n");
150 static void LoadRealLibrary()
152 static const char GetClassObject
[] = "DllGetClassObject";
153 static const char CanUnloadNow
[] = "DllCanUnloadNow";
155 WCHAR ModuleName
[MAX_PATH
] = {0};
157 HINSTANCE hUseInst
= hInst
;
163 if (!WantRealVersion())
165 TRACE(L
"LoadRealLibrary() - Bypass\n");
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.
174 Len
= GetModuleFileName(hUseInst
, ModuleName
, _countof(ModuleName
));
177 TRACE(L
"LoadRealLibrary() - Fail\n");
182 // truncate the string at the last '\' char
186 if (ModuleName
[Len
] == '\\')
188 ModuleName
[Len
] = L
'\0';
194 TRACE(L
"LoadRealLibrary() - Fail\n");
199 lstrcat(ModuleName
, L
"\\TortoiseGit.dll");
201 lstrcat(ModuleName
, L
"\\TortoiseGit32.dll");
204 lstrcpy(ModuleName
, DebugDllPath
);
205 TRACE(L
"LoadRealLibrary() - Load %s\n", ModuleName
);
207 hTortoiseGit
= LoadLibraryEx(ModuleName
, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH
);
210 TRACE(L
"LoadRealLibrary() - Fail\n");
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
);
226 pDllCanUnloadNow
= reinterpret_cast<LPFNCANUNLOADNOW
>(GetProcAddress(hTortoiseGit
, CanUnloadNow
));
227 if (!pDllCanUnloadNow
)
229 TRACE(L
"LoadRealLibrary() - Fail\n");
230 FreeLibrary(hTortoiseGit
);
236 static void UnloadRealLibrary()
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*/)
252 // if no debugger is present, then don't load the dll.
253 // this prevents other apps from loading the dll and locking
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)
266 if ((_wcsicmp(&buf
[pathLength
-13], L
"\\verclsid.exe")) == 0)
272 if (!IsDebuggerPresent() && !bInShellTest
)
274 TRACE(L
"In debug load preventer\n");
281 case DLL_PROCESS_ATTACH
:
286 /*case DLL_THREAD_ATTACH:
289 case DLL_THREAD_DETACH:
292 case DLL_PROCESS_DETACH:
299 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
301 TRACE(L
"DllGetClassObject() - Enter\n");
304 if (!pDllGetClassObject
)
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();
329 TRACE(L
"DllCanUnloadNow() - Unload\n");