FIX: GDI resources leak and possible crash when icons cannot be loaded.

This commit is contained in:
cobines 2010-01-06 22:01:40 +00:00
commit e7c23c8d76

View file

@ -114,8 +114,9 @@ destructor TIcoFile.Destroy;
var
i: integer;
begin
for i:=low(FIcons) to high(FIcons) do
DestroyIconData(FIcons[i]);
if Length(FIcons) > 0 then
for i:=low(FIcons) to high(FIcons) do
DestroyIconData(FIcons[i]);
inherited;
end;
@ -240,49 +241,55 @@ var
Size: Cardinal;
i: integer;
begin
if not GetIconInfo(h, IconInfo) then
Exit;
try
setLength(FIcons,length(FIcons)+1);
with FIcons[high(FIcons)] do
begin
Assert(GetIconInfo(h,IconInfo));
try
setLength(FIcons,length(FIcons)+1);
with FIcons[high(FIcons)] do
begin
InternalGetDIB(IconInfo.hbmColor,iRgbTable,BitmapInfo,ImageBits);
InternalGetDIB(IconInfo.hbmMask,i,MaskBitmapInfo,MaskBits);
// MaskBitmapInfo ìîæåò ïîíàäîáèòüñÿ òîëüêî äëÿ îòðèñîâêè, äëÿ ñîõðàíåíèÿ â ôàéë îíà íå íóæíà}
InternalGetDIB(IconInfo.hbmColor,iRgbTable,BitmapInfo,ImageBits);
InternalGetDIB(IconInfo.hbmMask,i,MaskBitmapInfo,MaskBits);
// MaskBitmapInfo ìîæåò ïîíàäîáèòüñÿ òîëüêî äëÿ îòðèñîâêè, äëÿ ñîõðàíåíèÿ â ôàéë îíà íå íóæíà}
with Info do
begin
Colors := 0;
Width := BitmapInfo^.bmiHeader.biWidth;
Height := BitmapInfo^.bmiHeader.biHeight;
Reserved1 := MaskBitmapInfo^.bmiHeader.biBitCount;
Reserved2 := BitmapInfo^.bmiHeader.biBitCount;
DIBSize := MaskBitmapInfo^.bmiHeader.biSizeImage+DWORD(iRgbTable)+BitmapInfo^.bmiHeader.biSize+BitmapInfo^.bmiHeader.biSizeImage;
DIBOffset := -1; // Íàäî ïðîñòàâèòü ïðè ñîõðàíåíèè.
end;
with Info do
begin
Colors := 0;
Width := BitmapInfo^.bmiHeader.biWidth;
Height := BitmapInfo^.bmiHeader.biHeight;
Reserved1 := MaskBitmapInfo^.bmiHeader.biBitCount;
Reserved2 := BitmapInfo^.bmiHeader.biBitCount;
DIBSize := MaskBitmapInfo^.bmiHeader.biSizeImage+DWORD(iRgbTable)+BitmapInfo^.bmiHeader.biSize+BitmapInfo^.bmiHeader.biSizeImage;
DIBOffset := -1; // Íàäî ïðîñòàâèòü ïðè ñîõðàíåíèè.
end;
with BitmapInfo^.bmiHeader do
begin
ImageLineWidth := BytesPerScanline(biWidth,biBitCount,32); // Ïî íåìó îïðåäåëÿåì ðàçìåð ëèíèè
with BitmapInfo^.bmiHeader do
begin
ImageLineWidth := BytesPerScanline(biWidth,biBitCount,32); // Ïî íåìó îïðåäåëÿåì ðàçìåð ëèíèè
Assert((biWidth*biBitCount+31) div 32*4 = ImageLineWidth);
Size := biHeight*ImageLineWidth; // È äîëæåí ïîëó÷èòüñÿ ðàçìåð âñåãî áèòìàïà
Assert(Size=biSizeImage);
Assert((biWidth*biBitCount+31) div 32*4 = ImageLineWidth);
Size := biHeight*ImageLineWidth; // È äîëæåí ïîëó÷èòüñÿ ðàçìåð âñåãî áèòìàïà
Assert(Size=biSizeImage);
biHeight := biHeight*2; // Òàê äîëæíî áûòü ÿêîáû èç-çà íàëè÷èÿ ìàñêè
end;
biHeight := biHeight*2; // Òàê äîëæíî áûòü ÿêîáû èç-çà íàëè÷èÿ ìàñêè
end;
with MaskBitmapInfo^.bmiHeader do
begin
MaskLineWidth := BytesPerScanline(biWidth,biBitCount,32);
with MaskBitmapInfo^.bmiHeader do
begin
MaskLineWidth := BytesPerScanline(biWidth,biBitCount,32);
Assert((biWidth+31) div 32*4 = MaskLineWidth); // Ïðîâåðêè
Size := biHeight*MaskLineWidth; // Ðàçìåð ìàñêè (1-áèòíîé)
Assert(Size=biSizeImage);
end;
end;
except
setLength(FIcons,length(FIcons)-1);
Assert((biWidth+31) div 32*4 = MaskLineWidth); // Ïðîâåðêè
Size := biHeight*MaskLineWidth; // Ðàçìåð ìàñêè (1-áèòíîé)
Assert(Size=biSizeImage);
end;
end;
except
setLength(FIcons,length(FIcons)-1);
end;
finally
DeleteObject(IconInfo.hbmColor);
DeleteObject(IconInfo.hbmMask);
end;
end;
@ -413,20 +420,24 @@ begin
FileHeader.Count := length(FIcons);
Stream.WriteBuffer(FileHeader,SizeOf(FileHeader));
offset := Stream.Position+length(FIcons)*SizeOf(TIconRec); // Áèòìàïû íà÷íóòñÿ çäåñü
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Info.DIBOffset := offset;
Stream.WriteBuffer(Info,SizeOf(TIconRec));
offset := offset+SizeOf(BitmapInfo^.bmiHeader)+iRgbTable+length(ImageBits)+length(MaskBits);
end;
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Stream.WriteBuffer(BitmapInfo^.bmiHeader,SizeOf(BitmapInfo^.bmiHeader)+iRgbTable);
Stream.WriteBuffer(ImageBits[0],length(ImageBits));
Stream.WriteBuffer(MaskBits[0],length(MaskBits));
end;
if Length(FIcons) > 0 then
begin
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Info.DIBOffset := offset;
Stream.WriteBuffer(Info,SizeOf(TIconRec));
offset := offset+SizeOf(BitmapInfo^.bmiHeader)+iRgbTable+length(ImageBits)+length(MaskBits);
end;
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Stream.WriteBuffer(BitmapInfo^.bmiHeader,SizeOf(BitmapInfo^.bmiHeader)+iRgbTable);
Stream.WriteBuffer(ImageBits[0],length(ImageBits));
Stream.WriteBuffer(MaskBits[0],length(MaskBits));
end;
end;
end;
procedure TIcoFile.check;
@ -437,25 +448,26 @@ begin
// Ìîæíî òàêæå ïðèìåíÿòü, ÷òîáû ïðîâåðèòü ïðàâèëüíîñòü çàãðóçêè è âîîáùå íà âñÿêèé ñëó÷àé
// ÷òîáû îòëîâèòü ãëþêè.
// "Ñîöèàëèçì - ýòî êîíòðîëü è ó÷¸ò."
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Assert((Info.Reserved1=0) = (Info.Reserved2=0)); // Ðàâíû íóëþ òîëüêî îäíîâðåìåííî
Assert((Info.Colors<>0) or (Info.Reserved1<>0));
Assert(Info.Reserved1 in [0,1]);
with BitmapInfo^.bmiHeader do
begin
Assert(biSize=sizeOf(BitmapInfo^.bmiHeader));
Assert(Info.Width=biWidth);
Assert(Info.Height*2=biHeight);
Assert(biPlanes=1);
Assert(Info.Reserved2 in [0,biBitCount]);
Assert(biBitCount in [1,4,8,16,24,32]);
Assert(biCompression=BI_RGB{=0});
Assert(biXPelsPerMeter=0);
Assert(biYPelsPerMeter=0);
end;
end;
if Length(FIcons) > 0 then
for i:=low(FIcons) to high(FIcons) do
with FIcons[i] do
begin
Assert((Info.Reserved1=0) = (Info.Reserved2=0)); // Ðàâíû íóëþ òîëüêî îäíîâðåìåííî
Assert((Info.Colors<>0) or (Info.Reserved1<>0));
Assert(Info.Reserved1 in [0,1]);
with BitmapInfo^.bmiHeader do
begin
Assert(biSize=sizeOf(BitmapInfo^.bmiHeader));
Assert(Info.Width=biWidth);
Assert(Info.Height*2=biHeight);
Assert(biPlanes=1);
Assert(Info.Reserved2 in [0,biBitCount]);
Assert(biBitCount in [1,4,8,16,24,32]);
Assert(biCompression=BI_RGB{=0});
Assert(biXPelsPerMeter=0);
Assert(biYPelsPerMeter=0);
end;
end;
end;
procedure TIcoFile.draw(icoNo,x,y:integer;dest:hdc;drawMask,drawImage,drawAlpha:boolean);
@ -597,29 +609,35 @@ end;
function CreateIconFromHandle(IconHandle : HIcon) : TIcon;
var
IcoFile : TIcoFile;
memstream : TMemoryStream;
IcoFile : TIcoFile = nil;
memstream : TMemoryStream = nil;
IconData : TIconData;
I : Integer;
begin
Result := nil;
try
IcoFile := TIcoFile.Create(nil);
memstream := TMemoryStream.Create;
IcoFile.loadFromHandle(IconHandle);
for I := Low(IcoFile.Icons) to High(IcoFile.Icons) do
if not IcoFile.IsValidAlpha(I) then
begin
IcoFile.saveTrueColorFrom32(I, IconData);
IcoFile.DestroyIconData(IcoFile.Icons[i]);
IcoFile.Icons[I] := IconData;
end;
IcoFile.saveToStream(memstream);
Result := TIcon.Create;
memstream.Position := 0;
Result.LoadFromStream(memstream);
if Length(IcoFile.Icons) > 0 then
begin
for I := Low(IcoFile.Icons) to High(IcoFile.Icons) do
if not IcoFile.IsValidAlpha(I) then
begin
IcoFile.saveTrueColorFrom32(I, IconData);
IcoFile.DestroyIconData(IcoFile.Icons[i]);
IcoFile.Icons[I] := IconData;
end;
IcoFile.saveToStream(memstream);
Result := TIcon.Create;
memstream.Position := 0;
Result.LoadFromStream(memstream);
end;
finally
IcoFile.Free;
memstream.Free;
if Assigned(IcoFile) then
IcoFile.Free;
if Assigned(memstream) then
memstream.Free;
end;
end;