Browse Source

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

cobines 15 years ago
parent
commit
e7c23c8d76
1 changed files with 104 additions and 86 deletions
  1. 104 86
      src/platform/win/uicofiles.pas

+ 104 - 86
src/platform/win/uicofiles.pas

@@ -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
-  try
-    setLength(FIcons,length(FIcons)+1);
-    with FIcons[high(FIcons)] do
-      begin
-        Assert(GetIconInfo(h,IconInfo));
+  if not GetIconInfo(h, IconInfo) then
+    Exit;
 
-        InternalGetDIB(IconInfo.hbmColor,iRgbTable,BitmapInfo,ImageBits);
-        InternalGetDIB(IconInfo.hbmMask,i,MaskBitmapInfo,MaskBits);
-        // MaskBitmapInfo ìîæåò ïîíàäîáèòüñÿ òîëüêî äëÿ îòðèñîâêè, äëÿ ñîõðàíåíèÿ â ôàéë îíà íå íóæíà}
+  try
+    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 ìîæåò ïîíàäîáèòüñÿ òîëüêî äëÿ îòðèñîâêè, äëÿ ñîõðàíåíèÿ â ôàéë îíà íå íóæíà}
 
-        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;