1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2014 - TortoiseGit
4 // Copyright (C) 2003-2013 - 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.
22 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
27 #include "ShellObjects.h"
28 #include "..\version.h"
31 extern ShellObjects g_shellObjects
;
33 // *********************** CShellExt *************************
34 CShellExt::CShellExt(FileState state
)
39 #if ENABLE_CRASHHANLDER
40 , m_crasher(L
"TortoiseGit", TGIT_VERMAJOR
, TGIT_VERMINOR
, TGIT_VERMICRO
, TGIT_VERBUILD
, TGIT_VERDATE
, false)
42 ,regDiffLater(L
"Software\\TortoiseGit\\DiffLater", L
"")
45 InterlockedIncrement(&g_cRefThisDll
);
48 AutoLocker
lock(g_csGlobalCOMGuard
);
49 g_shellObjects
.Insert(this);
52 INITCOMMONCONTROLSEX used
= {
53 sizeof(INITCOMMONCONTROLSEX
),
54 ICC_LISTVIEW_CLASSES
| ICC_WIN95_CLASSES
| ICC_BAR_CLASSES
| ICC_USEREX_CLASSES
56 InitCommonControlsEx(&used
);
60 CShellExt::~CShellExt()
62 AutoLocker
lock(g_csGlobalCOMGuard
);
63 InterlockedDecrement(&g_cRefThisDll
);
64 g_shellObjects
.Erase(this);
69 if ((g_langid
!= g_ShellCache
.GetLangID())&&((g_langTimeout
== 0)||(g_langTimeout
< GetTickCount())))
71 g_langid
= g_ShellCache
.GetLangID();
72 DWORD langId
= g_langid
;
73 TCHAR langDll
[MAX_PATH
*4] = {0};
74 HINSTANCE hInst
= NULL
;
75 TCHAR langdir
[MAX_PATH
] = {0};
76 char langdirA
[MAX_PATH
] = {0};
77 if (GetModuleFileName(g_hmodThisDll
, langdir
, _countof(langdir
))==0)
79 if (GetModuleFileNameA(g_hmodThisDll
, langdirA
, _countof(langdirA
))==0)
81 TCHAR
* dirpoint
= _tcsrchr(langdir
, '\\');
82 char * dirpointA
= strrchr(langdirA
, '\\');
87 dirpoint
= _tcsrchr(langdir
, '\\');
88 dirpointA
= strrchr(langdirA
, '\\');
93 strcat_s(langdirA
, "\\Languages");
96 IsWow64Process(GetCurrentProcess(), &bIsWow
);
101 _stprintf_s(langDll
, _T("%s\\Languages\\TortoiseProc32%lu.dll"), langdir
, langId
);
103 _stprintf_s(langDll
, _T("%s\\Languages\\TortoiseProc%lu.dll"), langdir
, langId
);
104 BOOL versionmatch
= TRUE
;
112 DWORD dwReserved
,dwBufferSize
;
113 dwBufferSize
= GetFileVersionInfoSize((LPTSTR
)langDll
,&dwReserved
);
115 if (dwBufferSize
> 0)
117 LPVOID pBuffer
= (void*) malloc(dwBufferSize
);
119 if (pBuffer
!= (void*) NULL
)
122 UINT nFixedLength
= 0;
123 LPSTR lpVersion
= NULL
;
124 VOID
* lpFixedPointer
;
125 TRANSARRAY
* lpTransArray
;
126 TCHAR strLangProductVersion
[MAX_PATH
] = {0};
128 if (GetFileVersionInfo((LPTSTR
)langDll
,
133 // Query the current language
134 if (VerQueryValue( pBuffer
,
135 _T("\\VarFileInfo\\Translation"),
139 lpTransArray
= (TRANSARRAY
*) lpFixedPointer
;
141 _stprintf_s(strLangProductVersion
, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),
142 lpTransArray
[0].wLanguageID
, lpTransArray
[0].wCharacterSet
);
144 if (VerQueryValue(pBuffer
,
145 (LPTSTR
)strLangProductVersion
,
146 (LPVOID
*)&lpVersion
,
149 versionmatch
= (_tcscmp((LPCTSTR
)lpVersion
, _T(STRPRODUCTVER
)) == 0);
155 } // if (pBuffer != (void*) NULL)
156 } // if (dwBufferSize > 0)
158 versionmatch
= FALSE
;
161 hInst
= LoadLibrary(langDll
);
164 if (g_hResInst
!= g_hmodThisDll
)
165 FreeLibrary(g_hResInst
);
170 DWORD lid
= SUBLANGID(langId
);
174 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
179 } while ((hInst
== NULL
) && (langId
!= 0));
182 // either the dll for the selected language is not present, or
183 // it is the wrong version.
184 // fall back to English and set a timeout so we don't retry
185 // to load the language dll too often
186 if (g_hResInst
!= g_hmodThisDll
)
187 FreeLibrary(g_hResInst
);
188 g_hResInst
= g_hmodThisDll
;
190 // set a timeout of 10 seconds
191 if (g_ShellCache
.GetLangID() != 1033)
192 g_langTimeout
= GetTickCount() + 10000;
196 } // if (g_langid != g_ShellCache.GetLangID())
199 STDMETHODIMP
CShellExt::QueryInterface(REFIID riid
, LPVOID FAR
*ppv
)
206 if (IsEqualIID(riid
, IID_IShellExtInit
) || IsEqualIID(riid
, IID_IUnknown
))
208 *ppv
= static_cast<LPSHELLEXTINIT
>(this);
210 else if (IsEqualIID(riid
, IID_IContextMenu
))
212 *ppv
= static_cast<LPCONTEXTMENU
>(this);
214 else if (IsEqualIID(riid
, IID_IContextMenu2
))
216 *ppv
= static_cast<LPCONTEXTMENU2
>(this);
218 else if (IsEqualIID(riid
, IID_IContextMenu3
))
220 *ppv
= static_cast<LPCONTEXTMENU3
>(this);
222 else if (IsEqualIID(riid
, IID_IShellIconOverlayIdentifier
))
224 *ppv
= static_cast<IShellIconOverlayIdentifier
*>(this);
226 else if (IsEqualIID(riid
, IID_IShellPropSheetExt
))
228 *ppv
= static_cast<LPSHELLPROPSHEETEXT
>(this);
230 else if (IsEqualIID(riid
, IID_IShellCopyHook
))
232 *ppv
= static_cast<ICopyHook
*>(this);
236 return E_NOINTERFACE
;
243 STDMETHODIMP_(ULONG
) CShellExt::AddRef()
248 STDMETHODIMP_(ULONG
) CShellExt::Release()
258 // IPersistFile members
259 STDMETHODIMP
CShellExt::GetClassID(CLSID
*pclsid
)
263 *pclsid
= CLSID_Tortoisegit_UNCONTROLLED
;
267 STDMETHODIMP
CShellExt::Load(LPCOLESTR
/*pszFileName*/, DWORD
/*dwMode*/)
273 UINT __stdcall
CShellExt::CopyCallback(HWND hWnd
, UINT wFunc
, UINT wFlags
, LPCTSTR pszSrcFile
, DWORD dwSrcAttribs
, LPCTSTR pszDestFile
, DWORD dwDestAttribs
)
277 return CopyCallback_Wrap(hWnd
, wFunc
, wFlags
, pszSrcFile
, dwSrcAttribs
, pszDestFile
, dwDestAttribs
);
279 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
285 UINT __stdcall
CShellExt::CopyCallback_Wrap(HWND
/*hWnd*/, UINT wFunc
, UINT
/*wFlags*/, LPCTSTR pszSrcFile
, DWORD
/*dwSrcAttribs*/, LPCTSTR
/*pszDestFile*/, DWORD
/*dwDestAttribs*/)
292 if (pszSrcFile
&& pszSrcFile
[0])
295 if (g_GitAdminDir
.HasAdminDir(pszSrcFile
, &topDir
))
296 m_CachedStatus
.m_GitStatus
.ReleasePath(topDir
);
297 m_remoteCacheLink
.ReleaseLockForPath(CTGitPath(pszSrcFile
));
304 // we could now wait a little bit to give the cache time to release the handles.
305 // but the explorer/shell already retries any action for about two seconds
306 // if it first fails. So if the cache hasn't released the handle yet, the explorer
307 // will retry anyway, so we just leave here immediately.