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