#1 2018-03-26 03:07:43

ToRag
Member
Registered: 2018-03-26
Posts: 7

Runtime error 216 in SynGdiPlus Finalization

Hi,

using Delphi XE and SynPDF v1.18 on Windows 10:

PDF creation works fine but after closing my application I get runtime error 216.
I traced it down to the finalization of unit SynGdiPlus.

finalization
  Gdip.Free;
  Windows.DeleteCriticalSection(GdipCS);
end.

Gdip.Free causes the problem, so Windows.DeleteCriticalSection(GdipCS) is skipped when debugging.

Any help appreciated.

Regards,
Tom

Offline

#2 2018-03-26 08:02:59

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,238
Website

Re: Runtime error 216 in SynGdiPlus Finalization

I don't get which kind of problem Gdip.Free may trigger, and never seen it in practice...

Do you have any more information about the context?
Most of the time, a "Runtime error 216" comes from a wrongly used of library resources in the program, IIRC.
An exception is probably raised in the initialization section of your code, or the framework code.
See https://stackoverflow.com/a/35747477/458259

Offline

#3 2018-03-26 15:18:49

Chaa
Member
Registered: 2011-03-26
Posts: 245

Re: Runtime error 216 in SynGdiPlus Finalization

This may be due to use the SynPDF in a DLL.

To avoid error you can call FreeAndNil(Gdip) before DLL will be unloaded.

Offline

#4 2018-03-26 15:43:21

ToRag
Member
Registered: 2018-03-26
Posts: 7

Re: Runtime error 216 in SynGdiPlus Finalization

Thanks for your help.

