Limit GUI updates the the main thread
[TortoiseGit.git] / src / TortoiseShell / ShellExt.cpp
blob3953d8c4041512b6a7bc58bc68d01b6c2b1f198d
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2012 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
21 #pragma warning (disable : 4786)
23 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
24 #include <initguid.h>
25 #include "Guids.h"
27 #include "ShellExt.h"
28 #include "ShellObjects.h"
29 //#include "..\version.h"
30 //#include "libintl.h"
31 #undef swprintf
33 extern ShellObjects g_shellObjects;
35 // *********************** CShellExt *************************
36 CShellExt::CShellExt(FileState state)
37 : m_crasher(L"TortoiseGit", false)
39 m_State = state;
41 m_cRef = 0L;
42 InterlockedIncrement(&g_cRefThisDll);
45 AutoLocker lock(g_csGlobalCOMGuard);
46 g_shellObjects.Insert(this);
49 INITCOMMONCONTROLSEX used = {
50 sizeof(INITCOMMONCONTROLSEX),
51 ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
53 InitCommonControlsEx(&used);
54 LoadLangDll();
56 if (SysInfo::Instance().IsVistaOrLater())
58 HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL"));
60 pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits");
61 pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint");
62 pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint");
66 CShellExt::~CShellExt()
68 AutoLocker lock(g_csGlobalCOMGuard);
69 InterlockedDecrement(&g_cRefThisDll);
70 g_shellObjects.Erase(this);
73 void LoadLangDll()
75 if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))
77 g_langid = g_ShellCache.GetLangID();
78 DWORD langId = g_langid;
79 TCHAR langDll[MAX_PATH*4];
80 HINSTANCE hInst = NULL;
81 TCHAR langdir[MAX_PATH] = {0};
82 char langdirA[MAX_PATH] = {0};
83 if (GetModuleFileName(g_hmodThisDll, langdir, _countof(langdir))==0)
84 return;
85 if (GetModuleFileNameA(g_hmodThisDll, langdirA, _countof(langdirA))==0)
86 return;
87 TCHAR * dirpoint = _tcsrchr(langdir, '\\');
88 char * dirpointA = strrchr(langdirA, '\\');
89 if (dirpoint)
90 *dirpoint = 0;
91 if (dirpointA)
92 *dirpointA = 0;
93 dirpoint = _tcsrchr(langdir, '\\');
94 dirpointA = strrchr(langdirA, '\\');
95 if (dirpoint)
96 *dirpoint = 0;
97 if (dirpointA)
98 *dirpointA = 0;
99 strcat_s(langdirA, "\\Languages");
100 // bindtextdomain ("subversion", langdirA);
102 BOOL bIsWow = FALSE;
103 IsWow64Process(GetCurrentProcess(), &bIsWow);
107 if (bIsWow)
108 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc32%d.dll"), langdir, langId);
109 else
110 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir, langId);
111 BOOL versionmatch = TRUE;
113 struct TRANSARRAY
115 WORD wLanguageID;
116 WORD wCharacterSet;
119 DWORD dwReserved,dwBufferSize;
120 dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);
122 if (dwBufferSize > 0)
124 LPVOID pBuffer = (void*) malloc(dwBufferSize);
126 if (pBuffer != (void*) NULL)
128 UINT nInfoSize = 0;
129 UINT nFixedLength = 0;
130 LPSTR lpVersion = NULL;
131 VOID* lpFixedPointer;
132 TRANSARRAY* lpTransArray;
133 TCHAR strLangProduktVersion[MAX_PATH];
135 if (GetFileVersionInfo((LPTSTR)langDll,
136 dwReserved,
137 dwBufferSize,
138 pBuffer))
140 // Query the current language
141 if (VerQueryValue( pBuffer,
142 _T("\\VarFileInfo\\Translation"),
143 &lpFixedPointer,
144 &nFixedLength))
146 lpTransArray = (TRANSARRAY*) lpFixedPointer;
148 _stprintf_s(strLangProduktVersion, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
149 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
151 if (VerQueryValue(pBuffer,
152 (LPTSTR)strLangProduktVersion,
153 (LPVOID *)&lpVersion,
154 &nInfoSize))
156 versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
161 free(pBuffer);
162 } // if (pBuffer != (void*) NULL)
163 } // if (dwBufferSize > 0)
164 else
165 versionmatch = FALSE;
167 if (versionmatch)
168 hInst = LoadLibrary(langDll);
169 if (hInst != NULL)
171 if (g_hResInst != g_hmodThisDll)
172 FreeLibrary(g_hResInst);
173 g_hResInst = hInst;
175 else
177 DWORD lid = SUBLANGID(langId);
178 lid--;
179 if (lid > 0)
181 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
183 else
184 langId = 0;
186 } while ((hInst == NULL) && (langId != 0));
187 if (hInst == NULL)
189 // either the dll for the selected language is not present, or
190 // it is the wrong version.
191 // fall back to English and set a timeout so we don't retry
192 // to load the language dll too often
193 if (g_hResInst != g_hmodThisDll)
194 FreeLibrary(g_hResInst);
195 g_hResInst = g_hmodThisDll;
196 g_langid = 1033;
197 // set a timeout of 10 seconds
198 if (g_ShellCache.GetLangID() != 1033)
199 g_langTimeout = GetTickCount() + 10000;
201 else
202 g_langTimeout = 0;
203 } // if (g_langid != g_ShellCache.GetLangID())
206 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
208 if(ppv == 0)
209 return E_POINTER;
211 *ppv = NULL;
213 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
215 *ppv = static_cast<LPSHELLEXTINIT>(this);
217 else if (IsEqualIID(riid, IID_IContextMenu))
219 *ppv = static_cast<LPCONTEXTMENU>(this);
221 else if (IsEqualIID(riid, IID_IContextMenu2))
223 *ppv = static_cast<LPCONTEXTMENU2>(this);
225 else if (IsEqualIID(riid, IID_IContextMenu3))
227 *ppv = static_cast<LPCONTEXTMENU3>(this);
229 else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))
231 *ppv = static_cast<IShellIconOverlayIdentifier*>(this);
233 else if (IsEqualIID(riid, IID_IShellPropSheetExt))
235 *ppv = static_cast<LPSHELLPROPSHEETEXT>(this);
237 else if (IsEqualIID(riid, IID_IColumnProvider))
239 *ppv = static_cast<IColumnProvider*>(this);
241 else if (IsEqualIID(riid, IID_IShellCopyHook))
243 *ppv = static_cast<ICopyHook*>(this);
245 else
247 return E_NOINTERFACE;
250 AddRef();
251 return S_OK;
254 STDMETHODIMP_(ULONG) CShellExt::AddRef()
256 return ++m_cRef;
259 STDMETHODIMP_(ULONG) CShellExt::Release()
261 if (--m_cRef)
262 return m_cRef;
264 delete this;
266 return 0L;
269 // IPersistFile members
270 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid)
272 if(pclsid == 0)
273 return E_POINTER;
274 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
275 return S_OK;
278 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
280 return S_OK;
283 // ICopyHook member
284 UINT __stdcall CShellExt::CopyCallback(HWND hWnd, UINT wFunc, UINT wFlags, LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
286 __try
288 return CopyCallback_Wrap(hWnd, wFunc, wFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs);
290 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
293 return IDYES;
296 UINT __stdcall CShellExt::CopyCallback_Wrap(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
298 if (wFunc == FO_COPY)
299 return IDYES; // copying is not a problem for us
301 m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile));
302 // we could now wait a little bit to give the cache time to release the handles.
303 // but the explorer/shell already retries any action for about two seconds
304 // if it first fails. So if the cache hasn't released the handle yet, the explorer
305 // will retry anyway, so we just leave here immediately.
306 return IDYES;