1 // TortoiseOverlays - an overlay handler for Tortoise clients
2 // Copyright (C) 2007 - TortoiseSVN
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
33 HKEY hkeys
[] = { HKEY_CURRENT_USER
, HKEY_LOCAL_MACHINE
};
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
)
51 if (::RegOpenKeyEx (hkeys
[i
],
52 _T("Software\\TortoiseOverlays"),
55 &hkey
) != ERROR_SUCCESS
)
58 if (icon
.empty() == true
59 && (::RegQueryValueEx (hkey
,
64 &len
)) == ERROR_SUCCESS
)
65 icon
.assign (regVal
, len
);
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
);
84 *pdwFlags
= ISIOI_ICONFILE
;
88 STDMETHODIMP
CShellExt::GetPriority(int *pPriority
)
92 case FileStateConflict
:
95 case FileStateModified
:
98 case FileStateDeleted
:
101 case FileStateReadOnly
:
104 case FileStateLocked
:
110 case FileStateNormal
:
113 case FileStateUnversioned
:
116 case FileStateIgnored
:
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
)
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
145 int nInstalledOverlayhandlers
= 0;
146 // scan the registry for installed overlay handlers
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
++)
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
++;
165 return nInstalledOverlayhandlers
;
168 void CShellExt::LoadHandlers(LPWSTR pwszIconFile
, int cchMax
, int *pIndex
, DWORD
*pdwFlags
)
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
,
186 0, KEY_READ
, &hKey
)==ERROR_SUCCESS
)
188 for (int i
= 0, rc
= ERROR_SUCCESS
; rc
== ERROR_SUCCESS
; i
++)
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
);
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
);
222 pointers
.hDll
= NULL
;
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
;
235 pointers
.pDllCanUnloadNow
= (LPFNCANUNLOADNOW
)GetProcAddress(pointers
.hDll
, CanUnloadNow
);
236 if (pointers
.pDllCanUnloadNow
== NULL
)
238 FreeLibrary(pointers
.hDll
);
239 pointers
.hDll
= NULL
;
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();
263 pClassFactory
->Release();
267 m_dllpointers
.push_back(pointers
);