Delphi 模块“GUI.exe”中地址00822135处的访问冲突。读取地址00000040
sqlite是一个数据库——一个描述符,包含表列表、域列表、字段列表、主键和外键列表以及索引列表。在内置组件的帮助下,我从Delphi XE3连接到这个基础上。有一个单独的模块,其中描述了类TTableSpec、TFieldSpec、TconstraintsSpec、TconstraintdSetSpec、TDomainSpec。这些类对应于上述sqlite的basis记录。在TTableSpec类中有这样的FFields字段:TComponent成为对象的所有者,如也已从basis卸载的TFieldSpec。例如,DBSchema还包含作为所有表所有者的FTables字段,而在TFieldSpec类中有FDomainSpec字段:TDomainSpec。实际上,我给出了一个连接到错误的类的代码Delphi 模块“GUI.exe”中地址00822135处的访问冲突。读取地址00000040,delphi,delphi-xe2,runtime-error,access-violation,Delphi,Delphi Xe2,Runtime Error,Access Violation,sqlite是一个数据库——一个描述符,包含表列表、域列表、字段列表、主键和外键列表以及索引列表。在内置组件的帮助下,我从Delphi XE3连接到这个基础上。有一个单独的模块,其中描述了类TTableSpec、TFieldSpec、TconstraintsSpec、TconstraintdSetSpec、TDomainSpec。这些类对应于上述sqlite的basis记录。在TTableSpec类中有这样的FFields字段:TComponent成为对象的所有者,如也已从basis卸载的TFi
type
TDataTypeId = (DataTypeId_String, DataTypeId_SmallInt, DataTypeId_Integer, DataTypeId_Word,
DataTypeId_Boolean, DataTypeId_Float, DataTypeId_Currency,
DataTypeId_BCD, DataTypeId_FmtBCD, DataTypeId_Date,
DataTypeId_Time, DataTypeId_DateTime, DataTypeId_TimeStamp,
DataTypeId_Bytes, DataTypeId_VarBytes, DataTypeId_Blob,
DataTypeId_Memo, DataTypeId_Graphic, DataTypeId_fmtMemo,
DataTypeId_FixedChar, DataTypeId_WideChar, DataTypeId_LargeInt,
DataTypeId_Array, DataTypeId_FixedWideChar, DataTypeId_WideMemo, DataTypeId_Default);
TDBSchemaSpec=class(Tcomponent)
private
FDomains: TComponent;
FTables : TComponent;
public
procedure Setup();
destructor Destroy; override;
property Domains: TComponent read FDomains;
property Tables : TComponent read FTables;
end;
TDomainSpec = class(TComponent)
private
FName: string;
FDescription: String;
FDataTypeId: TDataTypeId;
FLength: Cardinal;
FCharLength: Cardinal;
FPrecision: Cardinal;
FScale: Cardinal;
FWidth: Word;
FAlign: TAlignSpec;
FShowNull: Boolean;
FShowLeadNulls: Boolean;
FThousandsSeparator: Boolean;
public
procedure Setup(FName: string; FDescription: String; FDataTypeId: TDataTypeId;
FLength: Cardinal;FCharLength: Cardinal;FPrecision: Cardinal;FScale: Cardinal;
FWidth: Word;FAlign: TAlignSpec;FShowNull: Boolean;FShowLeadNulls: Boolean;
FThousandsSeparator: Boolean);
destructor Destroy; override;
property Name: String read FName;
property Description: String read FDescription;
property DataTypeId: TDataTypeId read FDataTypeId;
property Length: Cardinal read FLength;
property CharLength: Cardinal read FCharLength;
property Precision: Cardinal read FPrecision;
property Scale: Cardinal read FScale;
property Width: Word read FWidth;
property Align: TAlignSpec read FAlign;
property ShowNull: Boolean read FShowNull;
property ShowLeadNulls: Boolean read FShowLeadNulls;
property ThousandsSeparator: Boolean read FThousandsSeparator;
end;
TTableSpec= class(TComponent)
private
FFields : TComponent;
FIndices: TComponent;
FConstraints : TComponent;
FName : string;
FDescription: string;
FCanAdd: boolean;
FCanEdit: boolean;
FCanDelete: boolean;
public
procedure Setup(FName : string; FDescription:string;
FCanAdd: boolean; FCanEdit: boolean; FCanDelete: boolean);
destructor Destroy; override;
property Description : string read FDescription;
property Name : string read FName;
property CanAdd: boolean read FCanAdd;
property CanEdit: boolean read FCanEdit;
property CanDelete: boolean read FCanDelete;
property Fields : TComponent read FFields;
property Indices: TComponent read FIndices;
property Constraints : TComponent read FConstraints;
end;
TFieldSpec = class(TComponent)
private
FDomainSpec: TDomainSpec;
FPosition: integer;
FFieldName: string;
FDescription: string;
FCanInput: boolean;
FCanEdit: boolean;
FShowInGrid: boolean;
FShowInDetails: boolean;
FIsMean: boolean;
FAutoCalculated: boolean;
FRequired: boolean;
public
procedure Setup(FDomainSpec: TDomainSpec; FPosition: integer; FFieldName: string; FDescription: string; FCanInput: boolean; FCanEdit: boolean;
FShowInGrid: boolean; FShowInDetails: boolean; FIsMean: boolean;FAutoCalculated: boolean;
FRequired: boolean);
destructor Destroy; override;
property DomainSpec: TDomainSpec read FDomainSpec;
property Position: integer read FPosition;
property FieldName: string read FFieldName;
property Description: string read FDescription;
property CanInput: boolean read FCanInput;
property CanEdit: boolean read FCanEdit;
property ShowInGrid: boolean read FShowInGrid;
property ShowInDetails: boolean read FShowInDetails;
property IsMean: boolean read FIsMean;
property AutoCalculated: boolean read FAutoCalculated;
property Required: boolean read FRequired;
end;
在应用程序中,有一个表单fmListOfTables,从该表单中,在复选框中选择将在其他窗口的DBGrid中显示数据的表名。错误
Access violation at address 00822135 in module 'GUI.exe'.Read of address 00000040.(When debugging Project GUI.exe raised exception class $C0000005 with message 'access violation at 0x00822135: read of address 0x00000040'. )
起于第一线
if ((TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i] is TFieldSpec) and (TDomainSpec(TFieldSpec(TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i]).DomainSpec).DataTypeId<>DataTypeId_Blob) and (TDomainSpec(TFieldSpec(TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i]).DomainSpec).DataTypeId<>DataTypeId_WideMemo)) then
在选择表格的过程中
procedure TfmListOfTables.ListBox1DblClick(Sender: TObject);
var fmShowData : TfmTableData;
i : integer;
querystr : string;
begin
MainWindow.IBDatabase1.DatabaseName:=MainWindow.dbname;
MainWindow.IBDatabase1.Connected:=true;
fmShowData:=TfmTableData.Create(MainWindow);
fmShowData.Caption:=ListBox1.Items.Strings[ListBox1.ItemIndex];
fmShowData.tname:=ListBox1.Items.Strings[ListBox1.ItemIndex];
DisplayTable:=ListBox1.Items.Strings[ListBox1.ItemIndex];
querystr:='select ';
for i:= 0 to TTableSpec(DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.ComponentCount-1 do
begin
if ((TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i] is TFieldSpec) and (TDomainSpec(TFieldSpec(TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i]).DomainSpec).DataTypeId<>DataTypeId_Blob) and (TDomainSpec(TFieldSpec(TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i]).DomainSpec).DataTypeId<>DataTypeId_WideMemo)) then
querystr:=querystr+TFieldSpec(TTableSpec(MainForm.DBSchema.Tables.FindComponent(ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i]).FieldName+', ';
end;
Delete(querystr, Length(querystr)-1, 1);
querystr:=querystr+'from '+fmShowData.tname;
fmShowData.IBQuery1.SQL.Clear;
fmShowData.IBQuery1.SQL.Add(querystr);
fmShowData.IBQuery1.Open;
fmShowData.DBGrid1.DataSource:=fmShowData.DataSource1;
for I := 0 to fmShowData.DBGrid1.Columns.Count-1 do
fmShowData.DBGrid1.Columns[i].Width:=90;
fmShowData.DragKind:=dkDock;
fmShowData.DragMode:=dmAutomatic;
fmShowData.tname:=ListBox1.Items.Strings[ListBox1.ItemIndex];
TfmTableData(fmShowData).databasetable:=ListBox1.Items.Strings[ListBox1.ItemIndex];
fmShowData.Show;
end;
让我们看一下导致问题的代码行:
if ((TTableSpec(MainForm.DBSchema.Tables.FindComponent(
ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i] is TFieldSpec)
and (TDomainSpec(TFieldSpec(TTableSpec(MainForm.DBSchema.Tables.FindComponent(
ListBox1.Items.Strings[ListBox1.ItemIndex])).Fields.Components[i]).DomainSpec)
.DataTypeId<>DataTypeId_Blob) and (TDomainSpec(TFieldSpec(TTableSpec(MainForm.
DBSchema.Tables.FindComponent(ListBox1.Items.
Strings[ListBox1.ItemIndex])).Fields.Components[i]).DomainSpec).
DataTypeId<>DataTypeId_WideMemo)) then
然后我们可以这样写:
Component1 := MainForm.DBSchema.Tables.FindComponent(ComponentName);
我们继续这样做:
Component2 := TTableSpec(Component1).Fields.Components[i];
然后代码可以如下所示:
if (Component2 is TFieldSpec)
and (TDomainSpec(TFieldSpec(Component2).DomainSpec).DataTypeId<>DataTypeId_Blob)
and (TDomainSpec(TFieldSpec(Component2).DomainSpec).DataTypeId<>DataTypeId_WideMemo)) then
您的第一个任务是按照我建议的思路,以一种理智的方式重新编写代码
然后是实际的错误。您有一个读取地址为$00000040的访问冲突。这是试图取消引用空指针的标志。很明显这里有些东西是零。我不知道。但调试器会告诉您这一点。确保将其配置为在引发异常时中断。这是IDE调试器选项中的一个设置
很可能有一个FindComponent调用返回nil。或者也许DomainSpec是零。您可能需要将单个if语句分解为多个if语句,以便更容易调试
我的最后一点是重复我最初的建议。这个代码是行不通的。立即将其重新分解为一个合理的形式。可能是世界上最长的代码行吗?不可能调试这样一行代码。正如David所建议的,将其分成多行,缩小搜索范围,以准确找出导致A/V的原因。真正的原因是DomainsSpec为零。原因与创建适当对象的问题有关。你不知道对问题的回答是什么?
if (Component2 is TFieldSpec)
and (TDomainSpec(TFieldSpec(Component2).DomainSpec).DataTypeId<>DataTypeId_Blob)
and (TDomainSpec(TFieldSpec(Component2).DomainSpec).DataTypeId<>DataTypeId_WideMemo)) then