Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Private variables cause exceptions, how to use RegisterClass?

Status
Not open for further replies.

crockeea

Programmer
Feb 9, 2010
3
US
I'm pretty new to Delphi, and I'm not very clear about how classes work yet in Delphi.

Here is my code:
Code:
unit DatabaseForm;

interface

uses
  SysUtils, Forms, Dialogs, Classes, ACRMain, Db, Utility;

type
   TDBForm = class(TForm)
   private
     { Private declarations }
     SSA_Database: TACRDatabase;
     function  CreateDatabase(): Integer;
  end;

var
  DBForm: TDBForm;

implementation
{$R *.DFM}

function TDBForm.CreateDatabase(): Integer;
Begin
   SSA_Database.CreateDatabase();
   CreateDatabase := 1;
end;

initialization
   RegisterClass(TACRDatabase);
end.

I want to encapsulate SSA_Database and make it private. It is published by default (since this is a form), and if I leave SSA_Database as published or public, it works fine. When I make it private, however (WITHOUT the initialization section) I get the following RUNTIME error:

Exception EClassNotFound in module Project1.exe at <address>. Class TACRDatabase not found.

After some searching, I found some suggestions that I need to add the initialization section with the RegisterClass(TACRDatabase) call.

This results in the following RUNTIME error:
Exception EAccessViolation in module Project1.exe at <address>.
Access Violation at address <address> in module 'Project1.exe'. Read of address <address near 0>

I really don't know what the RegisterClass call accomplishes or why I need it, but I'm apparently doing it wrong.

Thanks for any help!
 
no need for registerclass().

Code:
 type
  TMyObject = class(TObject)
    procedure DoSomething; 
  end;

...
procedure SomeForm.UseMyObject;

var MyObject : TMyObject;

begin
 MyObject := TMyObject.Create;
 try
  MyObject.DoSomething;
 finally
  FreeAndNil(MyObject); 
 end;
end;

so in your case:

 SSA_Database := TACRDatabase.Create; 
 SSA_Database.CreateDatabase;

for a correct answer, we need to see the interface of TACRDatabase.

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Some sidenotes,

-what language are you used to write in? (so I can give you some pointers in the right direction)
- parameterless functions or procedures don't have to be stated with empty parenthesis

so a small rewrite of your code:

Code:
unit DatabaseForm;

interface

uses  SysUtils, Forms, Dialogs, Classes, ACRMain, Db, Utility;

type   
  TDBForm = class(TForm)   
  private     
  { Private declarations }  
   SSA_Database: TACRDatabase; 
   function  CreateDatabase: boolean;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
  end;

var  DBForm: TDBForm;

implementation

{$R *.DFM}

function TDBForm.CreateDatabase: Boolean;

begin   
 SSA_Database := TACRDatabase.Create; // create our object 
 Result := SSA_Database.CreateDatabase; // do something with the object, I assume here that SSA_Database.CreateDatabase returns a boolean  
end;

procedure TDBForm.FormCreate(Sender: TObject);
begin
 // this procedure is automatically called at form creation, best used to create objects that have the same lifecycle as your form
 if not CreateDatabase then
  ShowMessage('database error!');
end;

procedure TDBForm.FormDestroy(Sender: TObject);
begin
 // this procedure is automatically called at form destruction, ideal for cleaning up our objects
 if Assigned(SSA_Database) then
  FreeAndNil(SSA_Database);
end;

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Thanks for your response. I'm used to coding in Java or C. I'm trying to imitate a Java private variable (I think it is the same in Delphi).

I had to make a few changes to your code to make it compile.

Code:
unit DatabaseForm2;

interface

uses  SysUtils, Forms, Dialogs, Classes, ACRMain, Db, Utility;

type
  TTestForm = class(TForm)
  //had to make FormCreate published, otherwise I got a "EReadError, Invalid Property Value TestForm.OnCreate'
  procedure FormCreate(Sender: TObject);    
  private     
  { Private declarations }
   SSA_Database: TACRDatabase;
   function  CreateDatabase: boolean;
   
   procedure FormDestroy(Sender: TObject);
  end;

var  TestForm: TTestForm;

implementation

{$R *.DFM}

function TTestForm.CreateDatabase: Boolean;

begin   
 SSA_Database := TACRDatabase.Create(TestForm); // create our object (it takes its container)
 if SSA_Database.exists then //another form creates the DB, we'll just use it here for test purposes to make it break
        MessageDlg('Success!', mtInformation, [mbOk], 0);
 Result := true;
end;

procedure TTestForm.FormCreate(Sender: TObject);
begin
 // this procedure is automatically called at form creation, best used to create objects that have the same lifecycle as your form
 if not CreateDatabase then
  ShowMessage('database error!');
end;

procedure TTestForm.FormDestroy(Sender: TObject);
begin
 // this procedure is automatically called at form destruction, ideal for cleaning up our objects
 if Assigned(SSA_Database) then
  FreeAndNil(SSA_Database);
end;
end.

This is essentially the code you gave me with some minor modifications, and it compiles fine, but instantly gives the same runtime error. The error occurs when the 'Project' file creates the form (it calls
Code:
 Application.CreateForm(TTestForm, TestForm);
I tried to put breakpoints in FormCreate (our procedure) but it never gets there, it breaks before that.

Again, if I simply move SSA_Database outside the private var section, it compiles just fine. I used EXACTLY the code above.

Here are a couple more pieces of info that may or may not be helpful:
I'm using Delphi 5
The SSA_Database object is on my form (in the GUI), and I set a few of its properties via the GUI.


I'm getting the idea that private variables aren't created automatically, whereas published/public variables are. I don't have to explicitly create my SSA_Database if I make it published.

Also not sure why I had to make FormCreate non-private...

Thanks

 
Hi,

I think you really should read a delphi book to get you up to speed.

some things:

- FormCreate/FormDestroy are in fact events of the form, so go into the object inspector (the place where your set for example the caption of the form)
go to the events tab an doubleclick the onDestroy and on Create events and the FormCreate/FormDestroy code blocks are placed, any designer related element or event is placed above the private/protected/public statements.

- so SSA_database is a component on the form?, this means that it will be automatically created for you, so no need to create/destroy it on the fly like I showed you, the form will handle that for you.

I don't know the TACRxxxx components but It seems you have an issue somewhere. can you show me the original code (.pas file and .dfm file)

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
I know about FormCreate and FormDestory, when I add them via the form, the stubs are generated as "published", not private. They work fine when visibility is published, but I get a runtime error if FormCreate is private (as in your code).

Unfortunately, I don't have the source for the ACR library, all I know is everything works fine when it isn't private.

Thanks for your help.
 
The first thing to consider is that in Delphi you do not have to 'create' the entire structure of your application.
The IDE will do that for you.

Are you trying to create your 'main' form programmatically (as you would have to in Java?)





Steve: N.M.N.F.
If something is popular, it must be wrong: Mark Twain
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top