SysUtils.LoadPackage replaces Aplication.OnMessage handler - delphi

I have a main form where I set a handler for the Application.OnMessage event. (Code of this handler is placed in the main form). Then, while running the program, there can be calls to SysUtils.LoadPackage that loads some bpl-package. And after that is loaded, the handler of Application.OnMessage is changed.
I couldn't find what doing this. At least there is not right such code that goes Application.OnMessage := in the package.
One more thing: in the debugger, before LoadPackage, I see OnMessage handler described as Main.TMainForm.AppMessage. All other handlers (such as OnMinimize, OnModalBegin e.t.c.) are nil. And after LoadPackage all events have handlers, described as Vcl.AppEvnts.TMultiCaster.DoMessage.

The package in question uses an internal instance of TApplicationEvents, which is a multicaster that intercepts TApplication events and delegates them to every TApplicationEvents instance in the application, allowing multiple Forms, components, etc to receive the same app events without stepping on each other's toes trying to assign handlers to TApplication directly.
So, to coexist with the package, the solution is to add a TApplicationEvents to your MainForm and assign a handler to its OnMessage event, instead of assigning a handler to the TApplication.OnMessage event directly.

Related

Detect in TComponent descendant that parent form is about to be destroyed

I made my own UDP receiver a TComponent descendant. It has an OnReceive event. This event is used to add a line to TMemo which exists on the same form.
The problem is that when parent form is being destroyed TMemo gets destroyed first and UDP receiver continues to fire OnReceive event. Of course I get an exception when I try to mmo1.Lines.Add(S) to a non-existent Memo.
How to detect in TComponent the moment when parent form and it's components are about to be destroyed, but aren't destroyed yet? I would do then a proper receiver thread shutdown.
Why are you even trying to detect in your component when the parent form is destroyed? Wouldn't it be better to just utilize forms OnClose or OnCloseQuery events to stop your component from receiving data.
Both of these events are called before the form even begins destroying itself and its owned components. Where in OnCloseQuery event you can even prevent form from closing if certain work hasn't finished yet.
When you rely on components for your component to work but are not able to control their life-cycle, you can use TComponent's Notification to re-act when the component you are interested in gets destroyed.
First, your UDP Receiver will need to add itself to the notification list of the component with e.g.
Form.FreeNotification(Self);
to receive notifications from the TForm. Then, the UDP Receiver needs to override
procedure Notification(AComponent: TComponent; Operation: TOperation);
virtual;
There, you can listen to notifications where AComponent = Form and Operation = opRemove, that will indicate the Form is being removed.
Edit: Reading again, this might not be what you are interested in. If the OnReceive event is implemented in your form, you might check if the Form's ComponentState includes csDestroying.
Or, in case the Memo is created at design-time, or you explicitly create and free-and-nil the Memo yourself, just check if Memo <> nil.

onCreate is not the first event

I use a form with a JVWizard from Jedi (version 3.50) on it. I want to do some initialization stuff in the oncreate event, because I thought it will be the first event after creation of the form (like described here). But i found out that the onenterpage event of the welcomepage (first page in page list) event is fired before the oncreate event. I'm wondering what is wrong.
The sequence of events for a form are not absolutely guaranteed. Or rather, the events of a form are determined by the form, but this does not guarantee anything with respect to events triggered by other components.
The OnCreate event of a form is called once the form has been constructed, after any and all components and controls on that form have themselves been initialised.
If those components or controls trigger any events then these may occur before the form OnCreate event itself.
In your case, since you are using the JvWizard components and controls then if you have these controls and components placed on your form at design time then any events triggered by their initialization as they are loaded and initialised at runtime will occur before the Form.OnCreate event.
The OnEnterPage event is one of these, triggered by the JvWizard as it initialises and establishes its first page.
Without knowing the details of precisely what initialization it is you are trying to perform it is impossible to say what the correct solution in your case might be.
It might be simply to perform your form initialization later, for example in response to the forms OnShow event.
Or it may be to move some (or all) of the initialization to the wizard OnEnterPage itself.
Or it may be appropriate to instead implement your initialization as an override of the virtual Create constructor.
Overriding the constructor itself would enable you to perform some initialization before calling the inherited constructor (to initialise the form contents and eventually call OnCreate) and some initialization after the call to inherited (which will run after any Form OnCreate event handler).
constructor TMyForm.Create(Owner: TComponent);
begin
// Perform initialization BEFORE calling inherited and
// BEFORE any components or controls have initialised and
// triggered any of their events.
//
// But remember: At this point there are no form contents loaded!
// As a result the amount of useful initialization you can do
// here may be limited.
// ..
inherited Create(Owner);
// Perform further initialization here ...
//
// At this point form contents (controls/components) have been
// loaded and any events have been triggered and handled,
// including FormCreate. Any code here might even be better
// left to run in the FormCreate event handler.
end;
Hopefully with an understanding of what is going on you will be able to identify the appropriate approach in your case.