I'm using the PDF engine together with the "Print Preview" component (DelphiArea.com website).
I included the {$DEFINE SYNOPSE} compiler directive in the project options.
This should be enough for the Print Preview component to take care of everything if I understood correctly.
In my own project units I don't have any link to SynPDF.
Printing a PDF works fine, the error occurs after closing the application.
If I remove the compiler directive (in other words, when I don't use the PDF engine), no error occurs.

Where should I put the "FreeAndNil(Gdip)"?

Offline

#5 2018-03-27 07:14:24

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,238
Website

Re: Runtime error 216 in SynGdiPlus Finalization

Did you try to ask on the "Print Preview" component support?

Did you try with our mORMotReport.pas component, which has a print preview feature?

Offline

#6 2018-03-27 09:41:07

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Runtime error 216 in SynGdiPlus Finalization

Are you building/working with an ISAPI?
In this case your initializations/finalizations can be called for each execution (thread) but global vars are shared across the DLL so gdip could be freed when it is already free.

try to change finalization with:

finalization
  if Gdip<>nil then
    FreeAndNil(Gdip);
  Windows.DeleteCriticalSection(GdipCS);
end.

Last edited by MtwStark (2018-03-28 10:04:51)

Offline

#7 2018-03-27 17:00:01

ToRag
Member
Registered: 2018-03-26
Posts: 7

Re: Runtime error 216 in SynGdiPlus Finalization

Yesterday I posted my question on the DelphiArea forum but no answer yet.

My application is a VCL Forms application.

I din't try mORMotReport.pas since I'm using Print Preview for many years now. I prefer to keep using Print Preview if possible.

I changed the finalization without success.
If I debug trace into (F7) the finalization I enter the TGDIPlus.Destroy destructor.
fStartupHook.UnHook(fStartupHookToken) is the command that causes the problem.

destructor TGDIPlus.Destroy;
begin
  if fToken<>0 then begin
    if Assigned(fStartupHook.UnHook) then // may be nil e.g. for Win64
      fStartupHook.UnHook(fStartupHookToken);
    Shutdown(fToken);
    fToken := 0;
  end;
  UnLoad;
  inherited Destroy;
end;

Offline

#8 2018-03-27 18:01:47

ToRag
Member
Registered: 2018-03-26
Posts: 7

Re: Runtime error 216 in SynGdiPlus Finalization

I distributed the application on a Windows 7, same problem.

Offline

#9 2018-03-28 09:51:51

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Runtime error 216 in SynGdiPlus Finalization

Looking the Gdiplus Startup Output structure documentation it says that using the wrong token in the unhook function will cause resource leaks, cleaned up when the process exits.
This should not produce a runtime error.

I think the problem could be in the TGDIPlus.Create, maybe the token received in the hook function was invalid?
The hook function should returns a status (TGdipStatus) but it is not tested in TGDIPlus.Create

it is possible that the call of Startup(fToken,Input,fStartupHook) returns an error (<>stOk) but puts something dirt in fStartupHook?
In this case during the Destroy the fStartupHook.UnHook could result Assigned (<>nil) but invalid.
Try to clear the fStartupHook record when Startup fails in the TGDIPlus.Create:

  if Startup(fToken,Input,fStartupHook)<>stOk then begin
    FillChar(fStartupHook, SizeOf(fStartupHook), 0); // MTW 2018-03-28 - Be sure Hook/UnHook are unassigned
    fToken := 0;
    UnLoad;
    exit;
  end;

Offline

#10 2018-03-28 15:41:50

ToRag
Member
Registered: 2018-03-26
Posts: 7

Re: Runtime error 216 in SynGdiPlus Finalization

Thanks for your suggestion.
It didn't solve the problem.
Debugging learns me that Startup(fToken,Input,fStartupHook) = stOk. This begin-end block is not executed.

Offline

#11 2018-03-29 08:11:42

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Runtime error 216 in SynGdiPlus Finalization

you are welcome.
Are you sure the error is raised on fStartupHook.UnHook(fStartupHookToken), and not on Shutdown(fToken)?
In any case, I think the problem could be related to gdi objects not released before the TGDIPlus.Destroy
Shutdown procedure must be called only after all gdi objects are released...
Try to place a breakpoint in TPrintPreview.Destroy, TThumbnailPreview.Destroy and TPaperPreview.Destroy and see if the runtime error is raised before the destroy of you "Print Preview" component.
If it does not release all gdi objects before destruction it could bring to this kind of problems.

I have taken a brief look into preview.pas and I see it has its own gdiplus support.. maybe the problem is a conflict between the two.
In preview.pas, I would check also TGDIPlusSubset.Create and _gdiPlus.Free in finalization (TGDIPlusSubset.Destroy)

Finally..
I'm still using Delphi 2007 so, I'm not sure about that, but I have read here that in XE2 the calls to “GdiplusStartup” and “GdiplusShutdown” are only performed if not IsLibrary is True to avoid hangs in shutdown..

Last edited by MtwStark (2018-03-29 08:43:28)

Offline

#12 2018-03-30 17:06:59

ToRag
Member
Registered: 2018-03-26
Posts: 7

Re: Runtime error 216 in SynGdiPlus Finalization

The runtime error is raised before reaching the TPrintPreview.Destroy and TPaperPreview.Destroy breakpoints. 
TGDIPlusSubset.Destroy is executed before the SynPDF, SynCrypto, SynCommons and SynGDI finalization.

I made a small video showing the debugging. The runtime error itself isn't shown because only the Delphi Environment window was captured.
http://173.236.46.37/Runtime216.mp4

Offline

#13 2018-04-03 08:08:45

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Runtime error 216 in SynGdiPlus Finalization

Try to download the last print preview source code, TGDIPlusSubset Create/Destroy are slight different, maybe this was a known problem.

http://www.delphiarea.com/downloads/?dl … ch=PREVIEW

Offline

#14 2018-04-03 23:51:51

ToRag
Member
Registered: 2018-03-26
Posts: 7

Re: Runtime error 216 in SynGdiPlus Finalization

This seems to do the trick! Tomorrow I do some more testing to be absolutely sure.
Thanks you so much.

Offline

#15 2018-04-04 10:18:01

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Runtime error 216 in SynGdiPlus Finalization

you are welcome smile

I'm happy to hear you have solved

Offline

Board footer

Powered by FluxBB