[SHELL32] Big Icon Update by Henry Tang Ih and Jared Smudde
[reactos.git] / reactos / dll / win32 / shell32 / folders.cpp
1 /*
2 * Copyright 1997 Marcus Meissner
3 * Copyright 1998 Juergen Schmied
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "precomp.h"
21
22 WCHAR swShell32Name[MAX_PATH];
23
24 DWORD NumIconOverlayHandlers = 0;
25 IShellIconOverlayIdentifier ** Handlers = NULL;
26
27 static HRESULT getIconLocationForFolder(LPCITEMIDLIST pidl, UINT uFlags,
28 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
29 {
30 static const WCHAR shellClassInfo[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 };
31 static const WCHAR iconFile[] = { 'I', 'c', 'o', 'n', 'F', 'i', 'l', 'e', 0 };
32 static const WCHAR clsid[] = { 'C', 'L', 'S', 'I', 'D', 0 };
33 static const WCHAR clsid2[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 };
34 static const WCHAR iconIndex[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 };
35 static const WCHAR wszDesktopIni[] = { 'd','e','s','k','t','o','p','.','i','n','i',0 };
36 int icon_idx;
37
38 if (!(uFlags & GIL_DEFAULTICON) && (_ILGetFileAttributes(ILFindLastID(pidl), NULL, 0) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0 )
39 {
40 WCHAR wszFolderPath[MAX_PATH];
41
42 if (!SHGetPathFromIDListW(pidl, wszFolderPath))
43 return FALSE;
44
45 PathAppendW(wszFolderPath, wszDesktopIni);
46
47 if (PathFileExistsW(wszFolderPath))
48 {
49 WCHAR wszPath[MAX_PATH];
50 WCHAR wszCLSIDValue[CHARS_IN_GUID];
51
52 if (GetPrivateProfileStringW(shellClassInfo, iconFile, NULL, wszPath, MAX_PATH, wszFolderPath))
53 {
54 ExpandEnvironmentStringsW(wszPath, szIconFile, cchMax);
55
56 *piIndex = GetPrivateProfileIntW(shellClassInfo, iconIndex, 0, wszFolderPath);
57 return S_OK;
58 }
59 else if (GetPrivateProfileStringW(shellClassInfo, clsid, NULL, wszCLSIDValue, CHARS_IN_GUID, wszFolderPath) &&
60 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
61 {
62 *piIndex = icon_idx;
63 return S_OK;
64 }
65 else if (GetPrivateProfileStringW(shellClassInfo, clsid2, NULL, wszCLSIDValue, CHARS_IN_GUID, wszFolderPath) &&
66 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
67 {
68 *piIndex = icon_idx;
69 return S_OK;
70 }
71 }
72 }
73
74 static const WCHAR folder[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
75
76 if (!HCR_GetIconW(folder, szIconFile, NULL, cchMax, &icon_idx))
77 {
78 lstrcpynW(szIconFile, swShell32Name, cchMax);
79 icon_idx = -IDI_SHELL_FOLDER;
80 }
81
82 if (uFlags & GIL_OPENICON)
83 *piIndex = icon_idx < 0 ? icon_idx - 1 : icon_idx + 1;
84 else
85 *piIndex = icon_idx;
86
87 return S_OK;
88 }
89
90 void InitIconOverlays(void)
91 {
92 HKEY hKey;
93 DWORD dwIndex, dwResult, dwSize;
94 WCHAR szName[MAX_PATH];
95 WCHAR szValue[100];
96 CLSID clsid;
97
98 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
99 return;
100
101 if (RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwResult, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
102 {
103 RegCloseKey(hKey);
104 return;
105 }
106
107 Handlers = (IShellIconOverlayIdentifier **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwResult * sizeof(IShellIconOverlayIdentifier*));
108 if (!Handlers)
109 {
110 RegCloseKey(hKey);
111 return;
112 }
113
114 dwIndex = 0;
115
116 CoInitialize(0);
117
118 do
119 {
120 dwSize = sizeof(szName) / sizeof(WCHAR);
121 dwResult = RegEnumKeyExW(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL);
122
123 if (dwResult == ERROR_NO_MORE_ITEMS)
124 break;
125
126 if (dwResult == ERROR_SUCCESS)
127 {
128 dwSize = sizeof(szValue) / sizeof(WCHAR);
129 if (RegGetValueW(hKey, szName, NULL, RRF_RT_REG_SZ, NULL, szValue, &dwSize) == ERROR_SUCCESS)
130 {
131 CComPtr<IShellIconOverlayIdentifier> Overlay;
132
133 CLSIDFromString(szValue, &clsid);
134 dwResult = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellIconOverlayIdentifier, &Overlay));
135 if (dwResult == S_OK)
136 {
137 Handlers[NumIconOverlayHandlers] = Overlay.Detach();
138 NumIconOverlayHandlers++;
139 }
140 }
141 }
142
143 dwIndex++;
144
145 } while(1);
146
147 RegCloseKey(hKey);
148 }
149
150 BOOL
151 GetIconOverlay(LPCITEMIDLIST pidl, WCHAR * wTemp, int* pIndex)
152 {
153 DWORD Index;
154 HRESULT hResult;
155 int Priority;
156 int HighestPriority;
157 ULONG IconIndex;
158 ULONG Flags;
159 WCHAR szPath[MAX_PATH];
160
161 if(!SHGetPathFromIDListW(pidl, szPath))
162 return FALSE;
163
164
165 HighestPriority = 101;
166 IconIndex = NumIconOverlayHandlers;
167 for(Index = 0; Index < NumIconOverlayHandlers; Index++)
168 {
169 hResult = Handlers[Index]->IsMemberOf(szPath, SFGAO_FILESYSTEM);
170 if (hResult == S_OK)
171 {
172 hResult = Handlers[Index]->GetPriority(&Priority);
173 if (hResult == S_OK)
174 {
175 if (Priority < HighestPriority)
176 {
177 HighestPriority = Priority;
178 IconIndex = Index;
179 }
180 }
181 }
182 }
183
184 if (IconIndex == NumIconOverlayHandlers)
185 return FALSE;
186
187 hResult = Handlers[IconIndex]->GetOverlayInfo(wTemp, MAX_PATH, pIndex, &Flags);
188
189 if (hResult == S_OK)
190 return TRUE;
191 else
192 return FALSE;
193 }
194
195 /**************************************************************************
196 * IExtractIconW_Constructor
197 */
198 IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl)
199 {
200 CComPtr<IDefaultExtractIconInit> initIcon;
201 CComPtr<IExtractIconW> extractIcon;
202 GUID const * riid;
203 int icon_idx;
204 UINT flags;
205 CHAR sTemp[MAX_PATH];
206 WCHAR wTemp[MAX_PATH];
207 LPITEMIDLIST pSimplePidl = ILFindLastID(pidl);
208 HRESULT hr;
209
210 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
211 if (FAILED(hr))
212 return NULL;
213
214 hr = initIcon->QueryInterface(IID_PPV_ARG(IExtractIconW,&extractIcon));
215 if (FAILED(hr))
216 return NULL;
217
218 if (_ILIsDesktop(pSimplePidl))
219 {
220 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DESKTOP);
221 }
222 else if ((riid = _ILGetGUIDPointer(pSimplePidl)))
223 {
224 /* my computer and other shell extensions */
225 static const WCHAR fmt[] = { 'C', 'L', 'S', 'I', 'D', '\\',
226 '{', '%', '0', '8', 'l', 'x', '-', '%', '0', '4', 'x', '-', '%', '0', '4', 'x', '-',
227 '%', '0', '2', 'x', '%', '0', '2', 'x', '-', '%', '0', '2', 'x', '%', '0', '2', 'x',
228 '%', '0', '2', 'x', '%', '0', '2', 'x', '%', '0', '2', 'x', '%', '0', '2', 'x', '}', 0
229 };
230 WCHAR xriid[50];
231
232 swprintf(xriid, fmt,
233 riid->Data1, riid->Data2, riid->Data3,
234 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
235 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
236
237 const WCHAR* iconname = NULL;
238 if (_ILIsBitBucket(pSimplePidl))
239 {
240 static const WCHAR szFull[] = {'F','u','l','l',0};
241 static const WCHAR szEmpty[] = {'E','m','p','t','y',0};
242 CComPtr<IEnumIDList> EnumIDList;
243 CoInitialize(NULL);
244
245 CComPtr<IShellFolder2> psfRecycleBin;
246 CComPtr<IShellFolder> psfDesktop;
247 hr = SHGetDesktopFolder(&psfDesktop);
248
249 if (SUCCEEDED(hr))
250 hr = psfDesktop->BindToObject(pSimplePidl, NULL, IID_PPV_ARG(IShellFolder2, &psfRecycleBin));
251 if (SUCCEEDED(hr))
252 hr = psfRecycleBin->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &EnumIDList);
253
254 ULONG itemcount;
255 LPITEMIDLIST pidl = NULL;
256 if (SUCCEEDED(hr) && (hr = EnumIDList->Next(1, &pidl, &itemcount)) == S_OK)
257 {
258 CoTaskMemFree(pidl);
259 iconname = szFull;
260 } else {
261 iconname = szEmpty;
262 }
263 }
264
265 if (HCR_GetIconW(xriid, wTemp, iconname, MAX_PATH, &icon_idx))
266 {
267 initIcon->SetNormalIcon(wTemp, icon_idx);
268 }
269 else
270 {
271 if (IsEqualGUID(*riid, CLSID_MyComputer))
272 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_COMPUTER);
273 else if (IsEqualGUID(*riid, CLSID_MyDocuments))
274 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_DOCUMENTS);
275 else if (IsEqualGUID(*riid, CLSID_NetworkPlaces))
276 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_NETWORK_PLACES);
277 else
278 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_FOLDER);
279 }
280 }
281
282 else if (_ILIsDrive (pSimplePidl))
283 {
284 static const WCHAR drive[] = { 'D', 'r', 'i', 'v', 'e', 0 };
285 int icon_idx = -1;
286
287 if (_ILGetDrive(pSimplePidl, sTemp, MAX_PATH))
288 {
289 switch(GetDriveTypeA(sTemp))
290 {
291 case DRIVE_REMOVABLE:
292 icon_idx = IDI_SHELL_3_14_FLOPPY;
293 break;
294 case DRIVE_CDROM:
295 icon_idx = IDI_SHELL_CDROM;
296 break;
297 case DRIVE_REMOTE:
298 icon_idx = IDI_SHELL_NETDRIVE;
299 break;
300 case DRIVE_RAMDISK:
301 icon_idx = IDI_SHELL_RAMDISK;
302 break;
303 case DRIVE_NO_ROOT_DIR:
304 icon_idx = IDI_SHELL_CDROM;
305 break;
306 }
307 }
308
309 if (icon_idx != -1)
310 {
311 initIcon->SetNormalIcon(swShell32Name, -icon_idx);
312 }
313 else
314 {
315 if (HCR_GetIconW(drive, wTemp, NULL, MAX_PATH, &icon_idx))
316 initIcon->SetNormalIcon(wTemp, icon_idx);
317 else
318 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DRIVE);
319 }
320 }
321
322 else if (_ILIsFolder (pSimplePidl))
323 {
324 if (SUCCEEDED(getIconLocationForFolder(
325 pidl, 0, wTemp, MAX_PATH,
326 &icon_idx,
327 &flags)))
328 {
329 initIcon->SetNormalIcon(wTemp, icon_idx);
330 // FIXME: if/when getIconLocationForFolder does something for
331 // GIL_FORSHORTCUT, code below should be uncommented. and
332 // the following line removed.
333 initIcon->SetShortcutIcon(wTemp, icon_idx);
334 }
335 if (SUCCEEDED(getIconLocationForFolder(
336 pidl, GIL_DEFAULTICON, wTemp, MAX_PATH,
337 &icon_idx,
338 &flags)))
339 {
340 initIcon->SetDefaultIcon(wTemp, icon_idx);
341 }
342 // if (SUCCEEDED(getIconLocationForFolder(
343 // pidl, GIL_FORSHORTCUT, wTemp, MAX_PATH,
344 // &icon_idx,
345 // &flags)))
346 // {
347 // initIcon->SetShortcutIcon(wTemp, icon_idx);
348 // }
349 if (SUCCEEDED(getIconLocationForFolder(
350 pidl, GIL_OPENICON, wTemp, MAX_PATH,
351 &icon_idx,
352 &flags)))
353 {
354 initIcon->SetOpenIcon(wTemp, icon_idx);
355 }
356 }
357 else
358 {
359 BOOL found = FALSE;
360
361 if (_ILIsCPanelStruct(pSimplePidl))
362 {
363 if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl, wTemp, MAX_PATH, &icon_idx)))
364 found = TRUE;
365 }
366 else if (_ILGetExtension(pSimplePidl, sTemp, MAX_PATH))
367 {
368 if (HCR_MapTypeToValueA(sTemp, sTemp, MAX_PATH, TRUE)
369 && HCR_GetIconA(sTemp, sTemp, NULL, MAX_PATH, &icon_idx))
370 {
371 if (!lstrcmpA("%1", sTemp)) /* icon is in the file */
372 {
373 SHGetPathFromIDListW(pidl, wTemp);
374 icon_idx = 0;
375 }
376 else
377 {
378 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wTemp, MAX_PATH);
379 }
380
381 found = TRUE;
382 }
383 else if (!lstrcmpiA(sTemp, "lnkfile"))
384 {
385 /* extract icon from shell shortcut */
386 CComPtr<IShellFolder> dsf;
387 CComPtr<IShellLinkW> psl;
388
389 if (SUCCEEDED(SHGetDesktopFolder(&dsf)))
390 {
391 HRESULT hr = dsf->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*) &pidl, IID_NULL_PPV_ARG(IShellLinkW, &psl));
392
393 if (SUCCEEDED(hr))
394 {
395 hr = psl->GetIconLocation(wTemp, MAX_PATH, &icon_idx);
396
397 if (SUCCEEDED(hr) && *sTemp)
398 found = TRUE;
399
400 }
401 }
402 }
403 }
404
405 if (!found)
406 /* default icon */
407 initIcon->SetNormalIcon(swShell32Name, 0);
408 else
409 initIcon->SetNormalIcon(wTemp, icon_idx);
410 }
411
412 return extractIcon.Detach();
413 }
414
415 /**************************************************************************
416 * IExtractIconA_Constructor
417 */
418 IExtractIconA* IExtractIconA_Constructor(LPCITEMIDLIST pidl)
419 {
420 CComPtr<IExtractIconW> extractIconW;
421 CComPtr<IExtractIconA> extractIconA;
422 HRESULT hr;
423
424 extractIconW = IExtractIconW_Constructor(pidl);
425 if (!extractIconW)
426 return NULL;
427
428 hr = extractIconW->QueryInterface(IID_PPV_ARG(IExtractIconA, &extractIconA));
429 if (FAILED(hr))
430 return NULL;
431 return extractIconA.Detach();
432 }