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