Can 48x48 or 64x64 icons be obtained from the Vista Shell?
You must use the SHGetImageList function, to get the image list with the larger icons.
Here you have an example in delphi
uses ShellApi, Commctrl, ShlObj;
const
SHIL_LARGE = $00; //The image size is normally 32x32 pixels. However, if the Use large icons option is selected from the Effects section of the Appearance tab in Display Properties, the image is 48x48 pixels.
SHIL_SMALL = $01; //These images are the Shell standard small icon size of 16x16, but the size can be customized by the user.
SHIL_EXTRALARGE= $02; //These images are the Shell standard extra-large icon size. This is typically 48x48, but the size can be customized by the user.
SHIL_SYSSMALL = $03; //These images are the size specified by GetSystemMetrics called with SM_CXSMICON and GetSystemMetrics called with SM_CYSMICON.
SHIL_JUMBO = $04; //Windows Vista and later. The image is normally 256x256 pixels.
IID_IImageList: TGUID= '{46EB5926-582E-4017-9FDF-E8998DAA0950}';
function GetImageListSH(SHIL_FLAG:Cardinal): HIMAGELIST;
type
_SHGetImageList = function (iImageList: integer; const riid: TGUID; var ppv: Pointer): hResult; stdcall;
var
Handle : THandle;
SHGetImageList: _SHGetImageList;
begin
Result:= 0;
Handle:= LoadLibrary('Shell32.dll');
if Handle<> S_OK then
try
SHGetImageList:= GetProcAddress(Handle, PChar(727));
if Assigned(SHGetImageList) and (Win32Platform = VER_PLATFORM_WIN32_NT) then
SHGetImageList(SHIL_FLAG, IID_IImageList, Pointer(Result));
finally
FreeLibrary(Handle);
end;
end;
Procedure GetIconFromFile(aFile:String; var aIcon : TIcon;SHIL_FLAG:Cardinal);
var
aImgList : HIMAGELIST;
SFI : TSHFileInfo;
Begin
//Get the index of the imagelist
SHGetFileInfo(PChar(aFile), FILE_ATTRIBUTE_NORMAL, SFI,
SizeOf( TSHFileInfo ), SHGFI_ICON or SHGFI_LARGEICON or SHGFI_SHELLICONSIZE or
SHGFI_SYSICONINDEX or SHGFI_TYPENAME or SHGFI_DISPLAYNAME );
if not Assigned(aIcon) then
aIcon:= TIcon.Create;
//get the imagelist
aImgList:= GetImageListSH(SHIL_FLAG);
//extract the icon handle
aIcon.Handle:= ImageList_GetIcon(aImgList, Pred(ImageList_GetImageCount(aImgList)), ILD_NORMAL);
End;
You can use these functions in this way
var
hicon :TIcon;
begin
hicon:= TIcon.Create;
try
GetIconFromFile('C:\Tools\reflector\readme.htm',hicon,SHIL_JUMBO);
Image1.Picture.Icon.Assign(hIcon); //assign to timage
finally
hIcon.Free;
end;
end;
Read here: (Code in C++)
Getting the 16×16 and 32×32 icons on Windows is relatively easy and is often as simple as one call to ExtractIconEx.
However, getting the extra large (48×48) and jumbo (256×256) icons introduced respectively by XP and Vista is slighly more complex. This is normally done by:
- Getting the file information, in particular the icon index, for the given file using SHGetFileInfo
- Retrieving the system image list where all the icons are stored
- Casting the image list to an IImageList interface and getting the icon from there
We found that the index of the file was not correct because the incorrect icon was shown during testing of the code posted by RRUZ. The GetIconFromFile method was setting the index baised on the image count. We changed GetIconFromFile to use the SFI index ( aIndex := SFI.iIcon ) and the correct icon was obtained. Apparently the shellimagelist is constantly changing so the index was incorrect.
Thanks to all to assisted. This seems like a very good piece of code now.
procedure GetIconFromFile( aFile: string; var aIcon: TIcon;SHIL_FLAG: Cardinal );
var
aImgList: HIMAGELIST;
SFI: TSHFileInfo;
aIndex: integer;
begin // Get the index of the imagelist
SHGetFileInfo( PChar( aFile ), FILE_ATTRIBUTE_NORMAL, SFI, SizeOf( TSHFileInfo ),
SHGFI_ICON or SHGFI_LARGEICON or SHGFI_SHELLICONSIZE or SHGFI_SYSICONINDEX or SHGFI_TYPENAME or SHGFI_DISPLAYNAME );
if not Assigned( aIcon ) then
aIcon := TIcon.Create;
// get the imagelist
aImgList := GetImageListSH( SHIL_FLAG );
// get index
//aIndex := Pred( ImageList_GetImageCount( aImgList ) );
aIndex := SFI.iIcon;
// extract the icon handle
aIcon.Handle := ImageList_GetIcon( aImgList, aIndex, ILD_NORMAL );
end;
kicon
i use the appropriate kicon method (LoadFromFile/LoadFromModule/LoadFromModuleByIndex) depending on the source file type.
if these methods fail, i use PrivateExtractIconsA:
function PrivateExtractIcons(lpszFile: PChar; nIconIndex, cxIcon, cyIcon: integer; phicon: PHandle; piconid: PDWORD; nIcons, flags: DWORD): DWORD; stdcall; external 'user32.dll' name 'PrivateExtractIconsA';
and pass the resulting handle to kicon's LoadFromHandle method.
once it's been loaded into kicon, iterate over the icondata[] array to pick out the size you want. kicon has methods to convert the returned image to PNG.