I think I solved this one too... I never knew that my first love, LoadIconWithScaleDown, can load icons from dll's too. And the dll name can be found with SHGetFileInfo. The only thing that seems strange to me is, why SHGetFileInfo returns the icon idex as a negative value... ?
Update: After I read Remy's comment I improved the code so that it can extract icons from dll or exe, by resource ID (negative values) or icon index (positive values).
I wish I could have extracted the shell extension icons in this way as well, but it seems that SHGetFileInfo does not return icon location for file extensions, e.g SHGetFileInfo(PChar('D:\image1.jpg'),.... So, if anyone knows how we can extend this code to work for shell extension as well, I would really appreciate it.
uses ShellApi;
const
LOAD_LIBRARY_AS_IMAGE_RESOURCE = $00000020;
type
PResEnumData = ^TResEnumData;
TResEnumData = record
Idx, Count: Integer;
ResName: LPTSTR;
end;
function LoadIconWithScaleDown(hinst: HINST; pszName: LPCWSTR; cx: Integer;
cy: Integer; var phico: HICON): HResult; stdcall; external 'ComCtl32';
function EnumResNameProc(hModule: HMODULE; lpszType: LPCTSTR; lpszName: LPTSTR;
lParam: LONG_PTR): BOOL; stdcall;
var Data: PResEnumData;
begin
Data:= PResEnumData(lParam);
Inc(Data.Count);
if Data.Count < Data.Idx then Result:= True
else begin
Data.ResName:= lpszName;
Result:= False;
end;
end;
function GetIconResNameByIndex(Module: HMODULE; Index: Integer): LPTSTR;
var Data: TResEnumData;
begin
Data.Idx:= Index; Data.Count:= -1; Data.ResName:= nil;
EnumResourceNames(Module, RT_GROUP_ICON, @EnumResNameProc, NativeInt(@Data));
Result:= Data.ResName;
end;
procedure TForm1.Button1Click(Sender: TObject);
var FileInfo: TSHFileInfo;
Ico: TIcon;
hI: HICON;
hMod: HMODULE;
FileName, Ext: String;
ResName: LPTSTR;
begin
if SHGetFileInfo(PChar('c:'), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICONLOCATION) > 0 then begin
FileName:= FileInfo.szDisplayName;
Ext:= LowerCase(ExtractFileExt(FileName));
if (Ext = '.dll') or (Ext = '.exe') then begin
Ico:= TIcon.Create; hI:= 0;
hMod:= LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE or LOAD_LIBRARY_AS_DATAFILE);
if hMod > 0 then begin
if FileInfo.iIcon < 0
then ResName:= MAKEINTRESOURCE(Abs(FileInfo.iIcon))
else ResName:= GetIconResNameByIndex(hMod, FileInfo.iIcon);
if Assigned(ResName) and (LoadIconWithScaleDown(hMod, ResName, 64, 64, hI) = S_OK)
and (hI > 0) then begin
Ico.Handle:= hI;
TestBtn.LoadImgFromIcon(Ico);
end;
FreeLibrary(hmod);
end;
Ico.Free;
end;
end
end;