2 * Copyright 1997 Marcus Meissner
3 * Copyright 1998 Juergen Schmied
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.
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.
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
22 WCHAR swShell32Name
[MAX_PATH
];
24 DWORD NumIconOverlayHandlers
= 0;
25 IShellIconOverlayIdentifier
** Handlers
= NULL
;
27 static HRESULT
getIconLocationForFolder(LPCITEMIDLIST pidl
, UINT uFlags
,
28 LPWSTR szIconFile
, UINT cchMax
, int *piIndex
, UINT
*pwFlags
)
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 };
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.
46 if (!(uFlags
& GIL_DEFAULTICON
) && SHELL32_GetCustomFolderAttributes(pidl
, shellClassInfo
,
49 if (SHELL32_GetCustomFolderAttribute(pidl
, shellClassInfo
, iconFile
,
52 WCHAR wszIconIndex
[10];
53 SHELL32_GetCustomFolderAttribute(pidl
, shellClassInfo
, iconIndex
,
55 *piIndex
= _wtoi(wszIconIndex
);
58 else if (SHELL32_GetCustomFolderAttribute(pidl
, shellClassInfo
, clsid
,
59 wszCLSIDValue
, CHARS_IN_GUID
) &&
60 HCR_GetIconW(wszCLSIDValue
, szIconFile
, NULL
, cchMax
, &icon_idx
))
65 else if (SHELL32_GetCustomFolderAttribute(pidl
, shellClassInfo
, clsid2
,
66 wszCLSIDValue
, CHARS_IN_GUID
) &&
67 HCR_GetIconW(wszCLSIDValue
, szIconFile
, NULL
, cchMax
, &icon_idx
))
75 static const WCHAR folder
[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
77 if (!HCR_GetIconW(folder
, szIconFile
, NULL
, cchMax
, &icon_idx
))
79 lstrcpynW(szIconFile
, swShell32Name
, cchMax
);
80 icon_idx
= -IDI_SHELL_FOLDER
;
83 if (uFlags
& GIL_OPENICON
)
84 *piIndex
= icon_idx
< 0 ? icon_idx
- 1 : icon_idx
+ 1;
92 void InitIconOverlays(void)
95 DWORD dwIndex
, dwResult
, dwSize
;
96 WCHAR szName
[MAX_PATH
];
100 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
103 if (RegQueryInfoKeyW(hKey
, NULL
, NULL
, NULL
, &dwResult
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
109 Handlers
= (IShellIconOverlayIdentifier
**)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwResult
* sizeof(IShellIconOverlayIdentifier
*));
122 dwSize
= sizeof(szName
) / sizeof(WCHAR
);
123 dwResult
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
125 if (dwResult
== ERROR_NO_MORE_ITEMS
)
128 if (dwResult
== ERROR_SUCCESS
)
130 dwSize
= sizeof(szValue
) / sizeof(WCHAR
);
131 if (RegGetValueW(hKey
, szName
, NULL
, RRF_RT_REG_SZ
, NULL
, szValue
, &dwSize
) == ERROR_SUCCESS
)
133 CComPtr
<IShellIconOverlayIdentifier
> Overlay
;
135 CLSIDFromString(szValue
, &clsid
);
136 dwResult
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, IID_PPV_ARG(IShellIconOverlayIdentifier
, &Overlay
));
137 if (dwResult
== S_OK
)
139 Handlers
[NumIconOverlayHandlers
] = Overlay
.Detach();
140 NumIconOverlayHandlers
++;
153 GetIconOverlay(LPCITEMIDLIST pidl
, WCHAR
* wTemp
, int* pIndex
)
161 WCHAR szPath
[MAX_PATH
];
163 if(!SHGetPathFromIDListW(pidl
, szPath
))
167 HighestPriority
= 101;
168 IconIndex
= NumIconOverlayHandlers
;
169 for(Index
= 0; Index
< NumIconOverlayHandlers
; Index
++)
171 hResult
= Handlers
[Index
]->IsMemberOf(szPath
, SFGAO_FILESYSTEM
);
174 hResult
= Handlers
[Index
]->GetPriority(&Priority
);
177 if (Priority
< HighestPriority
)
179 HighestPriority
= Priority
;
186 if (IconIndex
== NumIconOverlayHandlers
)
189 hResult
= Handlers
[IconIndex
]->GetOverlayInfo(wTemp
, MAX_PATH
, pIndex
, &Flags
);
197 /**************************************************************************
198 * IExtractIconW_Constructor
200 IExtractIconW
* IExtractIconW_Constructor(LPCITEMIDLIST pidl
)
202 CComPtr
<IDefaultExtractIconInit
> initIcon
;
203 CComPtr
<IExtractIconW
> extractIcon
;
207 CHAR sTemp
[MAX_PATH
];
208 WCHAR wTemp
[MAX_PATH
];
209 LPITEMIDLIST pSimplePidl
= ILFindLastID(pidl
);
212 hr
= SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit
,&initIcon
));
216 hr
= initIcon
->QueryInterface(IID_PPV_ARG(IExtractIconW
,&extractIcon
));
220 if (_ILIsDesktop(pSimplePidl
))
222 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_DESKTOP
);
224 else if ((riid
= _ILGetGUIDPointer(pSimplePidl
)))
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
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]);
239 const WCHAR
* iconname
= NULL
;
240 if (_ILIsBitBucket(pSimplePidl
))
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
;
247 CComPtr
<IShellFolder2
> psfRecycleBin
;
248 CComPtr
<IShellFolder
> psfDesktop
;
249 hr
= SHGetDesktopFolder(&psfDesktop
);
252 hr
= psfDesktop
->BindToObject(pSimplePidl
, NULL
, IID_PPV_ARG(IShellFolder2
, &psfRecycleBin
));
254 hr
= psfRecycleBin
->EnumObjects(NULL
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
, &EnumIDList
);
257 LPITEMIDLIST pidl
= NULL
;
258 if (SUCCEEDED(hr
) && (hr
= EnumIDList
->Next(1, &pidl
, &itemcount
)) == S_OK
)
267 if (HCR_GetIconW(xriid
, wTemp
, iconname
, MAX_PATH
, &icon_idx
))
269 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
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
);
280 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_FOLDER
);
284 else if (_ILIsDrive (pSimplePidl
))
286 static const WCHAR drive
[] = { 'D', 'r', 'i', 'v', 'e', 0 };
289 if (_ILGetDrive(pSimplePidl
, sTemp
, MAX_PATH
))
291 switch(GetDriveTypeA(sTemp
))
293 case DRIVE_REMOVABLE
:
294 icon_idx
= IDI_SHELL_FLOPPY
;
297 icon_idx
= IDI_SHELL_CDROM
;
300 icon_idx
= IDI_SHELL_NETDRIVE
;
303 icon_idx
= IDI_SHELL_RAMDISK
;
305 case DRIVE_NO_ROOT_DIR
:
306 icon_idx
= IDI_SHELL_CDROM
;
313 initIcon
->SetNormalIcon(swShell32Name
, -icon_idx
);
317 if (HCR_GetIconW(drive
, wTemp
, NULL
, MAX_PATH
, &icon_idx
))
318 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
320 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_DRIVE
);
324 else if (_ILIsFolder (pSimplePidl
))
326 if (SUCCEEDED(getIconLocationForFolder(
327 pidl
, 0, wTemp
, MAX_PATH
,
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
);
337 if (SUCCEEDED(getIconLocationForFolder(
338 pidl
, GIL_DEFAULTICON
, wTemp
, MAX_PATH
,
342 initIcon
->SetDefaultIcon(wTemp
, icon_idx
);
344 // if (SUCCEEDED(getIconLocationForFolder(
345 // pidl, GIL_FORSHORTCUT, wTemp, MAX_PATH,
349 // initIcon->SetShortcutIcon(wTemp, icon_idx);
351 if (SUCCEEDED(getIconLocationForFolder(
352 pidl
, GIL_OPENICON
, wTemp
, MAX_PATH
,
356 initIcon
->SetOpenIcon(wTemp
, icon_idx
);
363 if (_ILIsCPanelStruct(pSimplePidl
))
365 if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl
, wTemp
, MAX_PATH
, &icon_idx
)))
368 else if (_ILGetExtension(pSimplePidl
, sTemp
, MAX_PATH
))
370 if (HCR_MapTypeToValueA(sTemp
, sTemp
, MAX_PATH
, TRUE
)
371 && HCR_GetIconA(sTemp
, sTemp
, NULL
, MAX_PATH
, &icon_idx
))
373 if (!lstrcmpA("%1", sTemp
)) /* icon is in the file */
375 SHGetPathFromIDListW(pidl
, wTemp
);
380 MultiByteToWideChar(CP_ACP
, 0, sTemp
, -1, wTemp
, MAX_PATH
);
385 else if (!lstrcmpiA(sTemp
, "lnkfile"))
387 /* extract icon from shell shortcut */
388 CComPtr
<IShellFolder
> dsf
;
389 CComPtr
<IShellLinkW
> psl
;
391 if (SUCCEEDED(SHGetDesktopFolder(&dsf
)))
393 HRESULT hr
= dsf
->GetUIObjectOf(NULL
, 1, (LPCITEMIDLIST
*) &pidl
, IID_NULL_PPV_ARG(IShellLinkW
, &psl
));
397 hr
= psl
->GetIconLocation(wTemp
, MAX_PATH
, &icon_idx
);
399 if (SUCCEEDED(hr
) && *sTemp
)
409 initIcon
->SetNormalIcon(swShell32Name
, 0);
411 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
414 return extractIcon
.Detach();
417 /**************************************************************************
418 * IExtractIconA_Constructor
420 IExtractIconA
* IExtractIconA_Constructor(LPCITEMIDLIST pidl
)
422 CComPtr
<IExtractIconW
> extractIconW
;
423 CComPtr
<IExtractIconA
> extractIconA
;
426 extractIconW
= IExtractIconW_Constructor(pidl
);
430 hr
= extractIconW
->QueryInterface(IID_PPV_ARG(IExtractIconA
, &extractIconA
));
433 return extractIconA
.Detach();