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