Delphi: getting access violation error at run-time

0

I'm pretty new to Delphi and am attempting to use different units to store TLists and TObjects, as well as generate other combobox options based on previous combobox selections. I am receiving the following error messages immediately after running:

Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x004087d7: read of address 0x00000000

Access violation at address 00408813 in module 'Project1.exe'. Read of address 00000000.

I've traced through the steps in the debugging tool but I can't see why it won't work. I have googled the issue and have found a few solutions but nothing that seems like it applies to my current problem.

unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TfMain = class(TForm)
    lCPU: TLabel;
    cbCPU: TComboBox;
    lGPU: TLabel;
    cbGPU: TComboBox;
    lMotherboard: TLabel;
    cbMotherboard: TComboBox;
    lRAM: TLabel;
    cbRAM: TComboBox;
    eCompatible: TEdit;
    lCompatible: TLabel;
    eCost: TEdit;
    lCost: TLabel;
    Label11: TLabel;
    lbCPU: TListBox;
    lbMotherboard: TListBox;
    lbGPU: TListBox;
    lbRAM: TListBox;
    procedure FormShow(Sender: TObject);
    procedure cbCPUChange(Sender: TObject);
  private
    { Private declarations }
  public
//    procedure cbCPUpopulate();
  end;

  type TGPU = class(TObject)
    public
      name : string;
      vram : integer;
      clock : integer;
      price : string;
  end;

  type TCPU = class(TObject)
    public
      name : string;
      cores : integer;
      clock : real;
      intel : boolean;
      amd : boolean;
      price : string;
  end;

  type TMobo = class(TObject)
    public
      name : string;
      intel : boolean;
      amd : boolean;
      price : string;
  end;

  type TRAM = class(TObject)
    public
      name : string;
      memory : integer;
      clock : integer;
      price : string;
  end;

var
  fMain: TfMain;

implementation

{$R *.dfm}

uses CPUs, GPUs, Motherboards;

procedure TfMain.cbCPUChange(Sender: TObject);
var
i : integer;
mobo : TMobo;
begin
  if TCPU(fMain.cbCPU.ItemIndex).intel = true then begin
    for i := 0 to Motherboards.MoboPartsList.Count-1 do begin
      mobo := TMobo(Motherboards.MoboPartsList.Items[i]);
      if mobo.intel = true then begin
        fMain.cbMotherboard.Items.AddObject(mobo.name, mobo);
      end;
    end;
  end;
end;

procedure cbCPUpopulate();
var
i : integer;
CPU : TCPU;
begin
  for i := 0 to CPUs.CPUPartsList.Count-1 do begin
    CPU := TCPU(CPUs.CPUPartsList.Items[i]);
    fMain.cbCPU.Items.AddObject(CPU.name, CPU);
  end;
end;

procedure TfMain.FormShow(Sender: TObject);
begin
  Motherboards.MakeMoboList;
  CPUs.MakeCPUList();
  GPUs.popgpulist();
  cbCPUpopulate;
end;

end.
delphi
access-violation
asked on Stack Overflow Nov 10, 2020 by John Weiland • edited Nov 11, 2020 by CognitiveRobot

1 Answer

5

In cbCPUChange(), you are accessing the TCPU objects incorrectly.

The expression TCPU(fMain.cbCPU.ItemIndex) is type-casting a list index into an object pointer. You need to instead use the ItemIndex to access the ComboBox's Objects[] property, which is filled with TCPU objects by cbCPUpopulate().

Also, there is no need to use the fMain global variable from inside a method of the TfMain class. Use the method's implicit Self pointer instead.

Try something more like this:

procedure TfMain.cbCPUChange(Sender: TObject);
var
  i : integer;
  mobo : TMobo;
begin
  cbMotherboard.Items.BeginUpdate;
  try
    cbMotherboard.Items.Clear;
    i := cbCPU.ItemIndex;
    if i < 0 then Exit;
    if TCPU(cbCPU.Items.Objects[i]).intel then begin
      for i := 0 to Motherboards.MoboPartsList.Count-1 do begin
        mobo := TMobo(Motherboards.MoboPartsList.Items[i]);
        if mobo.intel then begin
          cbMotherboard.Items.AddObject(mobo.name, mobo);
        end;
      end;
    end;
  finally
    cbMotherboard.Items.EndUpdate;
  end;
end;

On a side note, the declarations of the TCPU, TMobo, and TRAM types do not belong in the MainForm unit. They should be declared in the other units that are actually creating object lists of those types, eg: TCPU in the CPUs unit, TMobo in the Motherboards unit, etc:

unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TfMain = class(TForm)
    lCPU: TLabel;
    cbCPU: TComboBox;
    lGPU: TLabel;
    cbGPU: TComboBox;
    lMotherboard: TLabel;
    cbMotherboard: TComboBox;
    lRAM: TLabel;
    cbRAM: TComboBox;
    eCompatible: TEdit;
    lCompatible: TLabel;
    eCost: TEdit;
    lCost: TLabel;
    Label11: TLabel;
    lbCPU: TListBox;
    lbMotherboard: TListBox;
    lbGPU: TListBox;
    lbRAM: TListBox;
    procedure FormShow(Sender: TObject);
    procedure cbCPUChange(Sender: TObject);
  private
    { Private declarations }
    procedure cbCPUpopulate;
  public
  end;

var
  fMain: TfMain;

implementation

{$R *.dfm}

uses
  CPUs, GPUs, Motherboards;

procedure TfMain.cbCPUChange(Sender: TObject);
var
  i : integer;
  mobo : Motherboards.TMobo;
begin
  cbMotherboard.Items.BeginUpdate;
  try
    cbMotherboard.Items.Clear;
    i := cbCPU.ItemIndex;
    if i < 0 then Exit;
    if CPUs.TCPU(cbCPU.Items.Objects[i]).intel then begin
      for i := 0 to Motherboards.MoboPartsList.Count-1 do begin
        mobo := Motherboards.TMobo(Motherboards.MoboPartsList.Items[i]);
        if mobo.intel then begin
          cbMotherboard.Items.AddObject(mobo.name, mobo);
        end;
      end;
    end;
  finally
    cbMotherboard.Items.EndUpdate;
  end;
end;

procedure TfMain.cbCPUpopulate;
var
  i : integer;
  CPU : CPUs.TCPU;
begin
  for i := 0 to CPUs.CPUPartsList.Count-1 do begin
    CPU := CPUs.TCPU(CPUs.CPUPartsList.Items[i]);
    cbCPU.Items.AddObject(CPU.name, CPU);
  end;
end;

procedure TfMain.FormShow(Sender: TObject);
begin
  Motherboards.MakeMoboList;
  CPUs.MakeCPUList;
  GPUs.popgpulist;
  cbCPUpopulate;
end;

end.
answered on Stack Overflow Nov 11, 2020 by Remy Lebeau • edited Nov 11, 2020 by Remy Lebeau

User contributions licensed under CC BY-SA 3.0