c94ef107fca40960ba4e8068544b4de4d0e366f5
[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(IShellFolder * psf, LPCITEMIDLIST pidl, UINT uFlags,
30 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
31 {
32 static const WCHAR shellClassInfo[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 };
33 static const WCHAR iconFile[] = { 'I', 'c', 'o', 'n', 'F', 'i', 'l', 'e', 0 };
34 static const WCHAR clsid[] = { 'C', 'L', 'S', 'I', 'D', 0 };
35 static const WCHAR clsid2[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 };
36 static const WCHAR iconIndex[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 };
37 static const WCHAR wszDesktopIni[] = { 'd','e','s','k','t','o','p','.','i','n','i',0 };
38 int icon_idx;
39
40 if (!(uFlags & GIL_DEFAULTICON) && (_ILGetFileAttributes(ILFindLastID(pidl), NULL, 0) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0 )
41 {
42 WCHAR wszFolderPath[MAX_PATH];
43
44 if (!ILGetDisplayNameExW(psf, pidl, wszFolderPath, 0))
45 return FALSE;
46
47 PathAppendW(wszFolderPath, wszDesktopIni);
48
49 if (PathFileExistsW(wszFolderPath))
50 {
51 WCHAR wszPath[MAX_PATH];
52 WCHAR wszCLSIDValue[CHARS_IN_GUID];
53
54 if (GetPrivateProfileStringW(shellClassInfo, iconFile, NULL, wszPath, MAX_PATH, wszFolderPath))
55 {
56 ExpandEnvironmentStringsW(wszPath, szIconFile, cchMax);
57
58 *piIndex = GetPrivateProfileIntW(shellClassInfo, iconIndex, 0, wszFolderPath);
59 return S_OK;
60 }
61 else if (GetPrivateProfileStringW(shellClassInfo, clsid, NULL, wszCLSIDValue, CHARS_IN_GUID, wszFolderPath) &&
62 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
63 {
64 *piIndex = icon_idx;
65 return S_OK;
66 }
67 else if (GetPrivateProfileStringW(shellClassInfo, clsid2, NULL, wszCLSIDValue, CHARS_IN_GUID, wszFolderPath) &&
68 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
69 {
70 *piIndex = icon_idx;
71 return S_OK;
72 }
73 }
74 }
75
76 static const WCHAR folder[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
77
78 if (!HCR_GetIconW(folder, szIconFile, NULL, cchMax, &icon_idx))
79 {
80 lstrcpynW(szIconFile, swShell32Name, cchMax);
81 icon_idx = -IDI_SHELL_FOLDER;
82 }
83
84 if (uFlags & GIL_OPENICON)
85 *piIndex = icon_idx < 0 ? icon_idx - 1 : icon_idx + 1;
86 else
87 *piIndex = icon_idx;
88
89 return S_OK;
90 }
91
92 static 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 if (!Handlers)
167 InitIconOverlays();
168
169 HighestPriority = 101;
170 IconIndex = NumIconOverlayHandlers;
171 for(Index = 0; Index < NumIconOverlayHandlers; Index++)
172 {
173 hResult = Handlers[Index]->IsMemberOf(szPath, SFGAO_FILESYSTEM);
174 if (hResult == S_OK)
175 {
176 hResult = Handlers[Index]->GetPriority(&Priority);
177 if (hResult == S_OK)
178 {
179 if (Priority < HighestPriority)
180 {
181 HighestPriority = Priority;
182 IconIndex = Index;
183 }
184 }
185 }
186 }
187
188 if (IconIndex == NumIconOverlayHandlers)
189 return FALSE;
190
191 hResult = Handlers[IconIndex]->GetOverlayInfo(wTemp, MAX_PATH, pIndex, &Flags);
192
193 if (hResult == S_OK)
194 return TRUE;
195 else
196 return FALSE;
197 }
198
199 HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut)
200 {
201 CComPtr<IDefaultExtractIconInit> initIcon;
202 HRESULT hr;
203 int icon_idx = 0;
204 UINT flags = 0; // FIXME: Use it!
205 CHAR sTemp[MAX_PATH] = "";
206 WCHAR wTemp[MAX_PATH] = L"";
207
208 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
209 if (FAILED(hr))
210 return hr;
211
212 if (_ILIsFolder (pidl))
213 {
214 if (SUCCEEDED(getIconLocationForFolder(psf,
215 pidl, 0, wTemp, _countof(wTemp),
216 &icon_idx,
217 &flags)))
218 {
219 initIcon->SetNormalIcon(wTemp, icon_idx);
220 // FIXME: if/when getIconLocationForFolder does something for
221 // GIL_FORSHORTCUT, code below should be uncommented. and
222 // the following line removed.
223 initIcon->SetShortcutIcon(wTemp, icon_idx);
224 }
225 if (SUCCEEDED(getIconLocationForFolder(psf,
226 pidl, GIL_DEFAULTICON, wTemp, _countof(wTemp),
227 &icon_idx,
228 &flags)))
229 {
230 initIcon->SetDefaultIcon(wTemp, icon_idx);
231 }
232 // if (SUCCEEDED(getIconLocationForFolder(psf,
233 // pidl, GIL_FORSHORTCUT, wTemp, _countof(wTemp),
234 // &icon_idx,
235 // &flags)))
236 // {
237 // initIcon->SetShortcutIcon(wTemp, icon_idx);
238 // }
239 if (SUCCEEDED(getIconLocationForFolder(psf,
240 pidl, GIL_OPENICON, wTemp, _countof(wTemp),
241 &icon_idx,
242 &flags)))
243 {
244 initIcon->SetOpenIcon(wTemp, icon_idx);
245 }
246 }
247 else
248 {
249 BOOL found = FALSE;
250
251 if (_ILGetExtension(pidl, sTemp, _countof(sTemp)))
252 {
253 if (HCR_MapTypeToValueA(sTemp, sTemp, _countof(sTemp), TRUE)
254 && HCR_GetIconA(sTemp, sTemp, NULL, _countof(sTemp), &icon_idx))
255 {
256 if (!lstrcmpA("%1", sTemp)) /* icon is in the file */
257 {
258 ILGetDisplayNameExW(psf, pidl, wTemp, 0);
259 icon_idx = 0;
260 }
261 else
262 {
263 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wTemp, _countof(wTemp));
264 }
265
266 found = TRUE;
267 }
268 else if (!lstrcmpiA(sTemp, "lnkfile"))
269 {
270 /* extract icon from shell shortcut */
271 CComPtr<IShellLinkW> psl;
272 CComPtr<IExtractIconW> pei;
273
274 HRESULT hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_NULL_PPV_ARG(IShellLinkW, &psl));
275 if (SUCCEEDED(hr))
276 {
277 hr = psl->GetIconLocation(wTemp, _countof(wTemp), &icon_idx);
278 if (FAILED(hr) || !*wTemp)
279 {
280 /* The icon was not found directly, try to retrieve it from the shell link target */
281 hr = psl->QueryInterface(IID_PPV_ARG(IExtractIconW, &pei));
282 if (FAILED(hr) || !pei)
283 TRACE("No IExtractIconW interface!\n");
284 else
285 hr = pei->GetIconLocation(GIL_FORSHELL, wTemp, _countof(wTemp), &icon_idx, &flags);
286 }
287
288 if (SUCCEEDED(hr) && *wTemp)
289 found = TRUE;
290 }
291 }
292 }
293
294 /* FIXME: We should normally use the correct icon format according to 'flags' */
295 if (!found)
296 /* default icon */
297 initIcon->SetNormalIcon(swShell32Name, 0);
298 else
299 initIcon->SetNormalIcon(wTemp, icon_idx);
300 }
301
302 return initIcon->QueryInterface(iid, ppvOut);
303 }