Does Delphi offer an event handler for form notification?

Does Delphi provide any kind of event or hook to create the form (or, moreover, form lifecycle events)?

So, if somewhere in the code a form is created and displayed (modal or non-modal, dynamically or at the usual stage of application launch), does Delphi call an event handler that allows you to register / analyze / change the form before it is displayed?

I know that there are options that include introducing the base class of the form or the procedure for creating a custom form, but for existing applications that already have many forms, it would be nice to have a non-intrusive option to add something like cross-cutting problems in Aspect -oriented programming (AOP).

For example, if I had some code for tracking usage statistics that introduces additional event handlers, I would just add this functionality for each form, developers would not have to change the application code, add only code similar to this

... Application.OnNewForm := MyNewFormCreated; ... procedure TMyApp.MyNewFormCreated(Sender: TCustomForm); begin // iterate over components and do other stuff with the new form ... end; 
+4
source share
4 answers

The closest parameter that I can imagine at the moment that may suit your needs is the Screen.OnActiveFormChange event, which is fired every time the current active form changes. But it may be too late for your needs.

+1
source

At run time, you can override the TCustomForm.DoCreate and TCustomFrame.Create , as such:

 type THookedForm = class(TCustomForm) procedure HookedDoCreate; end; THookedFrame = class(TCustomFrame) constructor Create(AOwner: TComponent); override; end; var OriginalForm, OriginalFrame: TPatchCode; procedure PatchCreate; begin if OriginalForm[0]<>0 then exit; // patch once RedirectCode(@THookedForm.DoCreate,@THookedForm.HookedDoCreate,@OriginalForm); RedirectCode(@THookedFrame.Create,@THookedFrame.Create,@OriginalFrame); end; // hook logic was inspired from GetText() { THookedForm } procedure THookedForm.HookedDoCreate; // translate form contents just before an OnCreate handler would be called begin try try if Language<>nil then begin DisableAlign; DisableAutoRange; try Language.FormTranslateOne(self); // translate form finally EnableAlign; EnableAutoRange; end; end; finally RedirectCodeRestore(@THookedForm.DoCreate,OriginalForm); // disable Hook try DoCreate; // call normal DoCreate event finally RedirectCode(@THookedForm.DoCreate,@THookedForm.HookedDoCreate); end; end; except on Exception do; // ignore all raised exception end; end; { THookedFrame } constructor THookedFrame.Create(AOwner: TComponent); // translate frame contents just after constructor has been called begin RedirectCodeRestore(@THookedFrame.Create,OriginalFrame); // disable Hook try inherited Create(AOwner); // call normal constructor finally RedirectCode(@THookedFrame.Create,@THookedFrame.Create); end; if Language=nil then exit; DisableAlign; DisableAutoRange; try Language.FormTranslateOne(self); // translate frame finally EnableAlign; EnableAutoRange; end; end; .... initialization PatchCreate; 

Therefore, your own DoCreate event will be DoCreate every time an instance of TForm is created.

This code is extracted from mORMoti18n.pas , and you can find the patch routines (for Windows and Linux / BSD) in SynCommons.pas .

+4
source
 // Arnaud Bouchez provided great code, but he cut some important pieces of own code. // And what is more important - he didn't try to run it even once before posting :) // There is correct unit (copy-pasted from another project & tested with XE6/Win.x32) // It works for Windows x32 and x64 platforms. unit HookCreateFrm; interface implementation uses Windows, Classes, Forms, IdGlobal, SysUtils; type THookedForm = class(TCustomForm) procedure HookedDoCreate; end; THookedFrame = class(TCustomFrame) constructor Create(AOwner: TComponent); override; end; PPatchEvent = ^TPatchEvent; // asm opcode hack to patch an existing routine TPatchEvent = packed record Jump: byte; Offset: integer; end; var PatchForm, OriginalForm: TPatchEvent; PatchPositionForm: PPatchEvent = nil; PatchFrame, OriginalFrame: TPatchEvent; PatchPositionFrame: PPatchEvent = nil; procedure PatchCreate; var ov: cardinal; begin // hook TForm: PatchPositionForm := PPatchEvent(@THookedForm.DoCreate); OriginalForm := PatchPositionForm^; PatchForm.Jump := $E9; // Jmp opcode PatchForm.Offset := PByte(@THookedForm.HookedDoCreate)-PByte(PatchPositionForm)-5; if not VirtualProtect(PatchPositionForm, 5, PAGE_EXECUTE_READWRITE, @ov) then RaiseLastOSError; PatchPositionForm^ := PatchForm; // enable Hook // hook TFrame: PatchPositionFrame := PPatchEvent(@TCustomFrame.Create); OriginalFrame := PatchPositionFrame^; PatchFrame.Jump := $E9; // Jmp opcode PatchFrame.Offset := PByte(@THookedFrame.Create)-PByte(PatchPositionFrame)-5; if not VirtualProtect(PatchPositionFrame, 5, PAGE_EXECUTE_READWRITE, @ov) then RaiseLastOSError; PatchPositionFrame^ := PatchFrame; // enable Hook end; // hook logic was inspired from GetText() { THookedForm } procedure THookedForm.HookedDoCreate; begin // do what you want before original DoCreate PatchPositionForm^ := OriginalForm; try DoCreate; finally PatchPositionForm^ := PatchForm; end; // do what you want after original DoCreate end; { THookedFrame } constructor THookedFrame.Create(AOwner: TComponent); begin // do what you want before original DoCreate PatchPositionFrame^ := OriginalFrame; try inherited Create(AOwner); finally PatchPositionFrame^ := PatchFrame; end; // do what you want after original Create end; initialization PatchCreate; end. 
+2
source

If a normal superclass-based implementation is not an option, it might be better than ever before :-)

  • use the notification structure .

Eric Sasse The Notification Service project at Bitbuketka is promising. You can get it here . It is based on TNotify.

-1
source

All Articles