2

I'm working with Delphi 7 and I have to generate a lot of bitmaps from a FlashMovie embedded in my Delphi application. Definition of the pictures is 1010x720.

When I generate more than 6000 pictures (the number is different everytime), I get an EOutOfResources exception. I've looked around and it seems that it could come from a lack of available handles.

Here is the code:

var
FFlashPlayerControlExport:TFlashPlayerControl;
Bmp:TBitmap;
pPNG:TPNGObject;

begin
Bmp := FFlashPlayerControlExport.CreateFrameBitmap;
Bmp.Width := StrToInt(aArgs[5]);
Bmp.Height := StrToInt(aArgs[6]);

pPNG := TPNGObject.Create;
pPNG.Assign(Bmp);
pPNG.SaveToFile(sFileName);
pPNG.Free;

DeleteObject(Bmp.Handle);
Bmp.Free;
end;

I have tried CloseHandle(Bmp.Handle) just before Bmp.Free but I'm getting an EExternalException.

Thank you all for your help!


UPDATE 06 Dec 2012 :

Thanks to Arioch'The's answer, I tried to set the Width and Height of FFlashPlayerControlExport directly instead of using Bmp.Width and Bmp.Height It helped because now I don't get a EOutOfResources exception but the CreateFrameBitmap saves an all-black picture after a while.

FlashPlayerControl is still running because I see the picture on the screen.

Code update :

var
FFlashPlayerControlExport:TFlashPlayerControl;
Bmp:TBitmap;
pPNG:TPNGObject;

begin
FFlashPlayerControlExport.Width := StrToInt(aArgs[5]);
FFlashPlayerControlExport.Height := StrToInt(aArgs[6]);

Bmp := FFlashPlayerControlExport.CreateFrameBitmap;

pPNG := TPNGObject.Create;
pPNG.Assign(Bmp);
pPNG.SaveToFile(sFileName);
pPNG.Free;

Bmp.Free;
end;

UPDATE 20 Dec 2012 :

After contacting the FlashPlayerControl developper team, I found out that the bitmaps become black when the application reaches 10.000 GDI objects. They provided an effective help with my problem, contacting them is efficient :)

I eventually found out that the GDI objects leak comes from another parallel part of my code. This subject is close :)

  • You can try to add [ReportMemoryLeaksOnShutdown](http://docwiki.embarcadero.com/Libraries/XE3/en/System.ReportMemoryLeaksOnShutdown)... before you raise the exception... you close the application and check if you have any memory leaks and what kind of object is not _free_... – Whiler Dec 04 '12 at 11:01
  • For handle leaks in general consult this question: http://stackoverflow.com/questions/2180345/hunting-down-eoutofresources – Jens Mühlenhoff Dec 04 '12 at 11:05
  • That code looks clean. You should be using try/finally of course. And don't call `DeleteObject`. Let that happen in the `TBitmap` destructor. Something else is leaking. – David Heffernan Dec 04 '12 at 11:12
  • Did you try original support forum ? for 300 USD price tag they should give you support, and they are quite active there. http://www.f-in-box.com/forum/viewforum.php?f=1 – Arioch 'The Dec 04 '12 at 13:33
  • What is the value of `bmp.HandleAllocated` and `ppng.HandleAllocated` ? Documentation claims that 1) it does not allocate handle, until asked for it! 2) if u need to free it - you should not call Windows API but `.ReleaseHandle` method of the object http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Graphics.TBitmap.Handle And then, please do tell in WHICH LINE exactly the exception is rased. You're trying to patch here and there at random. Don't. Better tell wich action exactly exhausts system handles. – Arioch 'The Dec 04 '12 at 13:41
  • 1
    `Bmp.Width := StrToInt(aArgs[5]);` This line also seems very weird. Youreally do it 6000 times? 1: do StrToInt once BEFORE the loop. And why do you call it after bitmap created ? 2: do sizing in one line http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Graphics.TBitmap.SetSize 3: Canot u set the size of export over F-In-BOX component before the bitmap is created ? I don't wont to download 20MB demo, but i think there should be a way for that and it should be different sequence – Arioch 'The Dec 04 '12 at 13:48
  • @JensMühlenhoff I read this topic before but it gave me no real solution – Emilien Schneider Dec 04 '12 at 16:37
  • @Arioch'The I could try the support forum. The exception is raised on the line "Bmp.width" but the value of aArgs[5] is okay (I logged it) so I don't understand why. – Emilien Schneider Dec 04 '12 at 16:40
  • Actually, why would you set the width AFTER getting raster picture ? you should do it before, directly on VECTOR flash picture. There should be a way to set it BEFORE getting bmp. Go natural way - ask official support channels. Also did you applied Service Pack to yuor Delphi 7 ? – Arioch 'The Dec 04 '12 at 21:04
  • @Arioch'The Thanks for the answers, you can see that it helped a little in my "UPDATE" – Emilien Schneider Dec 05 '12 at 09:44
  • Great news! but why don't you just ask offical way ? we only guess over controls we never saw or used, they do now all ins and outs. Their help would be more effective! There's no online documentation on F-IN-BOX, so all these attempts are merely wishful shooting into dark sky. Also i think `DeleteObject(Bmp.Handle);` is redundant and unexpectedly messing in TBitmap internals. – Arioch 'The Dec 05 '12 at 09:52
  • Yes... Forgot to delete that but I deleted this part in my real code. – Emilien Schneider Dec 05 '12 at 10:32

