3
votes

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:

  1. Create a folder where all project files can be saved
  2. Create files in the folder for each of the five files included below
  3. Launch Delphi & Close All Files
  4. Click "File | New | Other | Delphi Project | Package"
  5. Save the package in the folder from step 1 as 'Package1'
  6. Add CDS2.pas to Package1
  7. Build Package1 (add suggested packages)
  8. Install Package1 (will register TMyCDS)
  9. Add BaseForm.pas to Package1 (add suggested VCL framework)
  10. Build Package1 (add suggested packages), build again
  11. Right-click ProjectGroup1 and select "Add New Project | Delphi Projects | Package"
  12. Save the new package in the folder from step 1 as 'Package2'
  13. Add SecondFrame.pas to Package2 (add suggested VCL framework)
  14. Build Package2 (add suggested packages)
  15. View SecondFrame in design mode (e.g., Press F12)
  16. Save any changes (including the project group because Delphi is about to crash)
  17. 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:

  1. Relaunch Delphi
  2. Make sure SecondFrame is not open
  3. Remove/re-install Package1 and rebuild it
  4. Double-click Package1 so it is the active project
  5. Set the debug host application to Delphi (C:\[path]\RAD Studio\9.0\bin\bds.exe)
  6. Run Package1 with debug (F9)
  7. Once Delphi opens a second time (in the second instance) make sure your project group is opened and then open SecondFrame
  8. 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.
1
+1 For a very thorough question. However, unless you are just after knowledge and an answer to the "why", I think you would need to file a bug report to QC for this to get a resolution.Marjan Venema
I was hoping someone else had a similar problem with the TClientDataSet and found a cleaver work around. But I'm leaning towards your same conclusion -- a QC report...James L.
Come to think of it, have you tried the same thing with descendants of other "standard" controls? The TClientDataSet involvement may be a red herring?Marjan Venema
Excellent question -- I tried it with only a TMyEdit = class(TEdit) (no flavor of TClientDataSet) and the result is 100% the same.James L.
Ah, that's unfortunate, but what I expected. Visual form inheritance is nice, but has its drawbacks. I have run into a couple of strange problems as well. Changes in ancestors not ending up in descendants depending on either or both being open, that sort of thing. The only "work around" I have found was to ensure that all descendants are closed when editing an ancestor plus not relying on the dfm and setting up forms, frames and controls at run-time. Yes it does take away the visual design features, but is much more reliable.Marjan Venema

1 Answers

0
votes

I was struggling with DSPack installation on Delphi XE2. I would swear that it was working to the date. However, after getting AV I tried many ways to fix it.

I finally fixed it after I saw your question which pointed me to the idea that inheritance is messing it up. First I moved everything from base package to design page and then I removed base package from project group, compiled, and installed. Working fine.