Application.OnHelp not getting called in Delphi 2007

I have assigned an event handler to Application.OnHelp, but it is not getting called. I have read some other threads about similar problems, but many of them are for Delphi 7 or Delphi 2010.
I have tried using D6OnHelpFix, but that simply changes the problems, rather than resolving them.
At the end of TApplication.DoOnHelp (in Forms) the invocation of FOnHelp always fails inside TMultiCaster.DoHelp in AppEvnts. That is, the DoHelp routine loops but fails to actually call my event handler.
It sounds like you have used TApplicationEvents objects in your code. In which case you need to attach your event handler to the OnHelp event of a TApplicationEvents object rather then the OnHelp event of TApplication.
The reason for this is that TApplicationEvents replaces the events attached to TApplication with its own handlers to perform the multi-cast dispatch.

Delphi: Freeing a dynamic control at runtime

Is there a failsafe way of freeing a Delphi control?
I have a TStringGrid descendent which I am "embedding" a custom control in it for an inplace editor. When the user navigates within the cells of the grid via the tab key or arrow keys, I need to create a dynamic control if the cell is editable. I have hooked the needed events and am utilizing the OnKeyDown event of my custom control to pass the navigation keys back to the parent TStringGrid.
Previously, the TStringGrid descendent would simply call FreeAndNil on the embedded control, but under some circumstances this would cause access violations inside of UpdateUIState/GetParentForm. Looking at the call stack, it appears that sometimes after the control was free'd, a WM_KEYDOWN (TWinControl.WMKeyDown) message was still happening.
I've all ready looked at and implemented the changes discussed in How to free control inside its event handler?. This appears to have resolved the issue, but I am wondering if there are any other cavet's to this approach.
In effect, this workaround has simply delayed the destruction of the control until after all the existing messages on the queue at the time the CM_RELEASE message was posted.
Would it not be possible that after the CM_RELEASE was posted, another WM_KEY* or similar message could all ready have been posted to the message queue?
My current CM_RELEASE handler looks like:
procedure TMyCustomControl.HandleRelease(var Msg: TMessage);
begin
Free;
end;
So, will this be safe in all instances or should I do something to clear any other messages from the queue? ( SendMessage(Self.Handle, WM_DESTROY, 0, 0) comes to mind )
In general you should not destroy a control in an event-handler of that control.
But since your function is a plain non virtual message handler which is never called from internal code in that control you should be ok. I don't like too too much from a style point of view, but I think it's ok for your use-case.
But a custom message might be cleaner.
Would it not be possible that after the CM_RELEASE was posted, another WM_KEY* or similar message could all ready have been posted to the message queue?
If messages in queue would cause big problems you could never safely destroy a control since messages can be posted from other threads and applications. Just make sure the correct functioning of your application doesn't depends on those messages being handles in every case.
SendMessage sends the message and wait for it to return, that's why you can not use it safely in the event handler of the control you are freeing.
PostMessage in the other hand, will send the message and will be processed after the event exits (if there are no more code in the event).

What is called after Loaded() in Delphi

