OSDN Git Service

Merge branch 'rel_0.3.x'
[tortoisegit/TortoiseGitJp.git] / src / TortoiseOverlays / IconOverlay.cpp
1 // TortoiseOverlays - an overlay handler for Tortoise clients\r
2 // Copyright (C) 2007 - TortoiseSVN\r
3 #include "stdafx.h"\r
4 #include "ShellExt.h"\r
5 #include "Guids.h"\r
6 \r
7 // "The Shell calls IShellIconOverlayIdentifier::GetOverlayInfo to request the\r
8 //  location of the handler's icon overlay. The icon overlay handler returns\r
9 //  the name of the file containing the overlay image, and its index within\r
10 //  that file. The Shell then adds the icon overlay to the system image list."\r
11 STDMETHODIMP CShellExt::GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)\r
12 {\r
13         int nInstalledOverlays = GetInstalledOverlays();\r
14         \r
15         if ((m_State == FileStateAdded)&&(nInstalledOverlays > 12))\r
16                 return S_FALSE;         // don't use the 'added' overlay\r
17         if ((m_State == FileStateLocked)&&(nInstalledOverlays > 13))\r
18                 return S_FALSE;         // don't show the 'locked' overlay\r
19         if ((m_State == FileStateIgnored)&&(nInstalledOverlays > 12))\r
20                 return S_FALSE;         // don't use the 'ignored' overlay\r
21         if ((m_State == FileStateUnversioned)&&(nInstalledOverlays > 13))\r
22                 return S_FALSE;         // don't show the 'unversioned' overlay\r
23 \r
24     // Get folder icons from registry\r
25         // Default icons are stored in LOCAL MACHINE\r
26         // User selected icons are stored in CURRENT USER\r
27         TCHAR regVal[1024];\r
28         DWORD len = 1024;\r
29 \r
30         wstring icon;\r
31         wstring iconName;\r
32 \r
33         HKEY hkeys [] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };\r
34         switch (m_State)\r
35         {\r
36                 case FileStateNormal            : iconName = _T("NormalIcon"); break;\r
37                 case FileStateModified          : iconName = _T("ModifiedIcon"); break;\r
38                 case FileStateConflict          : iconName = _T("ConflictIcon"); break;\r
39                 case FileStateDeleted           : iconName = _T("DeletedIcon"); break;\r
40                 case FileStateReadOnly          : iconName = _T("ReadOnlyIcon"); break;\r
41                 case FileStateLocked            : iconName = _T("LockedIcon"); break;\r
42                 case FileStateAdded                     : iconName = _T("AddedIcon"); break;\r
43                 case FileStateIgnored           : iconName = _T("IgnoredIcon"); break;\r
44                 case FileStateUnversioned       : iconName = _T("UnversionedIcon"); break;\r
45         }\r
46 \r
47         for (int i = 0; i < 2; ++i)\r
48         {\r
49                 HKEY hkey = 0;\r
50 \r
51                 if (::RegOpenKeyEx (hkeys[i],\r
52                         _T("Software\\TortoiseOverlays"),\r
53                     0,\r
54                     KEY_QUERY_VALUE,\r
55                     &hkey) != ERROR_SUCCESS)\r
56                         continue;\r
57 \r
58                 if (icon.empty() == true\r
59                         && (::RegQueryValueEx (hkey,\r
60                                                          iconName.c_str(),\r
61                                                          NULL,\r
62                                                          NULL,\r
63                                                          (LPBYTE) regVal,\r
64                                                          &len)) == ERROR_SUCCESS)\r
65                         icon.assign (regVal, len);\r
66 \r
67                 ::RegCloseKey(hkey);\r
68 \r
69         }\r
70 \r
71         // now load the Tortoise handlers and call their GetOverlayInfo method\r
72         // note: we overwrite any changes a Tortoise handler will do to the\r
73         // params and overwrite them later.\r
74         LoadHandlers(pwszIconFile, cchMax, pIndex, pdwFlags);\r
75 \r
76     // Add name of appropriate icon\r
77     if (icon.empty() == false)\r
78         wcsncpy_s (pwszIconFile, cchMax, icon.c_str(), cchMax);\r
79     else\r
80         return S_FALSE;\r
81 \r
82 \r
83     *pIndex = 0;\r
84     *pdwFlags = ISIOI_ICONFILE;\r
85     return S_OK;\r
86 };\r
87 \r
88 STDMETHODIMP CShellExt::GetPriority(int *pPriority)\r
89 {\r
90         switch (m_State)\r
91         {\r
92                 case FileStateConflict:\r
93                         *pPriority = 0;\r
94                         break;\r
95                 case FileStateModified:\r
96                         *pPriority = 1;\r
97                         break;\r
98                 case FileStateDeleted:\r
99                         *pPriority = 2;\r
100                         break;\r
101                 case FileStateReadOnly:\r
102                         *pPriority = 3;\r
103                         break;\r
104                 case FileStateLocked:\r
105                         *pPriority = 4;\r
106                         break;\r
107                 case FileStateAdded:\r
108                         *pPriority = 5;\r
109                         break;\r
110                 case FileStateNormal:\r
111                         *pPriority = 6;\r
112                         break;\r
113                 case FileStateUnversioned:\r
114                         *pPriority = 8;\r
115                         break;\r
116                 case FileStateIgnored:\r
117                         *pPriority = 7;\r
118                         break;\r
119                 default:\r
120                         *pPriority = 100;\r
121                         return S_FALSE;\r
122         }\r
123     return S_OK;\r
124 }\r
125 \r
126 STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib)\r
127 {\r
128         for (vector<DLLPointers>::iterator it = m_dllpointers.begin(); it != m_dllpointers.end(); ++it)\r
129         {\r
130                 if (it->pShellIconOverlayIdentifier)\r
131                 {\r
132                         if (it->pShellIconOverlayIdentifier->IsMemberOf(pwszPath, dwAttrib) == S_OK)\r
133                                 return S_OK;\r
134                 }\r
135         }\r
136         return S_FALSE;\r
137 }\r
138 \r
139 int CShellExt::GetInstalledOverlays()\r
140 {\r
141         // if there are more than 12 overlay handlers installed, then that means not all\r
142         // of the overlay handlers can be shown. Windows chooses the ones first\r
143         // returned by RegEnumKeyEx() and just drops the ones that come last in\r
144         // that enumeration.\r
145         int nInstalledOverlayhandlers = 0;\r
146         // scan the registry for installed overlay handlers\r
147         HKEY hKey;\r
148         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, \r
149                 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers"),\r
150                 0, KEY_ENUMERATE_SUB_KEYS, &hKey)==ERROR_SUCCESS)\r
151         {\r
152                 for (int i = 0, rc = ERROR_SUCCESS; rc == ERROR_SUCCESS; i++)\r
153                 { \r
154                         TCHAR value[1024];\r
155                         DWORD size = sizeof value / sizeof TCHAR;\r
156                         FILETIME last_write_time;\r
157                         rc = RegEnumKeyEx(hKey, i, value, &size, NULL, NULL, NULL, &last_write_time);\r
158                         if (rc == ERROR_SUCCESS) \r
159                         {\r
160                                 nInstalledOverlayhandlers++;\r
161                         }\r
162                 }\r
163         }\r
164         RegCloseKey(hKey);\r
165         return nInstalledOverlayhandlers;\r
166 }\r
167 \r
168 void CShellExt::LoadHandlers(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)\r
169 {\r
170         HKEY hKey;\r
171         wstring name;\r
172         switch (m_State)\r
173         {\r
174         case FileStateNormal            : name = _T("Software\\TortoiseOverlays\\Normal"); break;\r
175         case FileStateModified          : name = _T("Software\\TortoiseOverlays\\Modified"); break;\r
176         case FileStateConflict          : name = _T("Software\\TortoiseOverlays\\Conflict"); break;\r
177         case FileStateDeleted           : name = _T("Software\\TortoiseOverlays\\Deleted"); break;\r
178         case FileStateReadOnly          : name = _T("Software\\TortoiseOverlays\\ReadOnly"); break;\r
179         case FileStateLocked            : name = _T("Software\\TortoiseOverlays\\Locked"); break;\r
180         case FileStateAdded                     : name = _T("Software\\TortoiseOverlays\\Added"); break;\r
181         case FileStateIgnored           : name = _T("Software\\TortoiseOverlays\\Ignored"); break;\r
182         case FileStateUnversioned       : name = _T("Software\\TortoiseOverlays\\Unversioned"); break;\r
183         }\r
184         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, \r
185                 name.c_str(),\r
186                 0, KEY_READ, &hKey)==ERROR_SUCCESS)\r
187         {\r
188                 for (int i = 0, rc = ERROR_SUCCESS; rc == ERROR_SUCCESS; i++)\r
189                 { \r
190                         TCHAR k[MAX_PATH];\r
191                         TCHAR value[MAX_PATH];\r
192                         DWORD sizek = sizeof k / sizeof TCHAR;\r
193                         DWORD sizev = sizeof value / sizeof TCHAR;\r
194                         rc = RegEnumValue(hKey, i, k, &sizek, NULL, NULL, (LPBYTE)value, &sizev);\r
195                         if (rc == ERROR_SUCCESS) \r
196                         {\r
197                                 TCHAR comobj[MAX_PATH];\r
198                                 TCHAR modpath[MAX_PATH];\r
199                                 _tcscpy_s(comobj, MAX_PATH, _T("CLSID\\"));\r
200                                 _tcscat_s(comobj, MAX_PATH, value);\r
201                                 _tcscat_s(comobj, MAX_PATH, _T("\\InprocServer32"));\r
202                                 if (SHRegGetPath(HKEY_CLASSES_ROOT, comobj, _T(""), modpath, 0) == ERROR_SUCCESS)\r
203                                 {\r
204                                         LoadRealLibrary(modpath, value, pwszIconFile, cchMax, pIndex, pdwFlags);\r
205                                 }\r
206                         }\r
207                 }\r
208         }\r
209         RegCloseKey(hKey);\r
210 }\r
211 \r
212 void CShellExt::LoadRealLibrary(LPCTSTR ModuleName, LPCTSTR clsid, LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)\r
213 {\r
214         static const char GetClassObject[] = "DllGetClassObject";\r
215         static const char CanUnloadNow[] = "DllCanUnloadNow";\r
216 \r
217         DLLPointers pointers;\r
218 \r
219         pointers.hDll = LoadLibraryEx(ModuleName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);\r
220         if (!pointers.hDll)\r
221         {\r
222                 pointers.hDll = NULL;\r
223                 return;\r
224         }\r
225 \r
226         pointers.pDllGetClassObject = NULL;\r
227         pointers.pDllCanUnloadNow = NULL;\r
228         pointers.pDllGetClassObject = (LPFNGETCLASSOBJECT)GetProcAddress(pointers.hDll, GetClassObject);\r
229         if (pointers.pDllGetClassObject == NULL)\r
230         {\r
231                 FreeLibrary(pointers.hDll);\r
232                 pointers.hDll = NULL;\r
233                 return;\r
234         }\r
235         pointers.pDllCanUnloadNow = (LPFNCANUNLOADNOW)GetProcAddress(pointers.hDll, CanUnloadNow);\r
236         if (pointers.pDllCanUnloadNow == NULL)\r
237         {\r
238                 FreeLibrary(pointers.hDll);\r
239                 pointers.hDll = NULL;\r
240                 return;\r
241         }\r
242 \r
243         IID c;\r
244         if (IIDFromString((LPOLESTR)clsid, &c) == S_OK)\r
245         {\r
246                 IClassFactory * pClassFactory = NULL;\r
247                 if (SUCCEEDED(pointers.pDllGetClassObject(c, IID_IClassFactory, (LPVOID*)&pClassFactory)))\r
248                 {\r
249                         IShellIconOverlayIdentifier * pShellIconOverlayIdentifier = NULL;\r
250                         if (SUCCEEDED(pClassFactory->CreateInstance(NULL, IID_IShellIconOverlayIdentifier, (LPVOID*)&pShellIconOverlayIdentifier)))\r
251                         {\r
252                                 pointers.pShellIconOverlayIdentifier = pShellIconOverlayIdentifier;\r
253                                 if (pointers.pShellIconOverlayIdentifier->GetOverlayInfo(pwszIconFile, cchMax, pIndex, pdwFlags) != S_OK)\r
254                                 {\r
255                                         // the overlay handler refused to be properly initialized\r
256                                         FreeLibrary(pointers.hDll);\r
257                                         pointers.hDll = NULL;\r
258                                         pClassFactory->Release();\r
259                                         pointers.pShellIconOverlayIdentifier->Release();\r
260                                         return;\r
261                                 }\r
262                         }\r
263                         pClassFactory->Release();\r
264                 }\r
265         }\r
266 \r
267         m_dllpointers.push_back(pointers);\r
268 }\r
269 \r
270 \r
271 \r