1 Answers1

0

When the handle that is created by a TBitmap is used by buggy code it's possible that the handle doesn't get cleaned correctly. This handle leak accumulates and after several such leaks GetDC starts failing.

Another reason for an EOutOfResource exception is that the bitmap has wrong dimensions. The CopyBitmap function in the VCL unit Graphics calls GDICheck which always raises an EOutOfResource exception, but also calls GetLastError in order to give a more appropriate error message.

Depending on how TPNGObject.Assign works you should either call ReleaseHandle or FreeImage on the bitmap, before freeing it.

http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Graphics.TBitmap.ReleaseHandle

http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Graphics.TBitmap.FreeImage

Edit:

Calling ReleaseHandle may make matters worse, because it causes a handle leak when nobody takes the responsibility of the bitmap handle.

Calling FreeImage is normally not necessary, but only helped me once in a similar situation.

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113
  • @DavidHeffernan I had a very similar case. When you constantly create and destroy a bitmap it causes EOutOfResources. In my case I was adding the bitmaps to a TImageList. – Jens Mühlenhoff Dec 04 '12 at 11:57
  • I don't doubt that you've seen a similar problem. It's just that this proposed solution doesn't look like a solution. If it really is a solution, perhaps you can explain why the code in the Q leaks bitmap handles. As it stands this looks like trial and error programming. – David Heffernan Dec 04 '12 at 12:01
  • @DavidHeffernan you're right, I can't really explain the solution. The failing operation is GetDC in Vcl.Graphics `CopyBitmap`. There must be a mismatch between GetDC and ReleaseDC which is "cured" by `FreeImage`. I don't know why / didn't have the time to investigate. – Jens Mühlenhoff Dec 04 '12 at 12:14
  • @Jens - could you switch to a library separate from VCL ? Like Graphics32.org or Vampyre Imaging ? Diving down to GDI contexts just to copy one in-memory image to another looks like vast overkill for me! – Arioch 'The Dec 04 '12 at 13:52
  • I wonder if this only applies to vanilla Delphi 7.0. It looks like they fixed very similar issue in Delphi 7 Update 1 : http://edn.embarcadero.com/article/32337 and http://qc.embarcadero.com/wc/qcmain.aspx?d=2511 - or maybe similar leak exists in TPngImage.Assign ? – Arioch 'The Dec 04 '12 at 13:56
  • Thanks for all your answers. I tried both ReleaseHandle and FreeImage but it didn't work. ReleaseHandle makes my application slower and crash ; FreeImage made it run a little longer before getting the exception... but sent it eventually. – Emilien Schneider Dec 04 '12 at 16:20
  • There's no reason at all to expect that the suggestions in this answer could help at all. – David Heffernan Dec 04 '12 at 18:34
  • @DavidHeffernan I rewrote the answer, maybe it's more helpful now. It seems the original problem was a too large bitmap (wrong dimensions). – Jens Mühlenhoff Dec 05 '12 at 14:34