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.
Related
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.
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.
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).
My server must print some reports about its work. How can I use visual objects such as labels, edit boxes in the OneEecute event?
The same rule, for not modifying VCL objects in any thread except main thread, is valid here too. You should not change any of VCL controls in OnExecute event-handler, because that code will be run in the context of a worker thread spawn by Indy for every connection.
If you need to change graphical user interface, do it using Synchronize or Queue methods, or use a custom notification mechanism for notifying the main thread to do the GUI modification for you.
If you want to call Synchronize or Queue methods, you have to type-cast TIdYarn to TIdYarnOfThread which derives from TIdYarn and implements it with threads:
// Calling MyMethod using Synchornize inside TIdTcpServer.OnExecute event-handler
TIdYarnOfThread(AContext.Yarn).Thread.Synchronize(MyMethod);
// Calling MyMethod using Queue inside TIdTcpServer.OnExecute event-handler
TIdYarnOfThread(AContext.Yarn).Thread.Queue(MyMethod);
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 ?