I have a major problem and I have no idea how it might be corrected. Out of the blue, when I compile then try to run my application - which I have been working on for six months - I get a Class Not Registered error. I also have a pop-up error message saying that dbx.dbl was not found. I have added nothing to the program in the past few days which included any new classes. I am using Delphi 5. I do not know how to identify which class is not registered. The program will not run and I have spent hours trying to track down the problem without success.
More information: I have moved the executable and data files to another computer, and it all runs fine. So it seems to be a problem with my development box.
More Information: I did as fpiette suggested but found nothing which helped. So I created a very basic application:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Db, ADODB;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ADOConnection1.Connected := True;
ADOQuery1.Close;
ADOQuery1.Connection := ADOConnection1;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('select * from tblsupplier');
ADOQuery1.Open;
end;
end.
The Class Not Registered error occurs when it executes the ADOQuery1.Open; line.
Am I right in assuming that since there are no other components in the program that the error must be in the ADO code? The ADOConnection1 points at an Access database called Suppliers and the connection test was successful.
Related
The following code works just fine, but it shouldn't ! When I click the Button1, the object is destroyed first, and then its Value is used and I don't receive any Access Violation or something... Even more, the multiply operation gives the correct result, that proves that Obj1 is not destroyed ! But then again, this is not true either, because when I close the program it does'n report any memory leakage. I'm very confused.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
MyObj = class(TObject)
Value: Cardinal;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
public
Obj1:MyObj;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Obj1.Free;
Obj1.Value:=Obj1.Value * 5;
Caption:=IntToStr(Obj1.Value);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ReportMemoryLeaksOnShutdown:=true;
Obj1:=MyObj.Create;
Obj1.Value:=10;
end;
end.
The object is destroyed. The memory is returned to the memory manager. What happens next is out of your control. The memory could be returned to the system. In which case you'd see a runtime error. Or, the memory could be kept alive by the memory manager ready to reuse the next time the program asks for a block of that size. This is what happens here.
Your program exhibits undefined behaviour. Anything could happen, including the program appearing to work. Obviously the program is wrong and you must not access objects after they have been destroyed.
If you use the full debug version of FastMM then you should see an error because in that scenario steps are taken to detect access after free. That's a useful debugging tool.
I have an object that is created on Form1 and I would like to be able to access one of its fields on Form2. I have tried to google it and nobody can give an answer that I can understand. Please excuse me but I am a novice.
Form1
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
Ttest=class
public
sName:string;
end;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
myObj:Ttest;
begin
myObj.Create;
myObj.sName := 'Name';
Form2.Show;
end;
end.
Form2
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm2 = class(TForm)
Button2: TButton;
procedure Button2Click(Sender: TObject);
end;
var
Form2: TForm2;
implementation
uses Unit1;
{$R *.dfm}
procedure TForm2.Button2Click(Sender: TObject);
begin
ShowMessage(myObj.sName);//This is not working
end;
end.
You have two forms that both use an object. You should define the object in a separate unit and list it in the Uses clause in the Interface section of both forms. Try using something already defined in a main library, like TStringlist, so you don't get confused with this part.
From what you're showing here, you're attempting to create an instance of that object in one form and do something with it in another form. That's a common thing to do: you may have one unit that asks for a filename and loads a file into a TStringList, then hands that over to another form or unit to deal with.
The way you're doing it, however, can be improved to reduce coupling between the two forms.
What you want to do is define a property like this in TForm2:
TForm2 = class( TForm )
. . .
private
Ftestobj : TTest; // or TStringlist
public
property testobj : TTest read Ftestobj write Ftestobj;
Then in TForm1.OnButtonClick do something like this:
form2.testobj := myobj;
form2.Show;
And then this becomes:
procedure TForm2.Button2Click(Sender: TObject);
begin
ShowMessage(Ftestobj.sName);
end;
I did a whole session in CodeRage 9 on this topic recently, in fact. It's entitled, "Have you embraced your inner plumber yet?" and it's all about moving data in and out of forms like this. (I call it plumbing code.)
Search for "coderage 9" and watch the video. At the end is a link where you can download my example code. That should keep you busy for a while. :)
Another continuation of my previous question here.
In my previous question the project would not run and I was told that the DLL's that come with the component were simply in the wrong place. I moved them to the areas suggested (The output folder of the project I was working on) and the project did indeed run. However, a new error quickly revealed itself, as soon as TChromium attempts to navigate to any webpage, either through the defaulturl property or by use of the LoadURL procedure, the program throws a memory exception.
In particular the error notice says:
Debugger Fault Notification
Project faulted with message 'access violation at 0x00000000; read of address 0x00000000'
This particular error occurs on the end statement of the procedure that attempts to navigate.
To me this says that something is not being initialized properly, but this is simply a test project with nothing but a TChromium component and a TButton to navigate to 'http://www.google.com' on the form.
Source:
unit Test2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, cefvcl;
type
TForm1 = class(TForm)
Chromium1: TChromium;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Chromium1.Browser.getmainframe.LoadUrl('http://www.google.com');
end;
end.
Considering I can see no forum posts, or questions of this nature on this website I can only assume this is an isolated problem, probably caused by something I myself have done wrong, but for the life of me I cannot think what.
So my question is, does anyone know what is causing this error and have I simply made my project wrong?
I've downloaded free DBX driver from here.
I am trying to make it work since two days now, without success.
Here is the snapshot of my code:
unit uMainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SqlExpr, WideStrings, DBXDynalink, DB;
type
TMainForm = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.Button1Click(Sender: TObject);
var C: TSQLConnection;
begin
C := TSQLConnection.Create(Self);
try
C.DriverName := 'FirebirdConnection';
C.LibraryName := 'dbxfb4d12.dll';
C.VendorLib := 'fbclient.dll';
C.GetDriverFunc := 'getSQLDriverFIREBIRD';
C.Params.Add('User_Name=SYSDBA');
C.Params.Add('Password=masterkey');
C.Params.Add('Database=C:\MyDB.fdb');
C.Open;
if C.Connected then
ShowMessage('Connection is active')
finally
C.Free;
end;
end;
After running the test I am receiving error: "Unable to load fbclient.dll(ErrorCode 22). It may be missing from the system path."
I have required libraries in my application path, I have them even in the System32 path. I am not using dbxdrivers.ini and dbxconnections.ini.
So what is going on here? I have Delphi 2009 with latest updates.
Thanks for your time.
Did you also try to put the fbclient.dll file in the same folder as the executable?
Sometimes it's necessary to have the fbclient.dll renamed to gds32.dll. It might do the trick.
How do i run TestCase's from the IDE?
i created a new project, with a single, simple, form:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
private
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
end.
Now i'll add a test case to check that pushing Button1 does what it should:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses
TestFramework;
type
TForm1Tests = class(TTestCase)
private
f: TForm1;
protected
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestButton1Click;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
//todo
end;
{ TForm1Tests }
procedure TForm1Tests.SetUp;
begin
inherited;
f := TForm1.Create(nil);
end;
procedure TForm1Tests.TearDown;
begin
f.Free;
inherited;
end;
procedure TForm1Tests.TestButton1Click;
begin
f.Button1Click(nil);
Self.CheckEqualsString('Hello, world!', f.Caption);
end;
end.
Given what i've done (test code in the GUI project), how do i now trigger a run of the tests? If i push F9 then the form simply appears:
Ideally there would be a button, or menu option, in the IDE saying Run DUnit Tests:
Am i living in a dream-world? A fantasy land, living in a gumdrop house on lollipop lane?
Adding a TestCase to the main project is not the way to go. You should create a separate TestProject (you can have it in the same ProjectGroup as the main project), add a TestCase and run.
I agree with Uwe Raabe, but sometimes it can be useful to have a 'hidden' link within your app to run the DUnit GUI. I use:
TGUITestRunner.runRegisteredTests;
Call this from your button at the DUnit GUI will open for you to manually run and view test output.
For example, if you hold down a special key combination when opening the software's own "Control Panel", you get some advanced entries:
I like the idea of having a 'Run DUnit tests' command in the IDE.
It could be implemented by checking for a DUnit project in the same folder, having the same name as the current project:
Project1.dpr -> the software under test
Project1.Tests.dpr => the DUnit test app
In this case, the IDE should enable the Run DUnit tests command.
After executing the tests, a list of all failed tests should be displayed which allows to jump to the source line where a test failed.
If tests caused memory leaks, a list of all leaks should be displayed which allows to jump to the source line where the memory leak has been created
(DUnit can be configured to detect memory leaks and fail tests when one has been found)