1 // TortoiseOverlays - an overlay handler for Tortoise clients
\r
2 // Copyright (C) 2007 - TortoiseSVN
\r
4 #include "ShellExt.h"
\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
13 int nInstalledOverlays = GetInstalledOverlays();
\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
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
33 HKEY hkeys [] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
\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
47 for (int i = 0; i < 2; ++i)
\r
51 if (::RegOpenKeyEx (hkeys[i],
\r
52 _T("Software\\TortoiseOverlays"),
\r
55 &hkey) != ERROR_SUCCESS)
\r
58 if (icon.empty() == true
\r
59 && (::RegQueryValueEx (hkey,
\r
64 &len)) == ERROR_SUCCESS)
\r
65 icon.assign (regVal, len);
\r
67 ::RegCloseKey(hkey);
\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
76 // Add name of appropriate icon
\r
77 if (icon.empty() == false)
\r
78 wcsncpy_s (pwszIconFile, cchMax, icon.c_str(), cchMax);
\r
84 *pdwFlags = ISIOI_ICONFILE;
\r
88 STDMETHODIMP CShellExt::GetPriority(int *pPriority)
\r
92 case FileStateConflict:
\r
95 case FileStateModified:
\r
98 case FileStateDeleted:
\r
101 case FileStateReadOnly:
\r
104 case FileStateLocked:
\r
107 case FileStateAdded:
\r
110 case FileStateNormal:
\r
113 case FileStateUnversioned:
\r
116 case FileStateIgnored:
\r
126 STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib)
\r
128 for (vector<DLLPointers>::iterator it = m_dllpointers.begin(); it != m_dllpointers.end(); ++it)
\r
130 if (it->pShellIconOverlayIdentifier)
\r
132 if (it->pShellIconOverlayIdentifier->IsMemberOf(pwszPath, dwAttrib) == S_OK)
\r
139 int CShellExt::GetInstalledOverlays()
\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
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
152 for (int i = 0, rc = ERROR_SUCCESS; rc == ERROR_SUCCESS; i++)
\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
160 nInstalledOverlayhandlers++;
\r
165 return nInstalledOverlayhandlers;
\r
168 void CShellExt::LoadHandlers(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)
\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
184 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
\r
186 0, KEY_READ, &hKey)==ERROR_SUCCESS)
\r
188 for (int i = 0, rc = ERROR_SUCCESS; rc == ERROR_SUCCESS; i++)
\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
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
204 LoadRealLibrary(modpath, value, pwszIconFile, cchMax, pIndex, pdwFlags);
\r
212 void CShellExt::LoadRealLibrary(LPCTSTR ModuleName, LPCTSTR clsid, LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)
\r
214 static const char GetClassObject[] = "DllGetClassObject";
\r
215 static const char CanUnloadNow[] = "DllCanUnloadNow";
\r
217 DLLPointers pointers;
\r
219 pointers.hDll = LoadLibraryEx(ModuleName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
\r
220 if (!pointers.hDll)
\r
222 pointers.hDll = NULL;
\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
231 FreeLibrary(pointers.hDll);
\r
232 pointers.hDll = NULL;
\r
235 pointers.pDllCanUnloadNow = (LPFNCANUNLOADNOW)GetProcAddress(pointers.hDll, CanUnloadNow);
\r
236 if (pointers.pDllCanUnloadNow == NULL)
\r
238 FreeLibrary(pointers.hDll);
\r
239 pointers.hDll = NULL;
\r
244 if (IIDFromString((LPOLESTR)clsid, &c) == S_OK)
\r
246 IClassFactory * pClassFactory = NULL;
\r
247 if (SUCCEEDED(pointers.pDllGetClassObject(c, IID_IClassFactory, (LPVOID*)&pClassFactory)))
\r
249 IShellIconOverlayIdentifier * pShellIconOverlayIdentifier = NULL;
\r
250 if (SUCCEEDED(pClassFactory->CreateInstance(NULL, IID_IShellIconOverlayIdentifier, (LPVOID*)&pShellIconOverlayIdentifier)))
\r
252 pointers.pShellIconOverlayIdentifier = pShellIconOverlayIdentifier;
\r
253 if (pointers.pShellIconOverlayIdentifier->GetOverlayInfo(pwszIconFile, cchMax, pIndex, pdwFlags) != S_OK)
\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
263 pClassFactory->Release();
\r
267 m_dllpointers.push_back(pointers);
\r