What may and don't I may do in FormCreate()? - delphi

I think this must be a FAQ, but googling hasn't really helped.
What may I do - and may do not - in FormCreate()?
I am wondering if all of the form's child controls are fully created and available for access, etc.
The reason I ask is that I stumbled over an old project where my FormCreate() simply consists of
Sleep(1000);
PostMessage(Handle, UM_PROGRAM_START, 0, 0);
It seems that I want to "wait a bit" and then do some initialization "when things have settled down" ...
Surely I had a reason for it at the time(?), but, in the absence of an enlightening comment I am unable to recall why I felt that to be necessary.
Can anyone state, or reference a link which states, any restrictions on what one may do in FormCreate()?
[Update] I think thta DavidHefferman found the solution when he wrote "the application starts pumping messages. That happens when you call Application.Run in your .dpr file".
I guess that I wasn't concerned about a single form. For instance, my main form wants to do somethign with my config/options form at start up, so obviously would have to wait until it is created.
Here's a typical .DPR from one of my projects ...
Application.Initialize;
Application.CreateForm(TGlobal, Global);
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TLoginForm, LoginForm);
Application.CreateForm(TConfigurationForm, ConfigurationForm);
//[snip] a bunch of other forms ...
Application.Run();
So, it makes sense for my app's mainForm.CreateForm() to send a UM_APPLICATION_START to itself which it won't process until all forms are created & initialized (or, I could just call the fn() which the message triggers from my .DPR after Application.Run() is called; but I prefer the message as it is more obvious - I rarely look at my .DPR files).

There's no definitive documentation giving the list of all the things you can do and connot do in a form's OnCreate.
As for whether or not the .dfm file has been processed and all the form's owned components created, yes they have.
I wouldn't place much store in the code you have found. Calling Sleep during start up, to make the main thread wait, is absolutely not good practice. If the code wanted to wait for another thread it could block for that thread, or wait to get a message from that thread. This just looks like code that got put in by someone who didn't understand what he/she was doing. And the code never got removed.
The other line of code is reasonable:
PostMessage(Handle, UM_PROGRAM_START, 0, 0);
Because this message is posted, it won't get processed until the application starts pumping messages. That happens when you call Application.Run in your .dpr file. Which means that everything related to the creation of you main form happens before that message is pulled off the queue.

I wouldn't put to much initialization code in FormCreate, instead I would place it into a separate function, like
fm := TForm.Create;
fm.Init;
The problem is, an exception thrown in the FormCreate() procedure is not re-thrown (there is only a MessageBox). That means, your code keeps running, although the form is not initialized correctly.

You may do whatever you want in the FormCreate. But there is no message handler to play with, that's all. In general I would create dependent objects in the FormCreate and free them in the FormDestroy. I would also try to avoid time consuming initialization routines.

Related

Is there any purpose for an empty Try/Finally block?

I have inherited a large code base that is full of constructs like this:
try
DoWhatever;
finally
end;
Sometimes "DoWhatever" involves some fiddling with controls, and very often it's a post to a database, and there are many cases in the code where there IS something in the finally block.
But my understanding is, if there's nothing in the finally block, then the whole try...finally thing is pointless. The code is pretty noisy overall so I'm assuming it was just a placeholder for future code or a holdover from previous code. (There are many placeholders in the code.)
Is my understanding correct or is there some secret double-bluff reverso in Delphi try...finally blocks I've overlooked? (This is Delphi 2010.)
There is no functional purpose to it — it has no effect on the run-time behavior of the program. When control leaves the try section, the program will jump to the finally section, do nothing, and then continue to whatever the next instruction should be (according to how control reached the finally statement), the same as if the try-finally block hadn't been there at all. The only difference will be that the program spends an extra moment before and after the try-finally block as it sets up and clears the control structure form the stack.
It might be that the author had a template that included a try-finally block, but that some instances of that template ended up not needing any cleanup code. Having the code fit a consistent pattern might have made certain automated tasks easier.
The try-finally block might also provide a convenient place to put a breakpoint that triggers after the protected code runs, even in the event of an exception or other premature termination.
To find out why the code has such apparently useless constructs, ask the previous author, or check the commit history.

