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