Added unicode big-endian text file support to TortoiseMerge
[TortoiseGit.git] / src / TortoiseShell / ShellExt.cpp
blob04b759a052066f9f18aa19c122aa16e3e2134a13
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - 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"
26 #include "git.h"
27 #include "ShellExt.h"
28 //#include "..\version.h"
29 //#include "libintl.h"
30 #undef swprintf
31 #include "GitPropertyPage.h"
33 std::set<CShellExt *> g_exts;
35 // *********************** CShellExt *************************
36 CShellExt::CShellExt(FileState state)
37 : m_crasher(L"TortoiseGit", false)
39 m_State = state;
41 m_cRef = 0L;
42 g_cRefThisDll++;
44 g_exts.insert(this);
46 INITCOMMONCONTROLSEX used = {
47 sizeof(INITCOMMONCONTROLSEX),
48 ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
50 InitCommonControlsEx(&used);
51 LoadLangDll();
53 if (SysInfo::Instance().IsVistaOrLater())
55 HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL"));
57 pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits");
58 pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint");
59 pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint");
63 CShellExt::~CShellExt()
65 std::map<UINT, HBITMAP>::iterator it;
66 for (it = bitmaps.begin(); it != bitmaps.end(); ++it)
68 ::DeleteObject(it->second);
70 bitmaps.clear();
71 g_cRefThisDll--;
72 g_exts.erase(this);
75 void LoadLangDll()
77 if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))
79 g_langid = g_ShellCache.GetLangID();
80 DWORD langId = g_langid;
81 TCHAR langDll[MAX_PATH*4];
82 HINSTANCE hInst = NULL;
83 TCHAR langdir[MAX_PATH] = {0};
84 char langdirA[MAX_PATH] = {0};
85 if (GetModuleFileName(g_hmodThisDll, langdir, MAX_PATH)==0)
86 return;
87 if (GetModuleFileNameA(g_hmodThisDll, langdirA, MAX_PATH)==0)
88 return;
89 TCHAR * dirpoint = _tcsrchr(langdir, '\\');
90 char * dirpointA = strrchr(langdirA, '\\');
91 if (dirpoint)
92 *dirpoint = 0;
93 if (dirpointA)
94 *dirpointA = 0;
95 dirpoint = _tcsrchr(langdir, '\\');
96 dirpointA = strrchr(langdirA, '\\');
97 if (dirpoint)
98 *dirpoint = 0;
99 if (dirpointA)
100 *dirpointA = 0;
101 strcat_s(langdirA, MAX_PATH, "\\Languages");
102 // bindtextdomain ("subversion", langdirA);
104 BOOL bIsWow = FALSE;
105 IsWow64Process(GetCurrentProcess(), &bIsWow);
109 if (bIsWow)
110 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc32%d.dll"), langdir, langId);
111 else
112 _stprintf_s(langDll, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir, langId);
113 BOOL versionmatch = TRUE;
115 struct TRANSARRAY
117 WORD wLanguageID;
118 WORD wCharacterSet;
121 DWORD dwReserved,dwBufferSize;
122 dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);
124 if (dwBufferSize > 0)
126 LPVOID pBuffer = (void*) malloc(dwBufferSize);
128 if (pBuffer != (void*) NULL)
130 UINT nInfoSize = 0,
131 nFixedLength = 0;
132 LPSTR lpVersion = NULL;
133 VOID* lpFixedPointer;
134 TRANSARRAY* lpTransArray;
135 TCHAR strLangProduktVersion[MAX_PATH];
137 if (GetFileVersionInfo((LPTSTR)langDll,
138 dwReserved,
139 dwBufferSize,
140 pBuffer))
142 // Query the current language
143 if (VerQueryValue( pBuffer,
144 _T("\\VarFileInfo\\Translation"),
145 &lpFixedPointer,
146 &nFixedLength))
148 lpTransArray = (TRANSARRAY*) lpFixedPointer;
150 _stprintf_s(strLangProduktVersion, MAX_PATH, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
151 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
153 if (VerQueryValue(pBuffer,
154 (LPTSTR)strLangProduktVersion,
155 (LPVOID *)&lpVersion,
156 &nInfoSize))
158 // versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
163 free(pBuffer);
164 } // if (pBuffer != (void*) NULL)
165 } // if (dwBufferSize > 0)
166 else
167 versionmatch = FALSE;
169 if (versionmatch)
170 hInst = LoadLibrary(langDll);
171 if (hInst != NULL)
173 if (g_hResInst != g_hmodThisDll)
174 FreeLibrary(g_hResInst);
175 g_hResInst = hInst;
177 else
179 DWORD lid = SUBLANGID(langId);
180 lid--;
181 if (lid > 0)
183 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
185 else
186 langId = 0;
188 } while ((hInst == NULL) && (langId != 0));
189 if (hInst == NULL)
191 // either the dll for the selected language is not present, or
192 // it is the wrong version.
193 // fall back to English and set a timeout so we don't retry
194 // to load the language dll too often
195 if (g_hResInst != g_hmodThisDll)
196 FreeLibrary(g_hResInst);
197 g_hResInst = g_hmodThisDll;
198 g_langid = 1033;
199 // set a timeout of 10 seconds
200 if (g_ShellCache.GetLangID() != 1033)
201 g_langTimeout = GetTickCount() + 10000;
203 else
204 g_langTimeout = 0;
205 } // if (g_langid != g_ShellCache.GetLangID())
208 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
210 *ppv = NULL;
212 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
214 *ppv = (LPSHELLEXTINIT)this;
216 else if (IsEqualIID(riid, IID_IContextMenu))
218 *ppv = (LPCONTEXTMENU)this;
220 else if (IsEqualIID(riid, IID_IContextMenu2))
222 *ppv = (LPCONTEXTMENU2)this;
224 else if (IsEqualIID(riid, IID_IContextMenu3))
226 *ppv = (LPCONTEXTMENU3)this;
228 else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))
230 *ppv = (IShellIconOverlayIdentifier*)this;
232 else if (IsEqualIID(riid, IID_IShellPropSheetExt))
234 *ppv = (LPSHELLPROPSHEETEXT)this;
236 else if (IsEqualIID(riid, IID_IColumnProvider))
238 *ppv = (IColumnProvider *)this;
240 else if (IsEqualIID(riid, IID_IShellCopyHook))
242 *ppv = (ICopyHook *)this;
244 if (*ppv)
246 AddRef();
248 return S_OK;
251 return E_NOINTERFACE;
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 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
273 return S_OK;
276 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
278 return S_OK;
281 // ICopyHook member
282 UINT __stdcall CShellExt::CopyCallback(HWND hWnd, UINT wFunc, UINT wFlags, LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
284 __try
286 return CopyCallback_Wrap(hWnd, wFunc, wFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs);
288 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
291 return IDYES;
294 UINT __stdcall CShellExt::CopyCallback_Wrap(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
296 if (wFunc == FO_COPY)
297 return IDYES; // copying is not a problem for us
299 m_remoteCacheLink.ReleaseLockForPath(CTGitPath(pszSrcFile));
300 // we could now wait a little bit to give the cache time to release the handles.
301 // but the explorer/shell already retries any action for about two seconds
302 // if it first fails. So if the cache hasn't released the handle yet, the explorer
303 // will retry anyway, so we just leave here immediately.
304 return IDYES;