I have some code that does some setup of internal objects in the Loaded() function. However, some external objects are not completely created yet, but are AFTER the Loaded() function is complete. What function does Delphi call after it calls Loaded()?
Better yet what is the creation sequence of a component?
Basically I have a TCP Server and Client. Most people will place those two components into two separate applications, some will place them in the same application for local access.
My Client tries to fetch data from the server in OnLoaded(), but the server may not be up yet! I want to know if another function is called after all the OnLoaded()'s are called.
Loaded is called immediately after the dfm is streamed in, and shouldn't be used to access the server. Your best bet is probably to post a custom message to yourself in the constructor, and have a message handler procedure that responds to that message. Posting the message puts it into the end of the message queue, and therefore it won't get processed until all the other messages ahead of it has been handled. This should delay things long enough for your components to be fully constructed for use.
I've used breakpoints in some components and firmly established that AFTERCONSTRUCTION is called BEFORE LOADED not AFTER.
I've also done the same thing on a FORM and firmly established that AFTERCONSTRUCTION is called AFTER LOADED not BEFORE.
Bear in mind that AfterConstruction is a method in TObject, but Loaded is not. It follows that Loaded is generated by code that may not necessarily put it in a specific order relative to AfterConstruction, since Loaded is not actually part of the construction sequence of a TObject and AfterConstruction is.
Indeed, if you study the RTL source, you will see that Loaded is not even invoked by any self.method of a TComponent, but is in fact invoked by a stream reader that is reading the DFM, and that will most probably be happening under the control of an "owner" component. I strongly suggest therefore that its relationship relative to the execution of AfterConstruction is not really guaranteed. The fact that it appears in a particular order for a form is because the form is most likely the component to initiate stream reading. In other words, it smacks of a convenient accident that Loaded is before AfterConstruction in a form.
Further research shows that NON-FORM components that include the following code may never call the event handler.
procedure Txxx.AfterConstruction; override;
begin
inherited AfterConstruction;
if Assigned(FOnCreate) then FOnCreate(Self);
end;
The reason is that AfterConstruction, if invoked before properties are loaded, will find FOnCreate has not been assigned yet!
In such cases, you really HAVE to use the following:
procedure Loaded; override;
begin
inherited Loaded;
if assigned(OnLoaded) then OnLoaded(self);
end;
Like I said, this will produce different outcomes for a component owned by a form than it would for the form itself! The TForm component is usually the invoker of the DFM stream reader and it is the stream reader that calls Loaded for each component it reads from the form. This process starts (fortunately) BEFORE the form's AfterConstruction, but each component that is loaded by that reader gets its AfterConstruction method called BEFORE its loaded method.
QED.
The great irony is that the Delphi 6 help file says "The AfterConstruction method implemented in TObject does nothing. Override this method when creating a class that takes some action after the object is created. For example, TCustomForm overrides AfterConstruction to generate an OnCreate event."
What it omits to say is that if you try this on anything other than a TCustomForm (which does it already), it doesn't work! Because only a form (which has it already) will load its OnCreate property before calling AfterConstruction. Any other component won't, because the DFM reader invoked by the form calls AfterConstruction before Loaded! A clear case of Borland et. al. not understanding their own code, or at best, writing a help file entry that implies something is possible when in fact it is not.
Note, if your component is not on a form and is created at runtime (even if this is as an "owned" component), its "Loaded" method will NOT be called, because there was no stream reader involved.
Another point of interest is something that "Dr" Bob Swart wrote some time ago about AfterConstruction, namely that it represents the point where virtual methods can be invoked. Evidently this is only partly true: if a form's Loaded method is invoked BEFORE AfterConstruction, then you would not be able to invoke any virtual methods from Loaded if that were true. This is not the case (obviously) because Loaded is itself a virtual method! Evidently, Loaded for a form is called between the constructor and AfterConstruction by the stream reader. It begs the question: by what method is the stream reader actually invoked? My guess is either that it runs under control of the application (not the form) and that it deliberately invokes AfterConstruction differently for a form than for other components, OR that it is the last thing the form's constructor does after having created the VMT and hence the last thing that occurs before AfterConstruction is called in the form. Accordingly all the AfterConstruction-Loaded couplets of components owned by the form are called before the form's AfterConstruction is called. Tracing the calls also shows that mostly AfterConstruction is called for ALL of those components before ALL of their loaded methods are called. I didn't however test the case where there are hierarchical "parents" (such as panels with components on them), so there may be variations on this.
Normally you would override TObject.AfterConstruction for that purpose.
The order of execution is:
each Component.AfterConstruction in creation order
(Form or DataModule).Loaded
each Component.Loaded in creation order
(Form or DataModule).AfterConstruction
Trace:
Debug Output: button AfterConstruction Process Project2.exe (4876)
Debug Output: Form Loaded Process Project2.exe (4876)
Debug Output: button Loaded Process Project2.exe (4876)
Debug Output: Form AfterConstruction Process Project2.exe (4876)
I'm not sure what you mean with
the server may not be up yet
Anyway, if the client and the server are both on the same application form or datamodule, I see alternatives:
You may "force" the system to create the server before the client and up the server in the server's OnLoad and it will be up at the client OnLoad, because documentation says:
When the streaming system loads a form or data module from its form file, it first constructs the form component by calling its constructor, then reads its property values from the form file. After reading all the property values for all the components, the streaming system calls the Loaded methods of each component in the order the components were created. This gives the components a chance to initialize any data that depends on the values of other components or other parts of itself.
Inform the "client" whenever the server is UP to let it initialize (pull data from the server). You can use a direct method call, post a message or whatever you feel comfortable with.
Let the client stand up the server inside it's own OnLoad method.
Why not use the onCreate event of the main Form ?

Resources