1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2018 - TortoiseGit
4 // Copyright (C) 2003-2014 - 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"
29 #include "GitAdminDir.h"
32 extern ShellObjects g_shellObjects
;
34 // *********************** CShellExt *************************
35 CShellExt::CShellExt(FileState state
)
41 ,regDiffLater(L
"Software\\TortoiseGit\\DiffLater", L
"")
43 InterlockedIncrement(&g_cRefThisDll
);
46 AutoLocker
lock(g_csGlobalCOMGuard
);
47 g_shellObjects
.Insert(this);
50 INITCOMMONCONTROLSEX used
= {
51 sizeof(INITCOMMONCONTROLSEX
),
52 ICC_LISTVIEW_CLASSES
| ICC_WIN95_CLASSES
| ICC_BAR_CLASSES
| ICC_USEREX_CLASSES
54 InitCommonControlsEx(&used
);
58 CShellExt::~CShellExt()
60 AutoLocker
lock(g_csGlobalCOMGuard
);
61 InterlockedDecrement(&g_cRefThisDll
);
62 g_shellObjects
.Erase(this);
67 if (g_langid
!= g_ShellCache
.GetLangID() && (g_langTimeout
== 0 || g_langTimeout
< GetTickCount64()))
69 g_langid
= g_ShellCache
.GetLangID();
70 DWORD langId
= g_langid
;
71 TCHAR langDll
[MAX_PATH
*4] = {0};
72 HINSTANCE hInst
= nullptr;
73 TCHAR langdir
[MAX_PATH
] = {0};
74 if (GetModuleFileName(g_hmodThisDll
, langdir
, _countof(langdir
))==0)
76 TCHAR
* dirpoint
= wcsrchr(langdir
, L
'\\');
79 dirpoint
= wcsrchr(langdir
, L
'\\');
84 IsWow64Process(GetCurrentProcess(), &bIsWow
);
89 swprintf_s(langDll
, L
"%s\\Languages\\TortoiseProc32%lu.dll", langdir
, langId
);
91 swprintf_s(langDll
, L
"%s\\Languages\\TortoiseProc%lu.dll", langdir
, langId
);
92 BOOL versionmatch
= TRUE
;
100 DWORD dwReserved
,dwBufferSize
;
101 dwBufferSize
= GetFileVersionInfoSize((LPTSTR
)langDll
,&dwReserved
);
103 if (dwBufferSize
> 0)
105 LPVOID pBuffer
= (void*) malloc(dwBufferSize
);
110 UINT nFixedLength
= 0;
111 LPSTR lpVersion
= nullptr;
112 VOID
* lpFixedPointer
;
114 if (GetFileVersionInfo((LPTSTR
)langDll
,
119 // Query the current language
120 if (VerQueryValue( pBuffer
,
121 L
"\\VarFileInfo\\Translation",
125 auto lpTransArray
= reinterpret_cast<TRANSARRAY
*>(lpFixedPointer
);
126 TCHAR strLangProductVersion
[MAX_PATH
] = { 0 };
128 swprintf_s(strLangProductVersion
, L
"\\StringFileInfo\\%04x%04x\\ProductVersion",
129 lpTransArray
[0].wLanguageID
, lpTransArray
[0].wCharacterSet
);
131 if (VerQueryValue(pBuffer
, (LPTSTR
)strLangProductVersion
, (LPVOID
*)&lpVersion
, &nInfoSize
))
132 versionmatch
= (wcscmp((LPCTSTR
)lpVersion
, _T(STRPRODUCTVER
)) == 0);
138 } // if (dwBufferSize > 0)
140 versionmatch
= FALSE
;
143 hInst
= LoadLibrary(langDll
);
146 if (g_hResInst
!= g_hmodThisDll
)
147 FreeLibrary(g_hResInst
);
152 DWORD lid
= SUBLANGID(langId
);
155 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
159 } while (!hInst
&& langId
!= 0);
162 // either the dll for the selected language is not present, or
163 // it is the wrong version.
164 // fall back to English and set a timeout so we don't retry
165 // to load the language dll too often
166 if (g_hResInst
!= g_hmodThisDll
)
167 FreeLibrary(g_hResInst
);
168 g_hResInst
= g_hmodThisDll
;
170 // set a timeout of 10 seconds
171 if (g_ShellCache
.GetLangID() != 1033)
172 g_langTimeout
= GetTickCount64() + 10000;
176 } // if (g_langid != g_ShellCache.GetLangID())
179 STDMETHODIMP
CShellExt::QueryInterface(REFIID riid
, LPVOID FAR
*ppv
)
186 if (IsEqualIID(riid
, IID_IShellExtInit
) || IsEqualIID(riid
, IID_IUnknown
))
187 *ppv
= static_cast<LPSHELLEXTINIT
>(this);
188 else if (IsEqualIID(riid
, IID_IContextMenu
))
189 *ppv
= static_cast<LPCONTEXTMENU
>(this);
190 else if (IsEqualIID(riid
, IID_IContextMenu2
))
191 *ppv
= static_cast<LPCONTEXTMENU2
>(this);
192 else if (IsEqualIID(riid
, IID_IContextMenu3
))
193 *ppv
= static_cast<LPCONTEXTMENU3
>(this);
194 else if (IsEqualIID(riid
, IID_IShellIconOverlayIdentifier
))
195 *ppv
= static_cast<IShellIconOverlayIdentifier
*>(this);
196 else if (IsEqualIID(riid
, IID_IShellPropSheetExt
))
197 *ppv
= static_cast<LPSHELLPROPSHEETEXT
>(this);
198 else if (IsEqualIID(riid
, IID_IShellCopyHook
))
199 *ppv
= static_cast<ICopyHook
*>(this);
201 return E_NOINTERFACE
;
207 STDMETHODIMP_(ULONG
) CShellExt::AddRef()
209 return InterlockedIncrement(&m_cRef
);
212 STDMETHODIMP_(ULONG
) CShellExt::Release()
214 if (InterlockedDecrement(&m_cRef
))
222 // IPersistFile members
223 STDMETHODIMP
CShellExt::GetClassID(CLSID
*pclsid
)
227 *pclsid
= CLSID_Tortoisegit_UNCONTROLLED
;
231 STDMETHODIMP
CShellExt::Load(LPCOLESTR
/*pszFileName*/, DWORD
/*dwMode*/)
237 UINT __stdcall
CShellExt::CopyCallback(HWND
/*hWnd*/, UINT wFunc
, UINT
/*wFlags*/, LPCTSTR pszSrcFile
, DWORD
/*dwSrcAttribs*/, LPCTSTR
/*pszDestFile*/, DWORD
/*dwDestAttribs*/)
244 if (pszSrcFile
&& pszSrcFile
[0] && g_ShellCache
.IsPathAllowed(pszSrcFile
))
246 auto cacheType
= g_ShellCache
.GetCacheType();
249 case ShellCache::exe
:
250 m_remoteCacheLink
.ReleaseLockForPath(CTGitPath(pszSrcFile
));
252 case ShellCache::dll
:
253 case ShellCache::dllFull
:
256 if (GitAdminDir::HasAdminDir(pszSrcFile
, &topDir
))
257 m_CachedStatus
.m_GitStatus
.ReleasePath(topDir
);
269 // we could now wait a little bit to give the cache time to release the handles.
270 // but the explorer/shell already retries any action for about two seconds
271 // if it first fails. So if the cache hasn't released the handle yet, the explorer
272 // will retry anyway, so we just leave here immediately.