1 // TortoiseSVN - 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.
21 #pragma warning (disable : 4786)
23 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
28 //#include "..\version.h"
29 //#include "libintl.h"
32 std::set
<CShellExt
*> g_exts
;
34 // *********************** CShellExt *************************
35 CShellExt::CShellExt(FileState state
)
38 SecureZeroMemory(&inf
, sizeof(OSVERSIONINFOEX
));
39 inf
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
40 GetVersionEx((OSVERSIONINFO
*)&inf
);
41 fullver
= MAKEWORD(inf
.dwMinorVersion
, inf
.dwMajorVersion
);
50 INITCOMMONCONTROLSEX used
= {
51 sizeof(INITCOMMONCONTROLSEX
),
52 ICC_LISTVIEW_CLASSES
| ICC_WIN95_CLASSES
| ICC_BAR_CLASSES
| ICC_USEREX_CLASSES
54 InitCommonControlsEx(&used
);
57 if (fullver
>= 0x0600)
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 std::map
<UINT
, HBITMAP
>::iterator it
;
70 for (it
= bitmaps
.begin(); it
!= bitmaps
.end(); ++it
)
72 ::DeleteObject(it
->second
);
81 if ((g_langid
!= g_ShellCache
.GetLangID())&&((g_langTimeout
== 0)||(g_langTimeout
< GetTickCount())))
83 g_langid
= g_ShellCache
.GetLangID();
84 DWORD langId
= g_langid
;
85 TCHAR langDll
[MAX_PATH
*4];
86 HINSTANCE hInst
= NULL
;
87 TCHAR langdir
[MAX_PATH
] = {0};
88 char langdirA
[MAX_PATH
] = {0};
89 if (GetModuleFileName(g_hmodThisDll
, langdir
, MAX_PATH
)==0)
91 if (GetModuleFileNameA(g_hmodThisDll
, langdirA
, MAX_PATH
)==0)
93 TCHAR
* dirpoint
= _tcsrchr(langdir
, '\\');
94 char * dirpointA
= strrchr(langdirA
, '\\');
99 dirpoint
= _tcsrchr(langdir
, '\\');
100 dirpointA
= strrchr(langdirA
, '\\');
105 strcat_s(langdirA
, MAX_PATH
, "\\Languages");
106 // bindtextdomain ("subversion", langdirA);
110 _stprintf_s(langDll
, MAX_PATH
*4, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir
, langId
);
111 BOOL versionmatch
= TRUE
;
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
)
130 LPSTR lpVersion
= NULL
;
131 VOID
* lpFixedPointer
;
132 TRANSARRAY
* lpTransArray
;
133 TCHAR strLangProduktVersion
[MAX_PATH
];
135 if (GetFileVersionInfo((LPTSTR
)langDll
,
140 // Query the current language
141 if (VerQueryValue( pBuffer
,
142 _T("\\VarFileInfo\\Translation"),
146 lpTransArray
= (TRANSARRAY
*) lpFixedPointer
;
148 _stprintf_s(strLangProduktVersion
, MAX_PATH
, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
149 lpTransArray
[0].wLanguageID
, lpTransArray
[0].wCharacterSet
);
151 if (VerQueryValue(pBuffer
,
152 (LPTSTR
)strLangProduktVersion
,
153 (LPVOID
*)&lpVersion
,
156 // versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);
162 } // if (pBuffer != (void*) NULL)
163 } // if (dwBufferSize > 0)
165 versionmatch
= FALSE
;
168 hInst
= LoadLibrary(langDll
);
171 if (g_hResInst
!= g_hmodThisDll
)
172 FreeLibrary(g_hResInst
);
177 DWORD lid
= SUBLANGID(langId
);
181 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
186 } while ((hInst
== NULL
) && (langId
!= 0));
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
;
197 // set a timeout of 10 seconds
198 if (g_ShellCache
.GetLangID() != 1033)
199 g_langTimeout
= GetTickCount() + 10000;
203 } // if (g_langid != g_ShellCache.GetLangID())
206 STDMETHODIMP
CShellExt::QueryInterface(REFIID riid
, LPVOID FAR
*ppv
)
210 if (IsEqualIID(riid
, IID_IShellExtInit
) || IsEqualIID(riid
, IID_IUnknown
))
212 *ppv
= (LPSHELLEXTINIT
)this;
214 else if (IsEqualIID(riid
, IID_IContextMenu
))
216 *ppv
= (LPCONTEXTMENU
)this;
218 else if (IsEqualIID(riid
, IID_IContextMenu2
))
220 *ppv
= (LPCONTEXTMENU2
)this;
222 else if (IsEqualIID(riid
, IID_IContextMenu3
))
224 *ppv
= (LPCONTEXTMENU3
)this;
226 else if (IsEqualIID(riid
, IID_IShellIconOverlayIdentifier
))
228 *ppv
= (IShellIconOverlayIdentifier
*)this;
230 else if (IsEqualIID(riid
, IID_IShellPropSheetExt
))
232 *ppv
= (LPSHELLPROPSHEETEXT
)this;
234 else if (IsEqualIID(riid
, IID_IColumnProvider
))
236 *ppv
= (IColumnProvider
*)this;
238 else if (IsEqualIID(riid
, IID_IShellCopyHook
))
240 *ppv
= (ICopyHook
*)this;
249 return E_NOINTERFACE
;
252 STDMETHODIMP_(ULONG
) CShellExt::AddRef()
257 STDMETHODIMP_(ULONG
) CShellExt::Release()
267 // IPersistFile members
268 STDMETHODIMP
CShellExt::GetClassID(CLSID
*pclsid
)
270 *pclsid
= CLSID_Tortoisegit_UNCONTROLLED
;
274 STDMETHODIMP
CShellExt::Load(LPCOLESTR
/*pszFileName*/, DWORD
/*dwMode*/)
280 UINT __stdcall
CShellExt::CopyCallback(HWND
/*hWnd*/, UINT wFunc
, UINT
/*wFlags*/, LPCTSTR pszSrcFile
, DWORD
/*dwSrcAttribs*/, LPCTSTR
/*pszDestFile*/, DWORD
/*dwDestAttribs*/)
282 if (wFunc
== FO_COPY
)
283 return IDYES
; // copying is not a problem for us
285 m_remoteCacheLink
.ReleaseLockForPath(CTGitPath(pszSrcFile
));
286 // we could now wait a little bit to give the cache time to release the handles.
287 // but the explorer/shell already retries any action for about two seconds
288 // if it first fails. So if the cache hasn't released the handle yet, the explorer
289 // will retry anyway, so we just leave here immediately.
292 // CShellExt member functions (needed for IShellPropSheetExt)
293 STDMETHODIMP
CShellExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage
,
297 for (std::vector
<stdstring
>::iterator I
= files_
.begin(); I
!= files_
.end(); ++I
)
299 GitStatus svn
= GitStatus();
300 if (svn
.GetStatus(CTGitPath(I
->c_str())) == (-2))
301 return NOERROR
; // file/directory not under version control
303 if (svn
.status
->entry
== NULL
)
307 if (files_
.size() == 0)
312 SecureZeroMemory(&psp
, sizeof(PROPSHEETPAGE
));
313 HPROPSHEETPAGE hPage
;
314 CGitPropertyPage
*sheetpage
= new CGitPropertyPage(files_
);
316 psp
.dwSize
= sizeof (psp
);
317 psp
.dwFlags
= PSP_USEREFPARENT
| PSP_USETITLE
| PSP_USEICONID
| PSP_USECALLBACK
;
318 psp
.hInstance
= g_hResInst
;
319 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_PROPPAGE
);
320 psp
.pszIcon
= MAKEINTRESOURCE(IDI_APPSMALL
);
321 psp
.pszTitle
= _T("Subversion");
322 psp
.pfnDlgProc
= (DLGPROC
) PageProc
;
323 psp
.lParam
= (LPARAM
) sheetpage
;
324 psp
.pfnCallback
= PropPageCallbackProc
;
325 psp
.pcRefParent
= &g_cRefThisDll
;
327 hPage
= CreatePropertySheetPage (&psp
);
331 if (!lpfnAddPage (hPage
, lParam
))
334 DestroyPropertySheetPage (hPage
);
343 STDMETHODIMP
CShellExt::ReplacePage (UINT
/*uPageID*/, LPFNADDPROPSHEETPAGE
/*lpfnReplaceWith*/, LPARAM
/*lParam*/)