I ran an overnight stress test of my application, and when i came in this morning the software had crashed from a Windows error.
The error occurred because the process was obviously out of GDI handles:
Process Explorer
Task Manager
The next thing is to figure out exactly which kind of GDI resource (e.g. Pen, Brush, Bitmap, Font, Region, DC) i'm leaking. For that i turned to NirSoft's GDIView:
What could a GDI handle be, one that is not any known GDI type?
The answer was GDI HFONT
handles.
It is a Windows 8 issue that GDIView cannot show the font handles.
I used hooking to intercept every call to:
and logged every handle creation, along with its stack trace of when it was allowed. At the end i created a report of all undeleted HFONT
s.
I used the Detours library for Delphi.
Step 1 - For every GDI function there is that creates something, we ask Detours to intercept the function.
var
CreateFontIndirectAOriginal: function (const p1: TLogFontA): HFONT; stdcall = nil;
DeleteObjectOriginal: function (p1: HGDIOBJ): BOOL; stdcall = nil;
CreateFontIndirectAOriginal := InterceptCreate(@CreateFontIndirectA, @CreateFontIndirectAIntercept);
DeleteObjectOriginal := InterceptCreate(@DeleteObject, @DeleteObjectIntercept);
Step 2 - Declare our versions of the GDI functions:
function CreateFontIndirectAIntercept(const p1: TLogFontA): HFONT; stdcall;
begin
Result := CreateFontIndirectAOriginal(p1);
end;
function DeleteObjectIntercept(p1: HGDIOBJ): BOOL; stdcall;
begin
Result := DeleteObjectOriginal(p1);
end;
Step 3 - Add code to track every font created by CreateFont, and every font destruction by DestroyObject
function CreateFontIndirectAIntercept(const p1: TLogFontA): HFONT; stdcall;
begin
Result := TrampolineCreateFontIndirectA(p1);
GdiLeakTrackerSvc.AddFont(Result);
end;
function DeleteObjectIntercept(p1: HGDIOBJ): BOOL; stdcall;
var
objType: DWORD;
begin
objType := GetObjectType(p1);
Result := TrampolineDeleteObject(p1);
case objType of
OBJ_FONT: GdiLeakTrackerSvc.RemoveObject(p1);
end;
end;
And then the GdiLeakTrackerSvc
service tracks all font creations, font destructions, and can let us know during program shutdown if anything leaked.