OSDN Git Service

initial icon overlay support using the wingit lib
[tortoisegit/TortoiseGitJp.git] / src / 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 #include "git.h"\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 // *********************** CShellExt *************************\r
35 CShellExt::CShellExt(FileState state)\r
36 {\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
42 \r
43     m_State = state;\r
44 \r
45     m_cRef = 0L;\r
46     g_cRefThisDll++;\r
47 \r
48         g_exts.insert(this);\r
49         \r
50     INITCOMMONCONTROLSEX used = {\r
51         sizeof(INITCOMMONCONTROLSEX),\r
52                         ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES\r
53     };\r
54     InitCommonControlsEx(&used);\r
55         LoadLangDll();\r
56 \r
57         if (fullver >= 0x0600)\r
58         {\r
59                 HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL"));\r
60 \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
64         }\r
65 }\r
66 \r
67 CShellExt::~CShellExt()\r
68 {\r
69         std::map<UINT, HBITMAP>::iterator it;\r
70         for (it = bitmaps.begin(); it != bitmaps.end(); ++it)\r
71         {\r
72                 ::DeleteObject(it->second);\r
73         }\r
74         bitmaps.clear();\r
75         g_cRefThisDll--;\r
76         g_exts.erase(this);\r
77 }\r
78 \r
79 void LoadLangDll()\r
80 {\r
81         if ((g_langid != g_ShellCache.GetLangID())&&((g_langTimeout == 0)||(g_langTimeout < GetTickCount())))\r
82         {\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
90                         return;\r
91                 if (GetModuleFileNameA(g_hmodThisDll, langdirA, MAX_PATH)==0)\r
92                         return;\r
93                 TCHAR * dirpoint = _tcsrchr(langdir, '\\');\r
94                 char * dirpointA = strrchr(langdirA, '\\');\r
95                 if (dirpoint)\r
96                         *dirpoint = 0;\r
97                 if (dirpointA)\r
98                         *dirpointA = 0;\r
99                 dirpoint = _tcsrchr(langdir, '\\');\r
100                 dirpointA = strrchr(langdirA, '\\');\r
101                 if (dirpoint)\r
102                         *dirpoint = 0;\r
103                 if (dirpointA)\r
104                         *dirpointA = 0;\r
105                 strcat_s(langdirA, MAX_PATH, "\\Languages");\r
106 //              bindtextdomain ("subversion", langdirA);\r
107 \r
108                 do\r
109                 {\r
110                         _stprintf_s(langDll, MAX_PATH*4, _T("%s\\Languages\\TortoiseProc%d.dll"), langdir, langId);\r
111                         BOOL versionmatch = TRUE;\r
112 \r
113                         struct TRANSARRAY\r
114                         {\r
115                                 WORD wLanguageID;\r
116                                 WORD wCharacterSet;\r
117                         };\r
118 \r
119                         DWORD dwReserved,dwBufferSize;\r
120                         dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);\r
121 \r
122                         if (dwBufferSize > 0)\r
123                         {\r
124                                 LPVOID pBuffer = (void*) malloc(dwBufferSize);\r
125 \r
126                                 if (pBuffer != (void*) NULL)\r
127                                 {\r
128                                         UINT        nInfoSize = 0,\r
129                                                 nFixedLength = 0;\r
130                                         LPSTR       lpVersion = NULL;\r
131                                         VOID*       lpFixedPointer;\r
132                                         TRANSARRAY* lpTransArray;\r
133                                         TCHAR       strLangProduktVersion[MAX_PATH];\r
134 \r
135                                         if (GetFileVersionInfo((LPTSTR)langDll,\r
136                                                 dwReserved,\r
137                                                 dwBufferSize,\r
138                                                 pBuffer))\r
139                                         {\r
140                                                 // Query the current language\r
141                                                 if (VerQueryValue(      pBuffer,\r
142                                                         _T("\\VarFileInfo\\Translation"),\r
143                                                         &lpFixedPointer,\r
144                                                         &nFixedLength))\r
145                                                 {\r
146                                                         lpTransArray = (TRANSARRAY*) lpFixedPointer;\r
147 \r
148                                                         _stprintf_s(strLangProduktVersion, MAX_PATH, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),\r
149                                                                 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);\r
150 \r
151                                                         if (VerQueryValue(pBuffer,\r
152                                                                 (LPTSTR)strLangProduktVersion,\r
153                                                                 (LPVOID *)&lpVersion,\r
154                                                                 &nInfoSize))\r
155                                                         {\r
156 //                                                              versionmatch = (_tcscmp((LPCTSTR)lpVersion, _T(STRPRODUCTVER)) == 0);\r
157                                                         }\r
158 \r
159                                                 }\r
160                                         }\r
161                                         free(pBuffer);\r
162                                 } // if (pBuffer != (void*) NULL) \r
163                         } // if (dwBufferSize > 0) \r
164                         else\r
165                                 versionmatch = FALSE; \r
166 \r
167                         if (versionmatch)\r
168                                 hInst = LoadLibrary(langDll);\r
169                         if (hInst != NULL)\r
170                         {\r
171                                 if (g_hResInst != g_hmodThisDll)\r
172                                         FreeLibrary(g_hResInst);\r
173                                 g_hResInst = hInst;\r
174                         }\r
175                         else\r
176                         {\r
177                                 DWORD lid = SUBLANGID(langId);\r
178                                 lid--;\r
179                                 if (lid > 0)\r
180                                 {\r
181                                         langId = MAKELANGID(PRIMARYLANGID(langId), lid);\r
182                                 }\r
183                                 else\r
184                                         langId = 0;\r
185                         } \r
186                 } while ((hInst == NULL) && (langId != 0));\r
187                 if (hInst == NULL)\r
188                 {\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
196                         g_langid = 1033;\r
197                         // set a timeout of 10 seconds\r
198                         if (g_ShellCache.GetLangID() != 1033)\r
199                                 g_langTimeout = GetTickCount() + 10000;\r
200                 }\r
201                 else\r
202                         g_langTimeout = 0;\r
203         } // if (g_langid != g_ShellCache.GetLangID()) \r
204 }\r
205 \r
206 STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)\r
207 {\r
208     *ppv = NULL; \r
209 \r
210     if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))\r
211     {\r
212         *ppv = (LPSHELLEXTINIT)this;\r
213     }\r
214     else if (IsEqualIID(riid, IID_IContextMenu))\r
215     {\r
216         *ppv = (LPCONTEXTMENU)this;\r
217     }\r
218     else if (IsEqualIID(riid, IID_IContextMenu2))\r
219     {\r
220         *ppv = (LPCONTEXTMENU2)this;\r
221     }\r
222     else if (IsEqualIID(riid, IID_IContextMenu3))\r
223     {\r
224         *ppv = (LPCONTEXTMENU3)this;\r
225     }\r
226     else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier))\r
227     {\r
228         *ppv = (IShellIconOverlayIdentifier*)this;\r
229     }\r
230     else if (IsEqualIID(riid, IID_IShellPropSheetExt))\r
231     {\r
232         *ppv = (LPSHELLPROPSHEETEXT)this;\r
233     }\r
234         else if (IsEqualIID(riid, IID_IColumnProvider)) \r
235         { \r
236                 *ppv = (IColumnProvider *)this;\r
237         } \r
238         else if (IsEqualIID(riid, IID_IShellCopyHook))\r
239         {\r
240                 *ppv = (ICopyHook *)this;\r
241         }\r
242     if (*ppv)\r
243     {\r
244         AddRef();\r
245                 \r
246         return NOERROR;\r
247     }\r
248         \r
249     return E_NOINTERFACE;\r
250 }\r
251 \r
252 STDMETHODIMP_(ULONG) CShellExt::AddRef()\r
253 {\r
254     return ++m_cRef;\r
255 }\r
256 \r
257 STDMETHODIMP_(ULONG) CShellExt::Release()\r
258 {\r
259     if (--m_cRef)\r
260         return m_cRef;\r
261         \r
262     delete this;\r
263         \r
264     return 0L;\r
265 }\r
266 \r
267 // IPersistFile members\r
268 STDMETHODIMP CShellExt::GetClassID(CLSID *pclsid) \r
269 {\r
270     *pclsid = CLSID_Tortoisegit_UNCONTROLLED;\r
271     return S_OK;\r
272 }\r
273 \r
274 STDMETHODIMP CShellExt::Load(LPCOLESTR /*pszFileName*/, DWORD /*dwMode*/)\r
275 {\r
276     return S_OK;\r
277 }\r
278 \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
281 {\r
282         if (wFunc == FO_COPY)\r
283                 return IDYES;   // copying is not a problem for us\r
284 \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
290         return IDYES;\r
291 }\r
292 // CShellExt member functions (needed for IShellPropSheetExt)\r
293 STDMETHODIMP CShellExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage,\r
294                                   LPARAM lParam)\r
295 {\r
296 #if 0\r
297         for (std::vector<stdstring>::iterator I = files_.begin(); I != files_.end(); ++I)\r
298         {\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
302 \r
303                 if (svn.status->entry == NULL)\r
304                         return NOERROR;\r
305         }\r
306 \r
307         if (files_.size() == 0)\r
308                 return NOERROR;\r
309 \r
310         LoadLangDll();\r
311     PROPSHEETPAGE psp;\r
312         SecureZeroMemory(&psp, sizeof(PROPSHEETPAGE));\r
313         HPROPSHEETPAGE hPage;\r
314         CGitPropertyPage *sheetpage = new CGitPropertyPage(files_);\r
315 \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
326 \r
327     hPage = CreatePropertySheetPage (&psp);\r
328 \r
329         if (hPage != NULL)\r
330         {\r
331         if (!lpfnAddPage (hPage, lParam))\r
332         {\r
333             delete sheetpage;\r
334             DestroyPropertySheetPage (hPage);\r
335         }\r
336         }\r
337 #endif\r
338     return NOERROR;\r
339 }\r
340 \r
341 \r
342 \r
343 STDMETHODIMP CShellExt::ReplacePage (UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)\r
344 {\r
345     return E_FAIL;\r
346 }\r
347 \r