Startup error during main form creation

Delphi XE5/32, on Windows10/64, generating Win32 VCL executable.
I am getting intermittent Access Violation errors that are associated with form creation. This error has also been seen, rarely, by some end-users (I'm currently in small-scale trials, with a test group of about 20 users).
This has been going on for months and until recently my attempts to find the problem were frustrated by the fact that it was so hard to reproduce. However, I have now finally been able to establish an environment that reproduces the error quite reliably. Bizzarely, I have discovered it is triggered by certain emails being displayed in my GMail account, in Chrome browser. The emails that cause the problem are completely consistent - see the video in https://www.devexpress.com/Support/Center/Question/Details/T395896. (I initially posted this query to the DevExpress support forum because I suspected one of their components was the cause, however now I doubt this).
I have now disabled my splash screen temporarily, and changed my previous auto-create datamodules to be created in the main form's OnCreate. The DPR is now, very simply:
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.Title := 'Topshare V3';
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
That is, nothing happens prior to the CreateForm for the program's main form.
When the error is happening, the program either hangs silently during Application.CreateForm(TMainForm, MainForm), and before the main form's OnCreate is invoked; or it terminates before OnCreate, and invokes the form's OnDestroy. So the problem is occurring during the parsing of the DFM.
If I step the program in debug mode within the IDE when the error is active, there are several AVs raised during Application.CreateForm(TMainForm, MainForm). These are only apparent from the IDE so are, presumably, within try..except blocks. If I click Break on the first of these, the Call Stack is usually something like:
System.SysGetMem(???)
:00405423 SysGetMem + $43
System.Classes.TReader.ReadComponent(nil)
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($7BCCD90)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
:00aa0bcd TcxCustomGrid.ReadState + $29
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($7BF4230)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
System.Classes.TReader.ReadComponent(nil)
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($7BF3F50)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
System.Classes.TReader.ReadComponent(nil)
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($9B9C7A0)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
Vcl.Forms.TCustomForm.ReadState($9C6F098)
System.Classes.TReader.ReadRootComponent($9B9C7A0)
System.Classes.TStream.ReadComponent($9B9C7A0)
System.Classes.InternalReadComponentRes(???,???,$9B9C7A0)
System.Classes.InitComponent(TMainForm)
System.Classes.InitInheritedComponent($9B9C7A0,TForm)
Vcl.Forms.TCustomForm.Create(???)
Vcl.Forms.TApplication.CreateForm(???,(no value))
TopshareV3.TopshareV3
The apparent involvement of SysGetMem lead me to this Question: Delphi XE5 Acces Violation on app start
Accordingly I have enabled both Range Checking and Overflow Checking, but this does not help.
There must be something wrong with the DFM.
One aspect is that the main form inherits from an ancestor form type. The ancestor form has no components, just some methods. The ancestor form's source code does not include the default global variable declaration. So, the main form's form declaration is:
TMainForm = class(TABase)
and the DFM contains:
inherited MainForm: TMainForm
The form contains several nested frames, and also uses several ActionManagers, ActionToolbars, an ActionMainMenubar, a PopupActionbar, and a dxSkinController.
Can anyone shed any further light on what to look for, or how to proceed further??
EDIT: The call stack shown above is After the first AV. But I have already done the tracing you suggest. I put a breakpoint in System.Classes at line #10169, in TReader.ReadComponent. I then add watches on "Parent.name" and "CompName". Then, starting again in the IDE, I see the various main form components being created.
Previously, when the datamodules were being created first, I would see a number of components created, but the AV would always happen after hitting the breakpoint with watches showing the first View of the first cxGrid (DevExpress). If I added an extra grid to the form (and on the first panel to be created), without any properties being set, then the new grid would appear to trigger the AV. In other words, it seemed like the cxGrid was the problem - hence my contact with DevExpress support.
But postponing the creation of the datamodules, and eliminating my splash screen, has changed things (although the AV is still occurring). Now, it progresses well beyond the first grid; and, although a cxGrid still seems to be involved, I'm not sure that's relevant now (I have a lot of grids on the main form).
EDIT: Running in the IDE, there are 3 AVs (if I click Continue after each) - then the program hangs before my code in OnCreate executes: the first is $C0000005 with message 'access violation at 0x0040541d: read of address 0x002d001c'; and, twice, $C0000005 with message 'access violation at 0x00a8107a: read of address 0x00000068'.
EDIT: My initial breakpoint at Classes # 10169 now executes a few dozen times as the form components from the DFM are processed. On the now-critical component (still a cxGrid view), execution steps from Classes #10169 (in Treader.ReadComponent), to CreateComponent #10114, to Result.create #10129. From here there is a loop (or recursion) that includes an assembler block beginning at System #16752, and empty Tobject.Create at #15511. A breakpoint at System #15511 executes 29 times. Then, the 30th time through, the AV occurs at System #16757, CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance
EDIT: When stepping through execution when there's no error condition, things seem essentially the same as when there is: that is, the same sequence of calls. The same sequence described in the para above seems to be followed - except for no AV on the 30th pass or subsequently.
I have narrowed the problem down to DevExpress's dxSpreadSheetCore unit. If I include that in any Uses clause, the error is displayed; if I omit it, no error. I have submitted the problem to DevExpress, although I was not able to simplify my application enough to also give them a useful demonstration of the error.
My assumption, based on comments here, is that something in the initialization section of dxSpreadSheetCore (or in its dependant units) is causing heap corruption.

Delphi : force unload injected module

i use this code to determine if a specific module has been injected to my application's process
(i use it to prevent some Packet Sniffer Softwares)
Var
H:Cardinal;
Begin
H:= GetModuleHandle('WSock32.dll');
if H >0 then FreeLibrary(H);
end;
the problem is when i call Freelibrary it do nothing !
i don't wanna show message then terminate the application i just want to unload the injected module silently
thanks in advance
Well, first of all I'll attempt to answer the question as asked. And then, I'll try to argue that you are asking the wrong question.
Modules are reference counted. It's possible that there are multiple references to this module. So, keep calling FreeLibrary:
procedure ForceRemove(const ModuleName: string);
var
hMod: HMODULE;
begin
hMod := GetModuleHandle(PChar(ModuleName));
if hMod=0 then
exit;
repeat
until not FreeLibrary(hMod);
end;
If you were paranoid you might choose to add an alternative termination of the loop to avoid looping indefinitely.
I don't really know that this will work in your scenario. For instance, it's quite plausible that your process links statically to WSock32. In which case no amount of calling FreeLibrary will kick it out. And even if you could kick it out, the fact that your process statically linked to it probably means it's going to fail pretty hard.
Even if you can kick it out, it seems likely that other code in your process will hold references to functions in the module. And so you'll just fail somewhere else. I can think of very few scenarios where it makes sense to kick a module out of your process with complete disregard for the other users of that module.
Now, let's step back and look at what you are doing. You are trying to remove a standard system DLL from your process because you believe that it is only present because your process is having its packets sniffed. That seems unlikely to be true.
Since you state that your process is subject to packet sniffing attack. That means that the process is communicating over TCP/IP. Which means that it probably uses system modules to carry out that communication. One of which is WSock32. So you very likely link statically to WSock32. How is your process going to work if you kill one of the modules used to supply its functionality?
Are you quite sure that the presence of WSock32 in your process indicates that your process is under attack? If a packet sniffer was going to inject a DLL into your process, why would it inject the WSock32 system DLL? Did you check whether or not your process, or one of its dependencies, statically links to WSock32?
I rather suspect that you've just mis-diagnosed what is happening.
Some other points:
GetModuleHandle returns, and FreeLibrary accepts an HMODULE. For 32 bit that is compatible with Cardinal, but not for 64 bit. Use HMODULE.
The not found condition for GetModuleHandle is that the return value is 0. Nowhere in the documentation is it stated that a value greater than 0 indicates success. I realise that Cardinal and HMODULE are unsigned, and so <>0 is the same as >0, but it really makes no sense to test >0. It leaves the programmer thinking, "what is so special about <0?"

Easiest way to find previous instance of an application

I have rewritten a VB6 application in Delphi. It should have only one instance running. How can I do this with minimum of code?
In VB6 we just have to use one single line of code
>
If App.PrevInstance Then
'Take some action
End If
On goggling I did find a solution but it is very length and we have to mess with .drp file.
I do not want to do that.
I want something simpler.
I have some code along the lines of:
var
AppMutex: THandle;
{ .... }
initialization
// Create the mutex
AppMutex := CreateMutex(nil, True, 'MY-APPLICATION-NAME');
if (AppMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
begin
MessageDlg('My application is already running on this computer.'#13#10+
'You should close the other instance before starting a new one.',mtError,
[mbOK],0);
Halt;
end;
finalization
// Close the mutex
CloseHandle(AppMutex);
but I'm sure the answers in the thread that #mghie linked to are more helpful/richer features!
Edit: Note you can make this into a small unit in it's own right, then just use that unit in your project(s).
Note that in many cases, the user's expecation will be that launching the second instance results in the first instance being restored and brought to the foreground. Don't expect users to understand the difference between restoring a minimized/hidden app and launching from a shortcut or start menu.
In my experience one cannot decide in general wether an application my be started twice or not. It may be for instance perfectly valid to start the same application if it is started in another folder or under another user account or whatever. On the other hand it might be the case that two different applications may not run together if they are started in the same folder or so.
So besides the different approaches with mutexes and semaphores and handling race conditions, it is the wise selection of the mutex's or semaphore's name that handles the above combinations appropriately.
If an application may not run twice at all, take a GUID like name. You can even use the exe's filename if you can ignore that someone might rename it.
Restricting the one-time-start on a specific folder, you can take the exe path into account, but be aware that due to mappings different pathes may end up at the same exe.

Can you Catch an Exception after the main application unit has ended?

In one of our application im getting an exception that i can not seem to find or trap.
...
Application.CreateForm(TFrmMain, FrmMain);
outputdebugstring(pansichar('Application Run')); //this is printed
Application.Run;
outputdebugstring(pansichar('Application Run After')); //this is printed
end.
<--- The Exception seems to be here
The Event log shows
> ODS: Application Run
> //Various Application Messages
> ODS: Application Run After
> First Change Exception at $xxxxxxxx. ...etc
All i can think of is it is the finalization code of one of the units.
(Delphi 7)
Try installing MadExcept - it should catch the exception and give you a stack-trace.
It helped me when I had a similar issue.
Here's two things you can try:
1) Quick and easy is to to hit 'F7' on the final 'end.'. This will step you into the other finalization blocks.
2) Try overriding the Application.OnException Event.
The SysUtils unit actually sets up the default ErrorProc and ExceptProc procedures in its initialization section, and undoes them in its finalization section, so often in this situation it's worth ensuring that SysUtils is the very first unit in the uses clause in your dpr, so then it will be the last one finalised. Might be enough to get you some meaningful data about what is going wrong.
Finalization exceptions are tricky. Even if you put SysUtls first in your project file, your application object may already be gone, which means your global exception handler is gone too. MadExcept may work for this though.
Another solution is to put a Try / Except block in each of your unit finalization sections, and then handle the exceptions there.
What is your objective? Do you want to suppress the exception or debug it? Debugging it can be done by stepping through them with F7 as Zartog suggested. If you discover which unit has the exception in finalization then you might try placing it in a different order in the uses clause it is called from.
Good luck!

Resources