I'm using Delphi XE2 (Update 3). I have a very large project, which sometimes crashes the Delphi IDE when I compile a package. I have been able to strip it down to a simple project that replicates the issue.
Problem Summary
When you do visual form inheritance between packages using a VCL Frame and the ancestor frame includes a standard control, everything works fine.
When you do the same thing, except you replace the standard control in the ancestor frame with a sub-class of the control, then you can easily crash the Delphi IDE.
All you have to do is compile the package that contains the ancestor frame while viewing a VCL Frame in Design Mode that is a member of another package where the VCL Frame descends/inherits from the ancestor frame with a sub-classed control.
I have tried sub-classing both a TClientDataSet
and a TEdit
. Both exhibit the same behavior.
Question
Why can't you use a sub-classed control when doing Visual Form Inheritance between packages when you can use the standard controls?
Steps to Reproduce Problem:
- Create a folder where all project files can be saved
- Create files in the folder for each of the five files included below
- Launch Delphi & Close All Files
- Click "File | New | Other | Delphi Project | Package"
- Save the package in the folder from step 1 as 'Package1'
- Add
CDS2.pas
to Package1 - Build Package1 (add suggested packages)
- Install Package1 (will register TMyCDS)
- Add
BaseForm.pas
to Package1 (add suggested VCL framework) - Build Package1 (add suggested packages), build again
- Right-click
ProjectGroup1
and select "Add New Project | Delphi Projects | Package" - Save the new package in the folder from step 1 as 'Package2'
- Add
SecondFrame.pas
to Package2 (add suggested VCL framework) - Build Package2 (add suggested packages)
- View
SecondFrame
in design mode (e.g., Press F12) - Save any changes (including the project group because Delphi is about to crash)
- While viewing the
SecondFrame
in design mode, build Package1
The build fails and I get this error:
[DCC Error] E2161 Error: RLINK32: Error opening file "C:\[folder]\BaseFrame.dfm"
If I compile instead of build in step 17, it will often compile without errors. However, sometimes when I then try to re-display SecondFrame
in design mode, I get this error:
Access violation at address 5003C976 in module 'rtl160.bpl'. Read of address FFFFFFC4.
[5003C976]{rtl160.bpl } System.GetDynaMethod (Line 13480, "System.pas" + 7) + $0
[500ADE1D]{rtl160.bpl } System.Classes.IsDefaultObjectProp (Line 9525, "System.Classes.pas" + 9) + $B
[500AE2C1]{rtl160.bpl } System.Classes.IsDefaultPropertyValue (Line 9651, "System.Classes.pas" + 29) + $A
[500AECA7]{rtl160.bpl } System.Classes.TWriter.WriteProperty (Line 9893, "System.Classes.pas" + 12) + $7
[5044739A]{vcl160.bpl } Vcl.Forms.TScrollingWinControl.IsTouchPropertyStored (Line 3200, "Vcl.Forms.pas" + 1) + $4
[503432C6]{vcl160.bpl } Vcl.Controls.TCustomTouchManager.IsTabletOptionsStored (Line 17359, "Vcl.Controls.pas" + 1) + $9
[500AE08D]{rtl160.bpl } System.Classes.IsDefaultMethodProp (Line 9606, "System.Classes.pas" + 4) + $4
[500AE0ED]{rtl160.bpl } System.Classes.IsDefaultMethodProp (Line 9609, "System.Classes.pas" + 7) + $24
[500AE2CC]{rtl160.bpl } System.Classes.IsDefaultPropertyValue (Line 9653, "System.Classes.pas" + 31) + $A
[5033A7E9]{vcl160.bpl } Vcl.Controls.TWinControl.GetChildren (Line 12359, "Vcl.Controls.pas" + 1) + $3
[5003C9A6]{rtl160.bpl } System.@CallDynaInst (Line 13519, "System.pas" + 4) + $0
[50447AE1]{vcl160.bpl } Vcl.Forms.TCustomFrame.GetChildren (Line 3450, "Vcl.Forms.pas" + 6) + $6
[500AD658]{rtl160.bpl } System.Classes.TWriter.WriteData (Line 9270, "System.Classes.pas" + 54) + $2
[500B4423]{rtl160.bpl } System.Classes.TComponent.ValidateRename (Line 12845, "System.Classes.pas" + 0) + $F
[500AD317]{rtl160.bpl } System.Classes.TWriter.WriteComponent (Line 9200, "System.Classes.pas" + 20) + $9
[500AD761]{rtl160.bpl } System.Classes.TWriter.WriteFloat (Line 9298, "System.Classes.pas" + 1) + $3
[20FEC1AB]{designide160.bpl} ComponentDesigner.TComponentRoot.CreateRootInstance (Line 2288, "ComponentDesigner.pas" + 24) + $7
[20FEBFD7]{designide160.bpl} ComponentDesigner.TComponentRoot.CreateRootAs (Line 2255, "ComponentDesigner.pas" + 2) + $4
[20FEBEFA]{designide160.bpl} ComponentDesigner.TComponentRoot.CreateFromStream (Line 2235, "ComponentDesigner.pas" + 7) + $9
[20FEEF41]{designide160.bpl} ComponentDesigner.TComponentRoot.Resurrect (Line 3434, "ComponentDesigner.pas" + 11) + $6
[2104F16E]{designide160.bpl} EmbeddedDesignerForm.TFormEditorView.Display (Line 144, "EmbeddedDesignerForm.pas" + 4) + $5
[2075E399]{coreide160.bpl} EditorForm.TEditWindow.ShowView (Line 4294, "EditorForm.pas" + 49) + $F
[20758D44]{coreide160.bpl} EditorForm.TEditWindow.SwitchViews (Line 2147, "EditorForm.pas" + 6) + $9
[2075889A]{coreide160.bpl} EditorForm.TEditWindow.ViewBarChange (Line 1996, "EditorForm.pas" + 2) + $1
[504C0F8D]{vcl160.bpl } Vcl.Tabs.TTabSet.CanChange (Line 1910, "Vcl.Tabs.pas" + 3) + $9
[504C0FDE]{vcl160.bpl } Vcl.Tabs.TTabSet.SetTabIndex (Line 1921, "Vcl.Tabs.pas" + 5) + $0
[504C126A]{vcl160.bpl } Vcl.Tabs.TTabSet.MouseDown (Line 2033, "Vcl.Tabs.pas" + 6) + $2
[50332E54]{vcl160.bpl } Vcl.Controls.TControl.DoMouseDown (Line 7343, "Vcl.Controls.pas" + 7) + $2B
[50332EA3]{vcl160.bpl } Vcl.Controls.TControl.WMLButtonDown (Line 7354, "Vcl.Controls.pas" + 7) + $E
[5033280D]{vcl160.bpl } Vcl.Controls.TControl.WndProc (Line 7204, "Vcl.Controls.pas" + 91) + $6
[5033715B]{vcl160.bpl } Vcl.Controls.TWinControl.WndProc (Line 9976, "Vcl.Controls.pas" + 152) + $6
[5003D4F7]{rtl160.bpl } System.TMonitor.TryEnter (Line 14786, "System.pas" + 10) + $0
[5003D06C]{rtl160.bpl } System.TMonitor.Enter (Line 14489, "System.pas" + 4) + $2
[5003CF10]{rtl160.bpl } System.TMonitor.CheckOwningThread (Line 14411, "System.pas" + 2) + $0
[5003D216]{rtl160.bpl } System.TMonitor.Exit (Line 14600, "System.pas" + 9) + $7
[5003D24F]{rtl160.bpl } System.TMonitor.Exit (Line 14614, "System.pas" + 2) + $7
[50313627]{vcl160.bpl } Vcl.Graphics.FreeMemoryContexts (Line 7043, "Vcl.Graphics.pas" + 12) + $8
[503367B0]{vcl160.bpl } Vcl.Controls.TWinControl.MainWndProc (Line 9689, "Vcl.Controls.pas" + 3) + $6
[503367C5]{vcl160.bpl } Vcl.Controls.TWinControl.MainWndProc (Line 9692, "Vcl.Controls.pas" + 6) + $0
[503369F0]{vcl160.bpl } Vcl.Controls.TWinControl.IsControlMouseMsg (Line 9753, "Vcl.Controls.pas" + 9) + $25
[5033715B]{vcl160.bpl } Vcl.Controls.TWinControl.WndProc (Line 9976, "Vcl.Controls.pas" + 152) + $6
[503367B0]{vcl160.bpl } Vcl.Controls.TWinControl.MainWndProc (Line 9689, "Vcl.Controls.pas" + 3) + $6
[500B6030]{rtl160.bpl } System.Classes.MakeObjectInstance (Line 13921, "System.Classes.pas" + 0) + $0
[504525E7]{vcl160.bpl } Vcl.Forms.TApplication.ProcessMessage (Line 10164, "Vcl.Forms.pas" + 23) + $1
[5045262A]{vcl160.bpl } Vcl.Forms.TApplication.HandleMessage (Line 10194, "Vcl.Forms.pas" + 1) + $4
[5045295D]{vcl160.bpl } Vcl.Forms.TApplication.Run (Line 10331, "Vcl.Forms.pas" + 26) + $3
Regardless of what error occurs, when you try to do almost anything else Delphi will throw various random Access Violations. I close Delphi after dismissing the error. Then I kill BDS.EXE using Task Manager (to avoid many additional A/V errors).
I tried debugging Delphi as follows:
Debugging:
- Relaunch Delphi
- Make sure
SecondFrame
is not open - Remove/re-install Package1 and rebuild it
- Double-click Package1 so it is the active project
- Set the debug host application to Delphi (C:\[path]\RAD Studio\9.0\bin\bds.exe)
- Run Package1 with debug (F9)
- Once Delphi opens a second time (in the second instance) make sure your project group is opened and then open
SecondFrame
- Make sure
SecondFrame
is in design mode (e.g., press F12) and then compile Package1
Sometimes the first instance of Delphi will trap the exception raised in the second instance, sometimes it won't. When it does, the exception and stack trace look like this:
First chance exception at $5003C97D. Exception class $C0000005 with message 'access violation at 0x5003c97d: read of address 0x00000001'. Process bds.exe (8912)
:5003c97d GetDynaMethod + $D
:20fd45a6 TPairings.AddChildren + $46
:20fd4351 TPairing.SetComponent + $2D
:20fed656 TComponentRoot.GetRootStream + $5E
:20ff9d26 TRootStream.Create + $7A
:20ff2704 TComponentRoot.FormFileOpen + $14
:21b4231b ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\delphicoreide160.bpl
:204e7a1e ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\coreide160.bpl
:20614f2f ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\coreide160.bpl
:206150f9 ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\coreide160.bpl
:20615173 ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\coreide160.bpl
:066d1339 ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\dcc32160.dll
:1ac81dea ; C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\RLINK32.DLL
:2a242a24
.
Here are the 5 files to use in the Steps to Reproduce Problem above:
BaseFrame.dfm
object BaseFrameClass: TBaseFrameClass
Left = 0
Top = 0
Width = 320
Height = 240
TabOrder = 0
object MyCDS1: TMyCDS
Aggregates = <>
Params = <>
Left = 8
Top = 8
end
end
BaseFrame.pas
unit BaseFrame;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Data.DB, Datasnap.DBClient, CDS2;
type
TBaseFrameClass = class(TFrame)
MyCDS1: TMyCDS;
end;
implementation
{$R *.dfm}
end.
CDS2.pas
unit CDS2;
interface
uses
System.SysUtils, System.Classes, Data.DB, Datasnap.DBClient;
type
TMyCDS = class(TClientDataSet)
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Test', [TMyCDS]);
end;
end.
SecondFrame.dfm
inherited SecondFrameClass: TSecondFrameClass
end
SecondFrame.pas
unit SecondFrame;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, BaseFrame, Data.DB, Datasnap.DBClient, CDS2;
type
TSecondFrameClass = class(TBaseFrameClass)
end;
implementation
{$R *.dfm}
end.
TClientDataSet
and found a cleaver work around. But I'm leaning towards your same conclusion -- a QC report... – James L.TMyEdit = class(TEdit)
(no flavor ofTClientDataSet
) and the result is 100% the same. – James L.