Startup error during main form creation - delphi

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.

Related

Special case: wrong order of updates for fly-away

How can I track down the location of the "Special case: wrong order of updates for fly-away!" error?
This error message is defined in Datasnap.DSIntf as
const
...
ERRCODE_FLYAWAY_WRONGORDER = 13; { Special case: wrong order of updates for fly-away }
...
DBERR_FLYAWAY_WRONGORDER = ERRBASE_ALC + ERRCODE_FLYAWAY_WRONGORDER;
but nowhere else in the Delphi sources can I find references to substring FLYAWAY_WRONGORDER.*
My intention was to compile with debug dcu's, then put a breakpoint on the line where the exception is raised and check the call stack UP to find the cause.
I'm currently stepping DOWN into the code until the error occurs, but that is less efficient (complex app).
Placing a TApplicationEvents with a breakpoint in its OnException handler does not give me usable call stack information:
So, how can I (efficiently) track down the place where this error is generated?
Background on what is going on:
Form uses DevExpress TcxScheduler connected to TcxSchedulerStorage component in datamodule, connected to nested TClientDataSets
Code saves all changes to these datasets (ApplyUpdates)
In BeginUpdate/EndUpdate for these DevExpress components, I then insert, delete and update records in these datasets, move around while doing so, even change parent IDs in detail datasets so that they drop from the current detail dataset 'in view'.The error occurs when I Edit, then Post a record doing exactly that.
Delphi Tokyo 10.2.3, Win32 app
Any other info on that error message is welcome, I was not able to find anything.
I actually 'fixed' the error by calling ApplyUpdates for the master dataset in a few places, but since I'm not really sure about the cause I want to investigate this further. So my question is not How do I fix the error in my code, it is How do I find the error in my code?
* There is a CheckForFlyAway routine in TCustomADODataSet.InternalPost in Data.Win.ADODB but we don't use ADO, I cannot set breakpoints in those routines.

How do I keep Delphi from automatically expanding folded code regions?

I widely use {$Regions} in my units, but sometimes the VCL editor takes annoying decisions to automatically expand all regions. Is there any way to tell the editor not
to expand regions that are collapsed unless I explicity do this by clicking on the + button?
Update from comments:
Unfolding occurs,
with nested procs/funcs. Introducing a new nested "procedure" header. As soon as you type the 'p' character, all other nested procs/funcs are unfolded. This occurss also if, for instance, by mistake, you delete the "end" of any nested proc/func (or anything of the kind).
with regions. If you start a comment with "{", the Region immediately below is unfolded. Starting a comment with "(*" provoques all Regions below to be unfolded and same applies to all procs/funcs under those Regions.
Unfortunately this is one of the problems of Delphi whis is present athleast since Delphi XE if not even from older versions and still hasn't been fixed.
The reason why code gets automaticaly unfolded is the fact that as soon as Error Insight system detects any syntax error in your unit it treats all the code below that poiunt as non-valid and thus expans all folded code below that point.
So far the only way that I know to avoid this is to disable the Error Insight. But that means you won't be warned about any potentional syntax errors untill you try to compile your program.
But I seriously hope Embarcadero will go and fix this soon as it makeswhole code folding system to be useless unles you have Error Insight disabled as you spend more time folding the autoexpanded code again that writing any new code.
EDIT: Steps to reproduce this (one way of reproducing it)
Create new application
Create two new even handlers for OnCreate and OnClose for your form or any two other methods.
procedure TForm1.FormCreate(Sender: TObject);
begin
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//
end;
In case if you created even handlers make sure there is athleast some code in the lowest handler metrhod or athleast one commented line so that optimizer doesent automatically remove the "empy" event handler.
Now in top event handler write "Form." and you will se how bottom event handler will be automatically expanded.
You will see that at this point delphi desent even know when or where current method code block in which syntax error has been detected ends. And this also makes it imposible to properly detect any code blocks below that point.

How to reproduce this Code Completion bug?

