1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
21 #pragma warning (disable : 4786)
\r
23 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
\r
24 #include <initguid.h>
\r
27 #include "ShellExt.h"
\r
28 //#include "..\version.h"
\r
29 //#include "libintl.h"
\r
32 std::set<CShellExt *> g_exts;
\r
34 // *********************** CShellExt *************************
\r
35 CShellExt::CShellExt(FileState state)
\r
37 OSVERSIONINFOEX inf;
\r
38 SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));
\r
39 inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
\r
40 GetVersionEx((OSVERSIONINFO *)&inf);
\r
41 fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);
\r
48 g_exts.insert(this);
\r
50 INITCOMMONCONTROLSEX used = {
\r
51 sizeof(INITCOMMONCONTROLSEX),
\r
52 ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
\r
54 InitCommonControlsEx(&used);
\r
57 if (fullver >= 0x0600)
\r
59 HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL"));
\r
61 pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits");
\r
62 pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint");
\r
63 pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint");
\r
67 CShellExt::~CShellExt()
\r
69 std::map<UINT, HBITMAP>::iterator it;
\r
70 for (it = bitmaps.begin(); it != bitmaps.end(); ++it)
\r
72 ::DeleteObject(it->second);
\r
81 if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))
\r
83 g_langid = g_ShellCache.GetLangID();
\r
84 DWORD langId = g_langid;
\r
85 TCHAR langDll[MAX_PATH*4];
\r
86 HINSTANCE hInst = NULL;
\r
87 TCHAR langdir[MAX_PATH] = {0};
\r
88 char langdirA[MAX_PATH] = {0};
\r
89 if (GetModuleFileName(g_hmodThisDll, langdir, MAX_PATH)==0)
\r
91 if (GetModuleFileNameA(g_hmodThisDll, langdirA, MAX_PATH)==0)
\r
93 TCHAR * dirpoint = _tcsrchr(langdir, '\\');
\r
94 char * dirpointA = strrchr(langdirA, '\\');
\r
99 dirpoint = _tcsrchr(langdir, '\\');
\r
100 dirpointA = strrchr(langdirA, '\\');
\r
105 strcat_s(langdirA, MAX_PATH, "\\Languages");
\r
106 // bindtextdomain ("subversion", langdirA);
\r
110 _stprintf_s(langDll, MAX_PATH*4, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir, langId);
\r
111 BOOL versionmatch = TRUE;
\r
116 WORD wCharacterSet;
\r
119 DWORD dwReserved,dwBufferSize;
\r
120 dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);
\r
122 if (dwBufferSize > 0)
\r
124 LPVOID pBuffer = (void*) malloc(dwBufferSize);
\r
126 if (pBuffer != (void*) NULL)
\r
128 UINT nInfoSize = 0,
\r
130 LPSTR lpVersion = NULL;
\r
131 VOID* lpFixedPointer;
\r
132 TRANSARRAY* lpTransArray;
\r
133 TCHAR strLangProduktVersion[MAX_PATH];
\r
135 if (GetFileVersionInfo((LPTSTR)langDll,
\r
140 // Query the current language
\r
141 if (VerQueryValue( pBuffer,
\r
142 _T("\\VarFileInfo\\Translation"),
\r
146 lpTransArray = (TRANSARRAY*) lpFixedPointer;
\r
148 _stprintf_s(strLangProduktVersion, MAX_PATH, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
\r
149 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
\r
151 if (VerQueryValue(pBuffer,
\r
152 (LPTSTR)strLangProduktVersion,
\r
153 (LPVOID *)&lpVersion,
\r
156 // versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
\r
162 } // if (pBuffer != (void*) NULL)
\r
163 } // if (dwBufferSize > 0)
\r
165 versionmatch = FALSE;
\r
168 hInst = LoadLibrary(langDll);
\r
171 if (g_hResInst != g_hmodThisDll)
\r
172 FreeLibrary(g_hResInst);
\r
173 g_hResInst = hInst;
\r
177 DWORD lid = SUBLANGID(langId);
\r
181 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
\r
186 } while ((hInst == NULL) && (langId != 0));
\r
189 // either the dll for the selected language is not present, or
\r
190 // it is the wrong version.
\r
191 // fall back to English and set a timeout so we don't retry
\r
192 // to load the language dll too often
\r
193 if (g_hResInst != g_hmodThisDll)
\r
194 FreeLibrary(g_hResInst);
\r
195 g_hResInst = g_hmodThisDll;
\r
197 // set a timeout of 10 seconds
\r
198 if (g_ShellCache.GetLangID() != 1033)
\r
199 g_langTimeout = GetTickCount() + 10000;
\r
203 } // if (g_langid != g_ShellCache.GetLangID())
\r
206 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
\r
210 if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
\r
212 *ppv = (LPSHELLEXTINIT)this;
\r
214 else if (IsEqualIID(riid, IID_IContextMenu))
\r
216 *ppv = (LPCONTEXTMENU)this;
\r
218 else if (IsEqualIID(riid, IID_IContextMenu2))
\r
220 *ppv = (LPCONTEXTMENU2)this;
\r
222 else if (IsEqualIID(riid, IID_IContextMenu3))
\r
224 *ppv = (LPCONTEXTMENU3)this;
\r
226 else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))
\r
228 *ppv = (IShellIconOverlayIdentifier*)this;
\r
230 else if (IsEqualIID(riid, IID_IShellPropSheetExt))
\r
232 *ppv = (LPSHELLPROPSHEETEXT)this;
\r
234 else if (IsEqualIID(riid, IID_IColumnProvider))
\r
236 *ppv = (IColumnProvider *)this;
\r
238 else if (IsEqualIID(riid, IID_IShellCopyHook))
\r
240 *ppv = (ICopyHook *)this;
\r
249 return E_NOINTERFACE;
\r
252 STDMETHODIMP_(ULONG) CShellExt::AddRef()
\r
257 STDMETHODIMP_(ULONG) CShellExt::Release()
\r
267 // IPersistFile members
\r
268 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid)
\r
270 *pclsid = CLSID_Tortoisegit_UNCONTROLLED;
\r
274 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)
\r
279 // ICopyHook member
\r
280 UINT __stdcall CShellExt::CopyCallback(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)
\r
282 if (wFunc == FO_COPY)
\r
283 return IDYES; // copying is not a problem for us
\r
285 // m_remoteCacheLink.ReleaseLockForPath(CTSVNPath(pszSrcFile));
\r
286 // we could now wait a little bit to give the cache time to release the handles.
\r
287 // but the explorer/shell already retries any action for about two seconds
\r
288 // if it first fails. So if the cache hasn't released the handle yet, the explorer
\r
289 // will retry anyway, so we just leave here immediately.
\r
292 // CShellExt member functions (needed for IShellPropSheetExt)
\r
293 STDMETHODIMP CShellExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage,
\r
297 for (std::vector<stdstring>::iterator I = files_.begin(); I != files_.end(); ++I)
\r
299 GitStatus svn = GitStatus();
\r
300 if (svn.GetStatus(CTGitPath(I->c_str())) == (-2))
\r
301 return NOERROR; // file/directory not under version control
\r
303 if (svn.status->entry == NULL)
\r
307 if (files_.size() == 0)
\r
312 SecureZeroMemory(&psp, sizeof(PROPSHEETPAGE));
\r
313 HPROPSHEETPAGE hPage;
\r
314 CGitPropertyPage *sheetpage = new CGitPropertyPage(files_);
\r
316 psp.dwSize = sizeof (psp);
\r
317 psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USEICONID | PSP_USECALLBACK;
\r
318 psp.hInstance = g_hResInst;
\r
319 psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE);
\r
320 psp.pszIcon = MAKEINTRESOURCE(IDI_APPSMALL);
\r
321 psp.pszTitle = _T("Subversion");
\r
322 psp.pfnDlgProc = (DLGPROC) PageProc;
\r
323 psp.lParam = (LPARAM) sheetpage;
\r
324 psp.pfnCallback = PropPageCallbackProc;
\r
325 psp.pcRefParent = &g_cRefThisDll;
\r
327 hPage = CreatePropertySheetPage (&psp);
\r
331 if (!lpfnAddPage (hPage, lParam))
\r
334 DestroyPropertySheetPage (hPage);
\r
343 STDMETHODIMP CShellExt::ReplacePage (UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)
\r