1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2014 - TortoiseGit
4 // Copyright (C) 2007, 2009, 2013-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 "../targetver.h"
25 const HINSTANCE NIL
= (HINSTANCE
)((char*)(0)-1);
27 static HINSTANCE hInst
= NULL
;
29 static HINSTANCE hTortoiseGit
= NULL
;
30 static LPFNGETCLASSOBJECT pDllGetClassObject
= NULL
;
31 static LPFNCANUNLOADNOW pDllCanUnloadNow
= NULL
;
33 static BOOL
DebugActive(void)
35 static const WCHAR TGitRootKey
[]=_T("Software\\TortoiseGit");
36 static const WCHAR ExplorerOnlyValue
[]=_T("DebugShell");
40 HKEY hKey
= HKEY_CURRENT_USER
;
42 DWORD Type
= REG_DWORD
;
43 DWORD Len
= sizeof(DWORD
);
45 BOOL bDebugActive
= FALSE
;
48 TRACE(_T("DebugActive() - Enter\n"));
50 if (IsDebuggerPresent())
52 Result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, TGitRootKey
, 0, KEY_READ
, &hKey
);
53 if (Result
== ERROR_SUCCESS
)
55 Result
= RegQueryValueEx(hKey
, ExplorerOnlyValue
, NULL
, &Type
, (BYTE
*)&bDebug
, &Len
);
56 if ((Result
== ERROR_SUCCESS
) && (Type
== REG_DWORD
) && (Len
== sizeof(DWORD
)) && bDebug
)
58 TRACE(_T("DebugActive() - debug active\n"));
66 TRACE(_T("WantRealVersion() - Exit\n"));
71 * \ingroup TortoiseShell
72 * Check whether to load the full TortoiseGit.dll or not.
74 static BOOL
WantRealVersion(void)
76 static const WCHAR TGitRootKey
[]=_T("Software\\TortoiseGit");
77 static const WCHAR ExplorerOnlyValue
[]=_T("LoadDllOnlyInExplorer");
79 static const WCHAR ExplorerEnvPath
[]=_T("%SystemRoot%\\explorer.exe");
82 DWORD bExplorerOnly
= 0;
83 WCHAR ModuleName
[MAX_PATH
] = {0};
85 HKEY hKey
= HKEY_CURRENT_USER
;
87 DWORD Type
= REG_DWORD
;
88 DWORD Len
= sizeof(DWORD
);
90 BOOL bWantReal
= TRUE
;
92 TRACE(_T("WantRealVersion() - Enter\n"));
94 Result
= RegOpenKeyEx(HKEY_CURRENT_USER
, TGitRootKey
, 0, KEY_READ
, &hKey
);
95 if (Result
== ERROR_SUCCESS
)
97 Result
= RegQueryValueEx(hKey
, ExplorerOnlyValue
, NULL
, &Type
, (BYTE
*)&bExplorerOnly
, &Len
);
98 if ((Result
== ERROR_SUCCESS
) && (Type
== REG_DWORD
) && (Len
== sizeof(DWORD
)) && bExplorerOnly
)
100 TRACE(_T("WantRealVersion() - Explorer Only\n"));
102 // check if the current process is in fact the explorer
103 Len
= GetModuleFileName(NULL
, ModuleName
, _countof(ModuleName
));
106 TRACE(_T("Process is %s\n"), ModuleName
);
108 WCHAR ExplorerPath
[MAX_PATH
] = {0};
109 Len
= ExpandEnvironmentStrings(ExplorerEnvPath
, ExplorerPath
, _countof(ExplorerPath
));
110 if (Len
&& (Len
<= _countof(ExplorerPath
)))
112 TRACE(_T("Explorer path is %s\n"), ExplorerPath
);
113 bWantReal
= !lstrcmpi(ModuleName
, ExplorerPath
);
116 // we also have to allow the verclsid.exe process - that process determines
117 // first whether the shell is allowed to even use an extension.
118 Len
= lstrlen(ModuleName
);
119 if ((Len
> 13)&&(lstrcmpi(&ModuleName
[Len
-13], _T("\\verclsid.exe")) == 0))
127 TRACE(_T("WantRealVersion() - Exit\n"));
131 static void LoadRealLibrary(void)
133 static const char GetClassObject
[] = "DllGetClassObject";
134 static const char CanUnloadNow
[] = "DllCanUnloadNow";
136 WCHAR ModuleName
[MAX_PATH
] = {0};
138 HINSTANCE hUseInst
= hInst
;
143 if (!WantRealVersion())
145 TRACE(_T("LoadRealLibrary() - Bypass\n"));
149 // if HKCU\Software\TortoiseGit\DebugShell is set, load the dlls from the location of the current process
150 // which is for our debug purposes an instance of usually TortoiseProc. That way we can force the load
151 // of the debug dlls.
154 Len
= GetModuleFileName(hUseInst
, ModuleName
, _countof(ModuleName
));
157 TRACE(_T("LoadRealLibrary() - Fail\n"));
162 // truncate the string at the last '\' char
166 if (ModuleName
[Len
] == '\\')
168 ModuleName
[Len
] = '\0';
174 TRACE(_T("LoadRealLibrary() - Fail\n"));
179 lstrcat(ModuleName
, _T("\\TortoiseGit.dll"));
181 lstrcat(ModuleName
, _T("\\TortoiseGit32.dll"));
183 TRACE(_T("LoadRealLibrary() - Load %s\n"), ModuleName
);
185 hTortoiseGit
= LoadLibraryEx(ModuleName
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
188 TRACE(_T("LoadRealLibrary() - Fail\n"));
193 TRACE(_T("LoadRealLibrary() - Success\n"));
194 pDllGetClassObject
= NULL
;
195 pDllCanUnloadNow
= NULL
;
196 pDllGetClassObject
= (LPFNGETCLASSOBJECT
)GetProcAddress(hTortoiseGit
, GetClassObject
);
197 if (pDllGetClassObject
== NULL
)
199 TRACE(_T("LoadRealLibrary() - Fail\n"));
200 FreeLibrary(hTortoiseGit
);
204 pDllCanUnloadNow
= (LPFNCANUNLOADNOW
)GetProcAddress(hTortoiseGit
, CanUnloadNow
);
205 if (pDllCanUnloadNow
== NULL
)
207 TRACE(_T("LoadRealLibrary() - Fail\n"));
208 FreeLibrary(hTortoiseGit
);
214 static void UnloadRealLibrary(void)
219 if (hTortoiseGit
!= NIL
)
220 FreeLibrary(hTortoiseGit
);
223 pDllGetClassObject
= NULL
;
224 pDllCanUnloadNow
= NULL
;
227 BOOL WINAPI
DllMain(HINSTANCE hInstance
, DWORD Reason
, LPVOID
/*Reserved*/)
230 // if no debugger is present, then don't load the dll.
231 // this prevents other apps from loading the dll and locking
234 BOOL bInShellTest
= FALSE
;
235 TCHAR buf
[MAX_PATH
+ 1] = {0}; // MAX_PATH ok, the test really is for debugging anyway.
236 DWORD pathLength
= GetModuleFileName(NULL
, buf
, MAX_PATH
);
238 if (pathLength
>= 14)
240 if ((lstrcmpi(&buf
[pathLength
-14], _T("\\ShellTest.exe"))) == 0)
244 if ((_tcsicmp(&buf
[pathLength
-13], _T("\\verclsid.exe"))) == 0)
250 if (!IsDebuggerPresent() && !bInShellTest
)
252 TRACE(_T("In debug load preventer\n"));
259 case DLL_PROCESS_ATTACH
:
263 /*case DLL_THREAD_ATTACH:
266 case DLL_THREAD_DETACH:
269 case DLL_PROCESS_DETACH:
276 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
278 TRACE(_T("DllGetClassObject() - Enter\n"));
281 if (!pDllGetClassObject
)
286 TRACE(_T("DllGetClassObject() - Bypass\n"));
287 return CLASS_E_CLASSNOTAVAILABLE
;
290 TRACE(_T("DllGetClassObject() - Forward\n"));
291 return pDllGetClassObject(rclsid
, riid
, ppv
);
294 STDAPI
DllCanUnloadNow(void)
296 TRACE(_T("DllCanUnloadNow() - Enter\n"));
298 if (pDllCanUnloadNow
)
300 TRACE(_T("DllCanUnloadNow() - Forward\n"));
301 HRESULT Result
= pDllCanUnloadNow();
306 TRACE(_T("DllCanUnloadNow() - Unload\n"));