I'm having a bug on Delphi XE2 (Update 4 Hotfix 1), which reproduces many times on the legacy project I work (it evolved from D6 to D7,D2006 and finally XE2), but I didn't know how to trigger it in a smaller project.
The latest time, it triggered on creating an event handler for a "hidden popup" on the app. When I click on the menu option to create the Click handler this happens.
pprocedure TMainForm.Blablabla1Click(Sender: TObject);
begin
end;
rocedure TMainForm.FormActivate(Sender: TObject);
You can see that the IDE inserted the new code INSIDE the declaration of the next method... But it's not all.
Almost all times, on the DPR, code gets mangled too:
AApplication.CreateForm(TDM_DataAcc, DM_DataAcc);
AApplication.CreateForm(TMainForm, MainForm);
pplication.CreateForm(Tfrm_login, frm_login);
f frm_Login.CanLogin = mrOK then Application.Run
(It's almost like that, I don't remember if the 3rd Application.CreateForm get its' 'A' clipped or not, the other I'm sure are doubled and the IF gets its' "I" clipped).
Chasing on QualityCentral doesn't help (found nothing). This also happens sometimes on Class Completion(Ctrl-SHift-C).
Someone knows what triggers that bug, so I can create an new application and send it to Embarcadero?
Behavior like that suggests that the IDE is miscounting characters in the file. There are several "file oddities" that the developers might not have anticipated and that could cause a character index to be miscalculated.
Check your file for unusual line endings. For example, a line missing a carriage return will appear correctly in the editor, but can cause incorrect line numbers elsewhere in the program.
Non-breaking spaces are another kind of character that will appear normally, and maybe even parse correctly, but occupies multiple bytes when represented in UTF-8 when the "normal" version of the character (a regular space) only takes up one. You will sometimes acquire such characters if you copy code from a Web browser.
Incorrect byte-order marks for UTF-8 or UTF-16 source files might also cause problems.
Often, opening your source file in Notepad or a hex editor will help you identify these problems.

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

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.

Delphi "EClassNotFound" errors, and corrupted DFM possibility

I am getting a cascading set of "EClassNotFound" errors in in my Delphi 2007 project. Doesn't seem to be caused by the missing Name property value as often is the case, and though adding RegisterClass(XXX) in the initialization section(s) fixes the EClassNotFound error at hand, another one follows it seemingly indefinitely.
I finally cracked open the DFM file in text editor, and it looks likely corrupted to me (lots of non-ASCII characters amidst form element names, and very "unstructured" looking when compared to what I'm used to seeing in a DFM file). (I'd post a same here but not sure that's OK, w/the non-aSCII, so will hold off).
The form loads fine, and seems to compile / syntax check OK too, but once I run it, trouble.
Going back to early versions of it in SVN, it looks like it's been in this state for some time, which makes me think that either A) the DFM file isn't my problem, or B) the Delphi form-streaming is quite fault-tolerant/robust (Bonus Question: Which is it?).
If the DFM file is the problem, and is corrupted, rolling back will have to be a roll-back WAY back, and that's gonna be expensive. Given that the IDE can still load it, is there any utility that can clean up the file?
Or, am I totally off base w/the DFM as primary suspect?
Thanks folks for the input. Forgot about the binary/text options w/DFM files, so that was helpful. It looks like the DFM itself is not corrupted.
Still having the EClassError issue though. re: It being missing property values, or referencing non-existing properties, etc., a further question: Is the class the error is given for (currently TnxSqlUpdateObject, but probably more waiting in the wings if experience thus far is consistent) usually/always the actual "culprit" class/object?
For instance, right now my main form has four references to TnxSqlUpdateObject, w/those actually dropped on the form. If I put RegisterClass(TnxSqlUpdateObject) in the initialization section, it runs fine for that EClassNotFound error but then goes on to the next one (in this case, TStringField).
I have reinstalled the NexusDB components in this case, and also built a new project using some of the components I thought might be the problem. It compiles and runs fine, UNTIL I add this other form from my real project (which, in turn, unfortunately references quite a few others).
SO, it sounds like my real issue is how to methodically diagnose and fix any and all EClassNotFound errors?
I get this error if a component is on the form, but doesn't have an entry in the form definition in the source file too. Most often when I've copied and pasted from another form. Simplest solution is to select the component, cut it, then paste it back. When you save, the component's unit will be added to the source, and when you run it again it will all be okay.
Well, a dfm file could be binary or tekst (as I'm correct from version 4.0).
You can check this by right click on the form and check the Text DFM flag.
If a dfm file is corrupt, tou can try to fix it by removing all suspicious lines.
Be sure to leave the object .. end sets intact and you probably only loose some property values.
By the way, the dfm file should look like this (to get an idea of the general structure):
object Form5: TForm5
Left = 0
DesignSize = (
426
652)
object Button1: TButton
Left = 343
end
object Memo2: TMemo
Anchors = [akLeft, akTop, akRight, akBottom]
end
end
If it does not look like that you are probably editing the binary file.
If you have a recent compiled exe that works, you can use a resource-editor, like PE Explorer, to get the dfm-definition. Then you can compare the one from the exe with the one that you now have.
I believe there is tools to convert binary dfm-files to text-files too. This will give you a better view on the file, and help you decide if it's really corrupted or not. I see Felix has something on the topic.
If the Delphi IDE shows the form ok without errors, I can't believe there is a corruption-error. Could there be a package problem? Do you use runtime-packages?
Update:
Hvae you tried Eurekalog or madExcept or something similar to get a more detailed error message with callstack and memorydumt? Maybe that will give you some clue about the problem.
But generally i think this error comes from missing runtime package, or a missing unit in the uses-clause. If you think you know witch component causes the error, search the source for the call to RegisterClass( ), and see if that unit somehow is included in the projcets uses-clause. If not, add it and try again.
If you can load the form in the Delphi IDE the DFM resource is not corrupted. Delphi uses the same code to load the DFM as the final executable will use, so I think that won't be the reason.
You can open the DFM in the Delphi IDE directly (if the corresponding pas file is not open), or you can use Alt+F12 to switch between form view and text view of the DFM. In this view the structure should be sane, with correct indentation and so on.
As Gamecat pointed out you can use the command in the form popup menu to toggle the DFM storage format. Leave it as text for Delphi 5+, it works better this way with SVN.
As for the cause of your runtime problem - I have no idea...
Edit: After your ruling out the DFM as the source of the problem I can only assume that an important unit in the uses list is missing, which can only happen if not all the components on your form have a corresponding member field. You should check that all the components referenced in the DFM are also in the form, even when you do not access them in your code. This will in turn cause Delphi to add any missing units to the uses clause when the file is saved. Manually registering components should not be necessary if the form class has references to all the components in the DFM.
For a quick check you could create a test form, drop all of the components that your "problem" form has onto it (one instance is enough), and check whether this works.
This can happen in case you have changed one of your custom components and removed a property from it. The property is stil in the DFM and Delphi tries to initialize it.
Try to remove manually parts from your DFM so you can pinpoint which component is causing the problem.
Try this:
Make backup first
Right click on form in designer; uncheck "Text DFM"
Save
Right click on form in designer; check "Text DFM"
Save

Resources