Столкнулся с проблемой значительного увеличения размера exe файла из-за PImageList. Предлагаю следующий набор функций для хранения сжатой Zlib информации в DLL:
unit NKolZLib;
interface
uses Windows, KOL, KolZlib;
function StreamZCompress(Dest, Source: PStream): DWord;
function StreamZDecompress(Dest, Source: PStream; Count: DWord): DWord;
function GetStreamResource(Dest: PStream; const DllName, ResName: KolString): Boolean;
function GetBitmapResource(const DllName, ResName: KolString): PBitmap;
function SetStreamResource(Dest: PStream; const DllName, ResName: KolString): Boolean;
function AddFileToResource(const DllName, FileName, ResName: KolString): Boolean;
function GetFileFromResource(const DllName, NewFileName, ResName: KolString): Boolean;
function GetResData(const DllName, ResName: KolString; var Data: pointer; var Length: integer): THandle;
function LoadStringFromRCData(const DllName, ResName: KolString): KolString;
procedure AddRCDataResource(const DllName, ResName: KolString; Value: pointer; Size: integer);
procedure ReleaseResData(Handle: THandle);
type
TBlobByteData = array of Byte;
resourcestring
ERLIB = 'Динамически подключаемый модуль < %s > не найден...';
SERROR = 'Ошибка';
implementation
function MsgErr(const Msg: String; Args: Array of const): Boolean;
begin
MessageBox(0, PChar(Format(Msg, Args)), PChar(SERROR), MB_OK + MB_ICONSTOP);
Result:= True
end;
function StreamZDecompress(Dest, Source: PStream; Count: DWord): DWord;
var Zipper: PStream;
Size: DWord;
begin
Result:= 0;
try
Source.Seek(0, spBegin);
if Source.Read (Size, 4) <> 4 then Exit;
if not NewZLibDStream (Zipper, Source, nil) then Exit;
Result:= Stream2Stream(Dest, Zipper, Size);
finally
if Zipper <> nil then Zipper.Free;
end;
end;
function StreamZCompress(Dest, Source: PStream): DWord;
var Zipper: PStream; Size: DWord;
begin
Size:=Source.Size;
Result:= 0;
Source.Seek(0, spBegin);
Dest.Write (Size, 4);
try
If not NewZLibCStream (Zipper, clMax, Dest, nil) then Exit;
Result:= Stream2Stream(Zipper, Source, Size);
finally
if Zipper <> nil then Zipper.Free;
end;
end;
function GetResData(const DllName, ResName: KolString; var Data: pointer; var Length: integer): THandle;
var rHandle, hInst: THandle; p: Pointer;
begin
hInst:= LoadLibrary(PChar(DllName));
Result:= 0;
try
if hInst = 0 then MsgErr(ERLIB, [DllName]);
rhandle:= FindResource(hInst, MakeIntResource(ResName), RT_RCDATA);
Result:= LoadResource(hInst, rhandle);
p:= LockResource(Result);
Length:= SizeOfResource(hInst, rhandle);
Data:= AllocMem(Length);
Move(p^,Data^,Length);
finally
ReleaseResData(Result);
FreeLibrary(hInst);
end;
end;
function GetStreamResource(Dest: PStream; const DllName, ResName: KolString): Boolean;
var aSize: Integer; Buf: Pointer; M: PStream;
begin
Result:= GetResData(DllName, ResName, Buf, aSize) <> 0;
if not Result then Exit;
M:= NewMemoryStream;
try
M.Write(Buf^, aSize);
M.Position:= 0;
StreamZDecompress(Dest, M, 0);
Dest.Position:= 0;
finally
M.Free;
end;
FreeMem(Buf);
Result:= True;
end;
function GetBitmapResource(const DllName, ResName: KolString): PBitmap;
var M: PStream;
begin
M:= NewMemoryStream;
try
Result:= NewBitmap(1, 1);
if GetStreamResource(M, DllName, ResName) then
Result.LoadFromStream(M);
finally
M.Free;
end;
end;
function GetFileFromResource(const DllName, NewFileName, ResName: KolString): Boolean;
var F: PStream;
begin
F:= NewWriteFileStream(NewFileName);
try
Result:= GetStreamResource(F, DllName, ResName);
finally
F.Free;
end;
end;
function SetStreamResource(Dest: PStream; const DllName, ResName: KolString): Boolean;
var M: PStream;
begin
M:= NewMemoryStream;
try
StreamZCompress(M, Dest);
M.Position:= 0;
AddRCDataResource(DllName, ResName, M.Memory, M.Size);
finally
M.Free;
end;
Result:= True;
end;
function AddFileToResource(const DllName, FileName, ResName: KolString): Boolean;
var F: PStream;
begin
F:= NewReadFileStream(FileName);
try
Result:= SetStreamResource(F, DllName, ResName);
finally
F.Free;
end;
end;
procedure AddRCDataResource(const DllName, ResName: KolString; Value: pointer; Size: integer);
var h: THandle;
begin
h:= BeginUpdateResource(PChar(DllName), false);
if h = 0 then Exit;
UpdateResource(h, RT_RCDATA, MakeIntResource(UpperCase(ResName)), 0, Value, Size);
EndUpdateResource(h, false);
end;
procedure ReleaseResData(Handle: THandle);
begin
UnlockResource(Handle);
FreeResource(Handle);
end;
function LoadStringFromRCData(const DLLName, ResName: KolString): KolString;
var rHandle: THandle; Buf: Pointer; Size: integer;
begin
rHandle:= GetResData(DLLName, ResName, Buf, Size);
try
SetString(Result, PChar(Buf), size);
finally
FreeMem(Buf);
ReleaseResData(rHandle);
end;
end;
Для динамической загрузки PImageList использую:
Bmp:= GetBitmapResource(<путь к dll>, <имя ресурса>);
Img.AddMasked(Bmp.Handle, <TransparentColor>);
Bmp.Free;
Выигрыш в размере довольно значительный...