Do not use GitAdminDir objects
[TortoiseGit.git] / src / TortoiseShell / ShellExt.cpp
blob2dc4da7ff7f1ca9ff834c358b099477cfa6ade22
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2015 - TortoiseGit
4 // Copyright (C) 2003-2013 - 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 #undef swprintf
31 extern ShellObjects g_shellObjects;
33 // *********************** CShellExt *************************
34 CShellExt::CShellExt(FileState state)
35 : m_State(state)
36 , itemStates(0)
37 , itemStatesFolder(0)
38 , space(0)
39 #if ENABLE_CRASHHANLDER
40 , m_crasher(L"TortoiseGit", TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE, false)
41 #endif
42 ,regDiffLater(L"Software\\TortoiseGit\\DiffLater", L"")
44 m_cRef = 0L;
45 InterlockedIncrement(&g_cRefThisDll);
48 AutoLocker lock(g_csGlobalCOMGuard);
49 g_shellObjects.Insert(this);
52 INITCOMMONCONTROLSEX used = {
53 sizeof(INITCOMMONCONTROLSEX),
54 ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
56 InitCommonControlsEx(&used);
57 LoadLangDll();
60 CShellExt::~CShellExt()
62 AutoLocker lock(g_csGlobalCOMGuard);
63 InterlockedDecrement(&g_cRefThisDll);
64 g_shellObjects.Erase(this);
67 void LoadLangDll()
69 if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))
71 g_langid = g_ShellCache.GetLangID();
72 DWORD langId = g_langid;
73 TCHAR langDll[MAX_PATH*4] = {0};
74 HINSTANCE hInst = NULL;
75 TCHAR langdir[MAX_PATH] = {0};
76 char langdirA[MAX_PATH] = {0};
77 if (GetModuleFileName(g_hmodThisDll, langdir, _countof(langdir))==0)
78 return;
79 if (GetModuleFileNameA(g_hmodThisDll, langdirA, _countof(langdirA))==0)
80 return;
81 TCHAR * dirpoint = _tcsrchr(langdir, '\\');
82 char * dirpointA = strrchr(langdirA, '\\');
83 if (dirpoint)
84 *dirpoint = 0;
85 if (dirpointA)
86 *dirpointA = 0;
87 dirpoint = _tcsrchr(langdir, '\\');
88 dirpointA = strrchr(langdirA, '\\');
89 if (dirpoint)
90 *dirpoint = 0;
91 if (dirpointA)
92 *dirpointA = 0;
93 strcat_s(langdirA, "\\Languages");
95 BOOL bIsWow = FALSE;
96 IsWow64Process(GetCurrentProcess(), &bIsWow);
100 if (bIsWow)
101 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc32%lu.dll"), langdir, langId);
102 else
103 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc%lu.dll"), langdir, langId);
104 BOOL versionmatch = TRUE;
106 struct TRANSARRAY
108 WORD wLanguageID;
109 WORD wCharacterSet;
112 DWORD dwReserved,dwBufferSize;
113 dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);
115 if (dwBufferSize > 0)
117 LPVOID pBuffer = (void*) malloc(dwBufferSize);
119 if (pBuffer != (void*) NULL)
121 UINT nInfoSize = 0;
122 UINT nFixedLength = 0;
123 LPSTR lpVersion = NULL;
124 VOID* lpFixedPointer;
125 TRANSARRAY* lpTransArray;
126 TCHAR strLangProductVersion[MAX_PATH] = {0};
128 if (GetFileVersionInfo((LPTSTR)langDll,
129 dwReserved,
130 dwBufferSize,
131 pBuffer))
133 // Query the current language
134 if (VerQueryValue( pBuffer,
135 _T("\\VarFileInfo\\Translation"),
136 &lpFixedPointer,
137 &nFixedLength))
139 lpTransArray = (TRANSARRAY*) lpFixedPointer;
141 _stprintf_s(strLangProductVersion, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
142 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
144 if (VerQueryValue(pBuffer,
145 (LPTSTR)strLangProductVersion,
146 (LPVOID *)&lpVersion,
147 &nInfoSize))
149 versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
154 free(pBuffer);
155 } // if (pBuffer != (void*) NULL)
156 } // if (dwBufferSize > 0)
157 else
158 versionmatch = FALSE;
160 if (versionmatch)
161 hInst = LoadLibrary(langDll);
162 if (hInst != NULL)
164 if (g_hResInst != g_hmodThisDll)
165 FreeLibrary(g_hResInst);
166 g_hResInst = hInst;
168 else
170 DWORD lid = SUBLANGID(langId);
171 lid--;
172 if (lid > 0)
174 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
176 else
177 langId = 0;
179 } while ((hInst == NULL) && (langId != 0));
180 if (hInst == NULL)
182 // either the dll for the selected language is not present, or
183 // it is the wrong version.
184 // fall back to English and set a timeout so we don't retry
185 // to load the language dll too often
186 if (g_hResInst != g_hmodThisDll)
187 FreeLibrary(g_hResInst);
188 g_hResInst = g_hmodThisDll;
189 g_langid = 1033;
190 // set a timeout of 10 seconds
191 if (g_ShellCache.GetLangID() != 1033)
192 g_langTimeout = GetTickCount() + 10000;
194 else
195 g_langTimeout = 0;
196 } // if (g_langid != g_ShellCache.GetLangID())
199 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
201 if(ppv == 0)
202 return E_POINTER;
204 *ppv = NULL;
206 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
208 *ppv = static_cast<LPSHELLEXTINIT>(this);
210 else if (IsEqualIID(riid, IID_IContextMenu))
212 *ppv = static_cast<LPCONTEXTMENU>(this);
214 else if (IsEqualIID(riid, IID_IContextMenu2))
216 *ppv = static_cast<LPCONTEXTMENU2>(this);
218 else if (IsEqualIID(riid, IID_IContextMenu3))
220 *ppv = static_cast<LPCONTEXTMENU3>(this);
222 else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))
224 *ppv = static_cast<IShellIconOverlayIdentifier*>(this);
226 else if (IsEqualIID(riid, IID_IShellPropSheetExt))
228 *ppv = static_cast<LPSHELLPROPSHEETEXT>(this);
230 else if (IsEqualIID(riid, IID_IShellCopyHook))
232 *ppv = static_cast<ICopyHook*>(this);
234 else
236 return E_NOINTERFACE;
239 AddRef();
240 return S_OK;
243 STDMETHODIMP_(ULONG) CShellExt::AddRef()
245 return ++m_cRef;
248 STDMETHODIMP_(ULONG) CShellExt::Release()
250 if (--m_cRef)
251 return m_cRef;
253 delete this;
255 return 0L;
258 // IPersistFile members
259 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid)
261 if(pclsid == 0)
262 return E_POINTER;
263 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
264 return S_OK;
267 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
269 return S_OK;
272 // ICopyHook member
273 UINT __stdcall CShellExt::CopyCallback(HWND hWnd, UINT wFunc, UINT wFlags, LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
275 __try
277 return CopyCallback_Wrap(hWnd, wFunc, wFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs);
279 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
282 return IDYES;
285 UINT __stdcall CShellExt::CopyCallback_Wrap(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
287 switch (wFunc)
289 case FO_MOVE:
290 case FO_DELETE:
291 case FO_RENAME:
292 if (pszSrcFile && pszSrcFile[0])
294 CString topDir;
295 if (GitAdminDir::HasAdminDir(pszSrcFile, &topDir))
296 m_CachedStatus.m_GitStatus.ReleasePath(topDir);
297 m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile));
299 break;
300 default:
301 break;
304 // we could now wait a little bit to give the cache time to release the handles.
305 // but the explorer/shell already retries any action for about two seconds
306 // if it first fails. So if the cache hasn't released the handle yet, the explorer
307 // will retry anyway, so we just leave here immediately.
308 return IDYES;