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 IEnumIDList
*EnumIDList
= NULL
;
247 IShellFolder2
*psfRecycleBin
= NULL
;
248 IShellFolder
*psfDesktop
= NULL
;
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 psfDesktop
->Release();
269 psfRecycleBin
->Release();
271 EnumIDList
->Release();
274 if (HCR_GetIconW(xriid
, wTemp
, iconname
, MAX_PATH
, &icon_idx
))
276 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
280 if (IsEqualGUID(*riid
, CLSID_MyComputer
))
281 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_MY_COMPUTER
);
282 else if (IsEqualGUID(*riid
, CLSID_MyDocuments
))
283 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_MY_DOCUMENTS
);
284 else if (IsEqualGUID(*riid
, CLSID_NetworkPlaces
))
285 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_MY_NETWORK_PLACES
);
287 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_FOLDER
);
291 else if (_ILIsDrive (pSimplePidl
))
293 static const WCHAR drive
[] = { 'D', 'r', 'i', 'v', 'e', 0 };
296 if (_ILGetDrive(pSimplePidl
, sTemp
, MAX_PATH
))
298 switch(GetDriveTypeA(sTemp
))
300 case DRIVE_REMOVABLE
:
301 icon_idx
= IDI_SHELL_FLOPPY
;
304 icon_idx
= IDI_SHELL_CDROM
;
307 icon_idx
= IDI_SHELL_NETDRIVE
;
310 icon_idx
= IDI_SHELL_RAMDISK
;
312 case DRIVE_NO_ROOT_DIR
:
313 icon_idx
= IDI_SHELL_CDROM
;
320 initIcon
->SetNormalIcon(swShell32Name
, -icon_idx
);
324 if (HCR_GetIconW(drive
, wTemp
, NULL
, MAX_PATH
, &icon_idx
))
325 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
327 initIcon
->SetNormalIcon(swShell32Name
, -IDI_SHELL_DRIVE
);
331 else if (_ILIsFolder (pSimplePidl
))
333 if (SUCCEEDED(getIconLocationForFolder(
334 pidl
, 0, wTemp
, MAX_PATH
,
338 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
339 // FIXME: if/when getIconLocationForFolder does something for
340 // GIL_FORSHORTCUT, code below should be uncommented. and
341 // the following line removed.
342 initIcon
->SetShortcutIcon(wTemp
, icon_idx
);
344 if (SUCCEEDED(getIconLocationForFolder(
345 pidl
, GIL_DEFAULTICON
, wTemp
, MAX_PATH
,
349 initIcon
->SetDefaultIcon(wTemp
, icon_idx
);
351 // if (SUCCEEDED(getIconLocationForFolder(
352 // pidl, GIL_FORSHORTCUT, wTemp, MAX_PATH,
356 // initIcon->SetShortcutIcon(wTemp, icon_idx);
358 if (SUCCEEDED(getIconLocationForFolder(
359 pidl
, GIL_OPENICON
, wTemp
, MAX_PATH
,
363 initIcon
->SetOpenIcon(wTemp
, icon_idx
);
370 if (_ILIsCPanelStruct(pSimplePidl
))
372 if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl
, wTemp
, MAX_PATH
, &icon_idx
)))
375 else if (_ILGetExtension(pSimplePidl
, sTemp
, MAX_PATH
))
377 if (HCR_MapTypeToValueA(sTemp
, sTemp
, MAX_PATH
, TRUE
)
378 && HCR_GetIconA(sTemp
, sTemp
, NULL
, MAX_PATH
, &icon_idx
))
380 if (!lstrcmpA("%1", sTemp
)) /* icon is in the file */
382 SHGetPathFromIDListW(pidl
, wTemp
);
387 MultiByteToWideChar(CP_ACP
, 0, sTemp
, -1, wTemp
, MAX_PATH
);
392 else if (!lstrcmpiA(sTemp
, "lnkfile"))
394 /* extract icon from shell shortcut */
395 CComPtr
<IShellFolder
> dsf
;
396 CComPtr
<IShellLinkW
> psl
;
398 if (SUCCEEDED(SHGetDesktopFolder(&dsf
)))
400 HRESULT hr
= dsf
->GetUIObjectOf(NULL
, 1, (LPCITEMIDLIST
*) &pidl
, IID_NULL_PPV_ARG(IShellLinkW
, &psl
));
404 hr
= psl
->GetIconLocation(wTemp
, MAX_PATH
, &icon_idx
);
406 if (SUCCEEDED(hr
) && *sTemp
)
416 initIcon
->SetNormalIcon(swShell32Name
, 0);
418 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
421 return extractIcon
.Detach();
424 /**************************************************************************
425 * IExtractIconA_Constructor
427 IExtractIconA
* IExtractIconA_Constructor(LPCITEMIDLIST pidl
)
429 CComPtr
<IExtractIconW
> extractIconW
;
430 CComPtr
<IExtractIconA
> extractIconA
;
433 extractIconW
= IExtractIconW_Constructor(pidl
);
437 hr
= extractIconW
->QueryInterface(IID_PPV_ARG(IExtractIconA
, &extractIconA
));
440 return extractIconA
.Detach();