[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 WCHAR* iconname = NULL;
228 if (_ILIsBitBucket(pSimplePidl))
229 {
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_IShellFolder2, (void**) &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 = L"Full";
248 } else {
249 iconname = L"Empty";
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_IShellLinkW, NULL, (LPVOID *)&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 }