Don't set an exception filter for the shell extension
[TortoiseGit.git] / src / TortoiseShell / ShellExt.cpp
blob45a49278911fa13fb4ba127d33e933c2c68294c4
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2018 - 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 "GitAdminDir.h"
30 #undef swprintf
32 extern ShellObjects g_shellObjects;
34 // *********************** CShellExt *************************
35 CShellExt::CShellExt(FileState state)
36 : m_State(state)
37 , itemStates(0)
38 , itemStatesFolder(0)
39 , space(0)
40 , m_cRef(0)
41 ,regDiffLater(L"Software\\TortoiseGit\\DiffLater", L"")
43 InterlockedIncrement(&g_cRefThisDll);
46 AutoLocker lock(g_csGlobalCOMGuard);
47 g_shellObjects.Insert(this);
50 INITCOMMONCONTROLSEX used = {
51 sizeof(INITCOMMONCONTROLSEX),
52 ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
54 InitCommonControlsEx(&used);
55 LoadLangDll();
58 CShellExt::~CShellExt()
60 AutoLocker lock(g_csGlobalCOMGuard);
61 InterlockedDecrement(&g_cRefThisDll);
62 g_shellObjects.Erase(this);
65 void LoadLangDll()
67 if (g_langid != g_ShellCache.GetLangID() && (g_langTimeout == 0 || g_langTimeout < GetTickCount64()))
69 g_langid = g_ShellCache.GetLangID();
70 DWORD langId = g_langid;
71 TCHAR langDll[MAX_PATH*4] = {0};
72 HINSTANCE hInst = nullptr;
73 TCHAR langdir[MAX_PATH] = {0};
74 if (GetModuleFileName(g_hmodThisDll, langdir, _countof(langdir))==0)
75 return;
76 TCHAR* dirpoint = wcsrchr(langdir, L'\\');
77 if (dirpoint)
78 *dirpoint = L'\0';
79 dirpoint = wcsrchr(langdir, L'\\');
80 if (dirpoint)
81 *dirpoint = L'\0';
83 BOOL bIsWow = FALSE;
84 IsWow64Process(GetCurrentProcess(), &bIsWow);
88 if (bIsWow)
89 swprintf_s(langDll, L"%s\\Languages\\TortoiseProc32%lu.dll", langdir, langId);
90 else
91 swprintf_s(langDll, L"%s\\Languages\\TortoiseProc%lu.dll", langdir, langId);
92 BOOL versionmatch = TRUE;
94 struct TRANSARRAY
96 WORD wLanguageID;
97 WORD wCharacterSet;
100 DWORD dwReserved,dwBufferSize;
101 dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);
103 if (dwBufferSize > 0)
105 LPVOID pBuffer = (void*) malloc(dwBufferSize);
107 if (pBuffer)
109 UINT nInfoSize = 0;
110 UINT nFixedLength = 0;
111 LPSTR lpVersion = nullptr;
112 VOID* lpFixedPointer;
114 if (GetFileVersionInfo((LPTSTR)langDll,
115 dwReserved,
116 dwBufferSize,
117 pBuffer))
119 // Query the current language
120 if (VerQueryValue( pBuffer,
121 L"\\VarFileInfo\\Translation",
122 &lpFixedPointer,
123 &nFixedLength))
125 auto lpTransArray = reinterpret_cast<TRANSARRAY*>(lpFixedPointer);
126 TCHAR strLangProductVersion[MAX_PATH] = { 0 };
128 swprintf_s(strLangProductVersion, L"\\StringFileInfo\\%04x%04x\\ProductVersion",
129 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
131 if (VerQueryValue(pBuffer, (LPTSTR)strLangProductVersion, (LPVOID*)&lpVersion, &nInfoSize))
132 versionmatch = (wcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
136 free(pBuffer);
137 } // if (pBuffer)
138 } // if (dwBufferSize > 0)
139 else
140 versionmatch = FALSE;
142 if (versionmatch)
143 hInst = LoadLibrary(langDll);
144 if (hInst)
146 if (g_hResInst != g_hmodThisDll)
147 FreeLibrary(g_hResInst);
148 g_hResInst = hInst;
150 else
152 DWORD lid = SUBLANGID(langId);
153 lid--;
154 if (lid > 0)
155 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
156 else
157 langId = 0;
159 } while (!hInst && langId != 0);
160 if (!hInst)
162 // either the dll for the selected language is not present, or
163 // it is the wrong version.
164 // fall back to English and set a timeout so we don't retry
165 // to load the language dll too often
166 if (g_hResInst != g_hmodThisDll)
167 FreeLibrary(g_hResInst);
168 g_hResInst = g_hmodThisDll;
169 g_langid = 1033;
170 // set a timeout of 10 seconds
171 if (g_ShellCache.GetLangID() != 1033)
172 g_langTimeout = GetTickCount64() + 10000;
174 else
175 g_langTimeout = 0;
176 } // if (g_langid != g_ShellCache.GetLangID())
179 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
181 if (!ppv)
182 return E_POINTER;
184 *ppv = nullptr;
186 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
187 *ppv = static_cast<LPSHELLEXTINIT>(this);
188 else if (IsEqualIID(riid, IID_IContextMenu))
189 *ppv = static_cast<LPCONTEXTMENU>(this);
190 else if (IsEqualIID(riid, IID_IContextMenu2))
191 *ppv = static_cast<LPCONTEXTMENU2>(this);
192 else if (IsEqualIID(riid, IID_IContextMenu3))
193 *ppv = static_cast<LPCONTEXTMENU3>(this);
194 else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))
195 *ppv = static_cast<IShellIconOverlayIdentifier*>(this);
196 else if (IsEqualIID(riid, IID_IShellPropSheetExt))
197 *ppv = static_cast<LPSHELLPROPSHEETEXT>(this);
198 else if (IsEqualIID(riid, IID_IShellCopyHook))
199 *ppv = static_cast<ICopyHook*>(this);
200 else
201 return E_NOINTERFACE;
203 AddRef();
204 return S_OK;
207 STDMETHODIMP_(ULONG) CShellExt::AddRef()
209 return InterlockedIncrement(&m_cRef);
212 STDMETHODIMP_(ULONG) CShellExt::Release()
214 if (InterlockedDecrement(&m_cRef))
215 return m_cRef;
217 delete this;
219 return 0L;
222 // IPersistFile members
223 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid)
225 if (!pclsid)
226 return E_POINTER;
227 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
228 return S_OK;
231 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
233 return S_OK;
236 // ICopyHook member
237 UINT __stdcall CShellExt::CopyCallback(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
239 switch (wFunc)
241 case FO_MOVE:
242 case FO_DELETE:
243 case FO_RENAME:
244 if (pszSrcFile && pszSrcFile[0] && g_ShellCache.IsPathAllowed(pszSrcFile))
246 auto cacheType = g_ShellCache.GetCacheType();
247 switch (cacheType)
249 case ShellCache::exe:
250 m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile));
251 break;
252 case ShellCache::dll:
253 case ShellCache::dllFull:
255 CString topDir;
256 if (GitAdminDir::HasAdminDir(pszSrcFile, &topDir))
257 m_CachedStatus.m_GitStatus.ReleasePath(topDir);
258 break;
260 default:
261 break;
264 break;
265 default:
266 break;
269 // we could now wait a little bit to give the cache time to release the handles.
270 // but the explorer/shell already retries any action for about two seconds
271 // if it first fails. So if the cache hasn't released the handle yet, the explorer
272 // will retry anyway, so we just leave here immediately.
273 return IDYES;