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;