Add context menu to delete all tags in Reference Browser
[TortoiseGit.git] / src / TortoiseShell / ShellExt.cpp
blob8b84f0c8d177d25d55b0e9a99109c5aa89b5cc15
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2013 - TortoiseGit
4 // Copyright (C) 2003-2012 - 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 #pragma warning (disable : 4786)
24 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
25 #include <initguid.h>
26 #include "Guids.h"
28 #include "ShellExt.h"
29 #include "ShellObjects.h"
30 #include "..\version.h"
31 //#include "libintl.h"
32 #undef swprintf
34 extern ShellObjects g_shellObjects;
36 // *********************** CShellExt *************************
37 CShellExt::CShellExt(FileState state)
38 : m_crasher(L"TortoiseGit", TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE, false)
40 m_State = state;
42 m_cRef = 0L;
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();
57 if (SysInfo::Instance().IsVistaOrLater())
59 HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL"));
61 pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits");
62 pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint");
63 pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint");
67 CShellExt::~CShellExt()
69 AutoLocker lock(g_csGlobalCOMGuard);
70 InterlockedDecrement(&g_cRefThisDll);
71 g_shellObjects.Erase(this);
74 void LoadLangDll()
76 if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))
78 g_langid = g_ShellCache.GetLangID();
79 DWORD langId = g_langid;
80 TCHAR langDll[MAX_PATH*4];
81 HINSTANCE hInst = NULL;
82 TCHAR langdir[MAX_PATH] = {0};
83 char langdirA[MAX_PATH] = {0};
84 if (GetModuleFileName(g_hmodThisDll, langdir, _countof(langdir))==0)
85 return;
86 if (GetModuleFileNameA(g_hmodThisDll, langdirA, _countof(langdirA))==0)
87 return;
88 TCHAR * dirpoint = _tcsrchr(langdir, '\\');
89 char * dirpointA = strrchr(langdirA, '\\');
90 if (dirpoint)
91 *dirpoint = 0;
92 if (dirpointA)
93 *dirpointA = 0;
94 dirpoint = _tcsrchr(langdir, '\\');
95 dirpointA = strrchr(langdirA, '\\');
96 if (dirpoint)
97 *dirpoint = 0;
98 if (dirpointA)
99 *dirpointA = 0;
100 strcat_s(langdirA, "\\Languages");
101 // bindtextdomain ("subversion", langdirA);
103 BOOL bIsWow = FALSE;
104 IsWow64Process(GetCurrentProcess(), &bIsWow);
108 if (bIsWow)
109 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc32%d.dll"), langdir, langId);
110 else
111 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir, langId);
112 BOOL versionmatch = TRUE;
114 struct TRANSARRAY
116 WORD wLanguageID;
117 WORD wCharacterSet;
120 DWORD dwReserved,dwBufferSize;
121 dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);
123 if (dwBufferSize > 0)
125 LPVOID pBuffer = (void*) malloc(dwBufferSize);
127 if (pBuffer != (void*) NULL)
129 UINT nInfoSize = 0;
130 UINT nFixedLength = 0;
131 LPSTR lpVersion = NULL;
132 VOID* lpFixedPointer;
133 TRANSARRAY* lpTransArray;
134 TCHAR strLangProduktVersion[MAX_PATH];
136 if (GetFileVersionInfo((LPTSTR)langDll,
137 dwReserved,
138 dwBufferSize,
139 pBuffer))
141 // Query the current language
142 if (VerQueryValue( pBuffer,
143 _T("\\VarFileInfo\\Translation"),
144 &lpFixedPointer,
145 &nFixedLength))
147 lpTransArray = (TRANSARRAY*) lpFixedPointer;
149 _stprintf_s(strLangProduktVersion, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
150 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
152 if (VerQueryValue(pBuffer,
153 (LPTSTR)strLangProduktVersion,
154 (LPVOID *)&lpVersion,
155 &nInfoSize))
157 versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
162 free(pBuffer);
163 } // if (pBuffer != (void*) NULL)
164 } // if (dwBufferSize > 0)
165 else
166 versionmatch = FALSE;
168 if (versionmatch)
169 hInst = LoadLibrary(langDll);
170 if (hInst != NULL)
172 if (g_hResInst != g_hmodThisDll)
173 FreeLibrary(g_hResInst);
174 g_hResInst = hInst;
176 else
178 DWORD lid = SUBLANGID(langId);
179 lid--;
180 if (lid > 0)
182 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
184 else
185 langId = 0;
187 } while ((hInst == NULL) && (langId != 0));
188 if (hInst == NULL)
190 // either the dll for the selected language is not present, or
191 // it is the wrong version.
192 // fall back to English and set a timeout so we don't retry
193 // to load the language dll too often
194 if (g_hResInst != g_hmodThisDll)
195 FreeLibrary(g_hResInst);
196 g_hResInst = g_hmodThisDll;
197 g_langid = 1033;
198 // set a timeout of 10 seconds
199 if (g_ShellCache.GetLangID() != 1033)
200 g_langTimeout = GetTickCount() + 10000;
202 else
203 g_langTimeout = 0;
204 } // if (g_langid != g_ShellCache.GetLangID())
207 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
209 if(ppv == 0)
210 return E_POINTER;
212 *ppv = NULL;
214 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
216 *ppv = static_cast<LPSHELLEXTINIT>(this);
218 else if (IsEqualIID(riid, IID_IContextMenu))
220 *ppv = static_cast<LPCONTEXTMENU>(this);
222 else if (IsEqualIID(riid, IID_IContextMenu2))
224 *ppv = static_cast<LPCONTEXTMENU2>(this);
226 else if (IsEqualIID(riid, IID_IContextMenu3))
228 *ppv = static_cast<LPCONTEXTMENU3>(this);
230 else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))
232 *ppv = static_cast<IShellIconOverlayIdentifier*>(this);
234 else if (IsEqualIID(riid, IID_IShellPropSheetExt))
236 *ppv = static_cast<LPSHELLPROPSHEETEXT>(this);
238 else if (IsEqualIID(riid, IID_IColumnProvider))
240 *ppv = static_cast<IColumnProvider*>(this);
242 else if (IsEqualIID(riid, IID_IShellCopyHook))
244 *ppv = static_cast<ICopyHook*>(this);
246 else
248 return E_NOINTERFACE;
251 AddRef();
252 return S_OK;
255 STDMETHODIMP_(ULONG) CShellExt::AddRef()
257 return ++m_cRef;
260 STDMETHODIMP_(ULONG) CShellExt::Release()
262 if (--m_cRef)
263 return m_cRef;
265 delete this;
267 return 0L;
270 // IPersistFile members
271 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid)
273 if(pclsid == 0)
274 return E_POINTER;
275 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
276 return S_OK;
279 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
281 return S_OK;
284 // ICopyHook member
285 UINT __stdcall CShellExt::CopyCallback(HWND hWnd, UINT wFunc, UINT wFlags, LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
287 __try
289 return CopyCallback_Wrap(hWnd, wFunc, wFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs);
291 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
294 return IDYES;
297 UINT __stdcall CShellExt::CopyCallback_Wrap(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
299 if (wFunc == FO_COPY)
300 return IDYES; // copying is not a problem for us
302 m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile));
303 // we could now wait a little bit to give the cache time to release the handles.
304 // but the explorer/shell already retries any action for about two seconds
305 // if it first fails. So if the cache hasn't released the handle yet, the explorer
306 // will retry anyway, so we just leave here immediately.
307 return IDYES;