OSDN Git Service

Commit File List can show file and sort
[tortoisegit/TortoiseGitJp.git] / TortoiseShell / ShellExt.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseSVN\r
4 \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
9 \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
14 \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
18 //\r
19 #include "stdafx.h"\r
20 \r
21 #pragma warning (disable : 4786)\r
22 \r
23 // Initialize GUIDs (should be done only and at-least once per DLL/EXE)\r
24 #include <initguid.h>\r
25 #include "Guids.h"\r
26 \r
27 #include "ShellExt.h"\r
28 //#include "..\version.h"\r
29 //#include "libintl.h"\r
30 #undef swprintf\r
31 \r
32 std::set<CShellExt *> g_exts;\r
33 \r
34 \r
35 // *********************** CShellExt *************************\r
36 CShellExt::CShellExt(FileState state)\r
37 {\r
38         OSVERSIONINFOEX inf;\r
39         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
40         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
41         GetVersionEx((OSVERSIONINFO *)&inf);\r
42         fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
43 \r
44     m_State = state;\r
45 \r
46     m_cRef = 0L;\r
47     g_cRefThisDll++;\r
48 \r
49         g_exts.insert(this);\r
50         \r
51     INITCOMMONCONTROLSEX used = {\r
52         sizeof(INITCOMMONCONTROLSEX),\r
53                         ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES\r
54     };\r
55     InitCommonControlsEx(&used);\r
56         LoadLangDll();\r
57 \r
58         if (fullver >= 0x0600)\r
59         {\r
60                 HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL"));\r
61 \r
62                 pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits");\r
63                 pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint");\r
64                 pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint");\r
65         }\r
66 }\r
67 \r
68 CShellExt::~CShellExt()\r
69 {\r
70         std::map<UINT, HBITMAP>::iterator it;\r
71         for (it = bitmaps.begin(); it != bitmaps.end(); ++it)\r
72         {\r
73                 ::DeleteObject(it->second);\r
74         }\r
75         bitmaps.clear();\r
76         g_cRefThisDll--;\r
77         g_exts.erase(this);\r
78 }\r
79 \r
80 void LoadLangDll()\r
81 {\r
82         if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))\r
83         {\r
84                 g_langid = g_ShellCache.GetLangID();\r
85                 DWORD langId = g_langid;\r
86                 TCHAR langDll[MAX_PATH*4];\r
87                 HINSTANCE hInst = NULL;\r
88                 TCHAR langdir[MAX_PATH] = {0};\r
89                 char langdirA[MAX_PATH] = {0};\r
90                 if (GetModuleFileName(g_hmodThisDll, langdir, MAX_PATH)==0)\r
91                         return;\r
92                 if (GetModuleFileNameA(g_hmodThisDll, langdirA, MAX_PATH)==0)\r
93                         return;\r
94                 TCHAR * dirpoint = _tcsrchr(langdir, '\\');\r
95                 char * dirpointA = strrchr(langdirA, '\\');\r
96                 if (dirpoint)\r
97                         *dirpoint = 0;\r
98                 if (dirpointA)\r
99                         *dirpointA = 0;\r
100                 dirpoint = _tcsrchr(langdir, '\\');\r
101                 dirpointA = strrchr(langdirA, '\\');\r
102                 if (dirpoint)\r
103                         *dirpoint = 0;\r
104                 if (dirpointA)\r
105                         *dirpointA = 0;\r
106                 strcat_s(langdirA, MAX_PATH, "\\Languages");\r
107 //              bindtextdomain ("subversion", langdirA);\r
108 \r
109                 do\r
110                 {\r
111                         _stprintf_s(langDll, MAX_PATH*4, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir, langId);\r
112                         BOOL versionmatch = TRUE;\r
113 \r
114                         struct TRANSARRAY\r
115                         {\r
116                                 WORD wLanguageID;\r
117                                 WORD wCharacterSet;\r
118                         };\r
119 \r
120                         DWORD dwReserved,dwBufferSize;\r
121                         dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);\r
122 \r
123                         if (dwBufferSize > 0)\r
124                         {\r
125                                 LPVOID pBuffer = (void*) malloc(dwBufferSize);\r
126 \r
127                                 if (pBuffer != (void*) NULL)\r
128                                 {\r
129                                         UINT        nInfoSize = 0,\r
130                                                 nFixedLength = 0;\r
131                                         LPSTR       lpVersion = NULL;\r
132                                         VOID*       lpFixedPointer;\r
133                                         TRANSARRAY* lpTransArray;\r
134                                         TCHAR       strLangProduktVersion[MAX_PATH];\r
135 \r
136                                         if (GetFileVersionInfo((LPTSTR)langDll,\r
137                                                 dwReserved,\r
138                                                 dwBufferSize,\r
139                                                 pBuffer))\r
140                                         {\r
141                                                 // Query the current language\r
142                                                 if (VerQueryValue(      pBuffer,\r
143                                                         _T("\\VarFileInfo\\Translation"),\r
144                                                         &lpFixedPointer,\r
145                                                         &nFixedLength))\r
146                                                 {\r
147                                                         lpTransArray = (TRANSARRAY*) lpFixedPointer;\r
148 \r
149                                                         _stprintf_s(strLangProduktVersion, MAX_PATH, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),\r
150                                                                 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);\r
151 \r
152                                                         if (VerQueryValue(pBuffer,\r
153                                                                 (LPTSTR)strLangProduktVersion,\r
154                                                                 (LPVOID *)&lpVersion,\r
155                                                                 &nInfoSize))\r
156                                                         {\r
157 //                                                              versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);\r
158                                                         }\r
159 \r
160                                                 }\r
161                                         }\r
162                                         free(pBuffer);\r
163                                 } // if (pBuffer != (void*) NULL) \r
164                         } // if (dwBufferSize > 0) \r
165                         else\r
166                                 versionmatch = FALSE; \r
167 \r
168                         if (versionmatch)\r
169                                 hInst = LoadLibrary(langDll);\r
170                         if (hInst != NULL)\r
171                         {\r
172                                 if (g_hResInst != g_hmodThisDll)\r
173                                         FreeLibrary(g_hResInst);\r
174                                 g_hResInst = hInst;\r
175                         }\r
176                         else\r
177                         {\r
178                                 DWORD lid = SUBLANGID(langId);\r
179                                 lid--;\r
180                                 if (lid > 0)\r
181                                 {\r
182                                         langId = MAKELANGID(PRIMARYLANGID(langId), lid);\r
183                                 }\r
184                                 else\r
185                                         langId = 0;\r
186                         } \r
187                 } while ((hInst == NULL) && (langId != 0));\r
188                 if (hInst == NULL)\r
189                 {\r
190                         // either the dll for the selected language is not present, or\r
191                         // it is the wrong version.\r
192                         // fall back to English and set a timeout so we don't retry\r
193                         // to load the language dll too often\r
194                         if (g_hResInst != g_hmodThisDll)\r
195                                 FreeLibrary(g_hResInst);\r
196                         g_hResInst = g_hmodThisDll;\r
197                         g_langid = 1033;\r
198                         // set a timeout of 10 seconds\r
199                         if (g_ShellCache.GetLangID() != 1033)\r
200                                 g_langTimeout = GetTickCount() + 10000;\r
201                 }\r
202                 else\r
203                         g_langTimeout = 0;\r
204         } // if (g_langid != g_ShellCache.GetLangID()) \r
205 }\r
206 \r
207 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)\r
208 {\r
209     *ppv = NULL; \r
210 \r
211     if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))\r
212     {\r
213         *ppv = (LPSHELLEXTINIT)this;\r
214     }\r
215     else if (IsEqualIID(riid, IID_IContextMenu))\r
216     {\r
217         *ppv = (LPCONTEXTMENU)this;\r
218     }\r
219     else if (IsEqualIID(riid, IID_IContextMenu2))\r
220     {\r
221         *ppv = (LPCONTEXTMENU2)this;\r
222     }\r
223     else if (IsEqualIID(riid, IID_IContextMenu3))\r
224     {\r
225         *ppv = (LPCONTEXTMENU3)this;\r
226     }\r
227     else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))\r
228     {\r
229         *ppv = (IShellIconOverlayIdentifier*)this;\r
230     }\r
231     else if (IsEqualIID(riid, IID_IShellPropSheetExt))\r
232     {\r
233         *ppv = (LPSHELLPROPSHEETEXT)this;\r
234     }\r
235         else if (IsEqualIID(riid, IID_IColumnProvider)) \r
236         { \r
237                 *ppv = (IColumnProvider *)this;\r
238         } \r
239         else if (IsEqualIID(riid, IID_IShellCopyHook))\r
240         {\r
241                 *ppv = (ICopyHook *)this;\r
242         }\r
243     if (*ppv)\r
244     {\r
245         AddRef();\r
246                 \r
247         return NOERROR;\r
248     }\r
249         \r
250     return E_NOINTERFACE;\r
251 }\r
252 \r
253 STDMETHODIMP_(ULONG) CShellExt::AddRef()\r
254 {\r
255     return ++m_cRef;\r
256 }\r
257 \r
258 STDMETHODIMP_(ULONG) CShellExt::Release()\r
259 {\r
260     if (--m_cRef)\r
261         return m_cRef;\r
262         \r
263     delete this;\r
264         \r
265     return 0L;\r
266 }\r
267 \r
268 // IPersistFile members\r
269 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid) \r
270 {\r
271     *pclsid = CLSID_Tortoisegit_UNCONTROLLED;\r
272     return S_OK;\r
273 }\r
274 \r
275 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)\r
276 {\r
277     return S_OK;\r
278 }\r
279 \r
280 // ICopyHook member\r
281 UINT __stdcall CShellExt::CopyCallback(HWND /*hWnd*/, UINT wFunc, UINT /*wFlags*/, LPCTSTR pszSrcFile, DWORD /*dwSrcAttribs*/, LPCTSTR /*pszDestFile*/, DWORD /*dwDestAttribs*/)\r
282 {\r
283         if (wFunc == FO_COPY)\r
284                 return IDYES;   // copying is not a problem for us\r
285 \r
286 //      m_remoteCacheLink.ReleaseLockForPath(CTSVNPath(pszSrcFile));\r
287         // we could now wait a little bit to give the cache time to release the handles.\r
288         // but the explorer/shell already retries any action for about two seconds\r
289         // if it first fails. So if the cache hasn't released the handle yet, the explorer\r
290         // will retry anyway, so we just leave here immediately.\r
291         return IDYES;\r
292 }\r
293 // CShellExt member functions (needed for IShellPropSheetExt)\r
294 STDMETHODIMP CShellExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage,\r
295                                   LPARAM lParam)\r
296 {\r
297 #if 0\r
298         for (std::vector<stdstring>::iterator I = files_.begin(); I != files_.end(); ++I)\r
299         {\r
300                 GitStatus svn = GitStatus();\r
301                 if (svn.GetStatus(CTGitPath(I->c_str())) == (-2))\r
302                         return NOERROR;                 // file/directory not under version control\r
303 \r
304                 if (svn.status->entry == NULL)\r
305                         return NOERROR;\r
306         }\r
307 \r
308         if (files_.size() == 0)\r
309                 return NOERROR;\r
310 \r
311         LoadLangDll();\r
312     PROPSHEETPAGE psp;\r
313         SecureZeroMemory(&psp, sizeof(PROPSHEETPAGE));\r
314         HPROPSHEETPAGE hPage;\r
315         CGitPropertyPage *sheetpage = new CGitPropertyPage(files_);\r
316 \r
317     psp.dwSize = sizeof (psp);\r
318     psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USEICONID | PSP_USECALLBACK;    \r
319         psp.hInstance = g_hResInst;\r
320         psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE);\r
321     psp.pszIcon = MAKEINTRESOURCE(IDI_APPSMALL);\r
322     psp.pszTitle = _T("Subversion");\r
323     psp.pfnDlgProc = (DLGPROC) PageProc;\r
324     psp.lParam = (LPARAM) sheetpage;\r
325     psp.pfnCallback = PropPageCallbackProc;\r
326     psp.pcRefParent = &g_cRefThisDll;\r
327 \r
328     hPage = CreatePropertySheetPage (&psp);\r
329 \r
330         if (hPage != NULL)\r
331         {\r
332         if (!lpfnAddPage (hPage, lParam))\r
333         {\r
334             delete sheetpage;\r
335             DestroyPropertySheetPage (hPage);\r
336         }\r
337         }\r
338 #endif\r
339     return NOERROR;\r
340 }\r
341 \r
342 \r
343 \r
344 STDMETHODIMP CShellExt::ReplacePage (UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)\r
345 {\r
346     return E_FAIL;\r
347 }\r
348 \r