Access Violation when assigning component property on Data Module - delphi

I'm on Delphi 2009, and my application contains a data module, which has a custom component named 'Globals' on it.
In another form in the application, I'm trying to change a published property (a string) on the Globals component:
dm.Globals.qhProject := _ProjectName.Text; //always gives access violation
The _ProjectName control is a TLabeledEdit descendant. I always get an access violation here if there's any text in the box.
However, if I manually assing a string to the property, I don't get the AV:
dm.Globals.qhProject := 'some text'; //works
Here's the declaration of the qhProject property:
FqhProject: string;
property qhProject: string read FqhProject write FqhProject;
I can't figure out why there's an AV here at all. I've tried moving the auto create order of the forms/data module around, but I always get the AV.
What am I doing wrong here?
Update:
I'm using Billenium Effects TFormContainer to switch between different forms in the application. Both forms that are involved here are in the form container. One form, TdlgSummary, contains the following:
procedure TdlgSummary.SyncVars;
begin
dm.Globals.qhProject := _ProjectName.Text
end;
The other form, TdlgFinalize, contains the following:
dlgSummary.SyncVars;
If I run SyncVars inside of dlgSummary, it works fine. If I call it from dlgFinalize, I get the AV. This seems to be the crux of the problem, but I can't figure out what's going wrong. Even if I switch control to dlgFinalize, dlgSummary hasn't been destroyed, because I can go back to it. Any ideas?

Looks to me like _ProjectName is nil. Try putting a breakpoint at this line and examine _ProjectName, see if it gives a valid reference or not.

Related

Delphi Bookmark Error: E2003 Undeclared identifier 'TBookmark'

Hey I wanted to use a TBookmark as a varialbe in my Form. I got it running in another Form and it is working there.
But in the new Form I get the Error.. I guess I have to include something in the uses statement but I cant remember what it was. Here is the code TBookmark is underlined in red so thats where the error sits.
procedure TForm4.FormCreate(Sender: TObject);
var test : string;
var selectedRow, rows : TBookmark;
begin
rows := Form1.DBGrid1.DataSource.DataSet.GetBookmark;
Form1.DBGrid1.SelectedRows.CurrentRowSelected := True;
Form1.DBGrid1.DataSource.DataSet.GotoBookmark(rows);
test := Form1.DBGrid1.DataSource.DataSet.FieldByName('name').AsString;
ShowMessage(test);
end;
end.
Your Form4 needs to Use the DB unit, because that's where TBookMark is declared.
Btw, what is in Form1's unit is irrelevant to this. The only relevant thing is that Form4's unit has to Use DB. What happens is that when the compiler tries to compile your Form4 unit, it needs to be able to find the definition of TBookMark, and that is in the standard DB.Pas unit along with lots of other dataset-related stuff. The same is true of any other identifier (or its class) that the compiler encounters in your project's source code.
99% of problems like this can be solved by doing a "Search | Find in Files" through Dephi's source code folders (and your project's folder if it's one of yours) to identify where the "undeclared" or missing item is declared.
Update So, you've got this code, which I'll assume is in your uForm4.Pas unit.
procedure TForm4.FormCreate(Sender: TObject);
var
test : string;
var
selectedRow, rows : TBookmark;
begin
rows := Form1.DBGrid1.DataSource.DataSet.GetBookmark;
Form1.DBGrid1.SelectedRows.CurrentRowSelected := True;
Form1.DBGrid1.DataSource.DataSet.GotoBookmark(rows);
test := Form1.DBGrid1.DataSource.DataSet.FieldByName('name').AsString;
ShowMessage(test);
end;
You want to be able to do something with the Name value that's shown in the current row of
DBGrid1 on Form1. There's nothing particularly wrong with the way you've done it, just that
it's long-winded, error-prone and invites problems like the one you've having with
TBookMark.
The point is that somewhere in your project, maybe in your uForm1.Pas unit, you know,
I don't, there must be a TDataSet-descendant (like TFDQuery, TAdoQuery or TTable) that is
specified in the DataSet property of Form1's DataSource1. For the sake of argument, lets'
say that the dataset component is FDQuery1 on Form1 and you want to get the Name field value
from the current row in DBGrid1.
To get that Name value, you don't actually need the bookmarks your code is using. The way
a TDBGrid works, the currently-selected row in the grid is always the current row in the
dataset component. So you could simply write
procedure TForm4.FormCreate(Sender: TObject);
var
test : string;
begin
test := Form1.FDQuery1.FieldByName('name').AsString;
ShowMessage(test);
end;
because you don't need to go through the rigmarole of Form1.DBGrid1.DataSource.DataSet to get to it.
Now, to explain another little mystery, how come your code would work fine if it was in uForm1.Pas
but you get the Undeclared Identifier: TBookMark error why you try the same code in uForm4.Pas
unit? Well, if you've ever watched the top of a source code file as it's being saved, you'll notice that
Delphi automatically adds, to the Uses list at the top, the units which contain any of the
components you've added to the form since its last save. So adding a TDataSource to the form would add
the DB unit to the Uses list, because that's where TDataSource is declared and so is TBookMark. Which
is why Delphi could compile Form1's code without the error, whereas when you try to mention a TBookMark
to uForm4, you need to add it to the unit's Uses list unless you add a component (like TDataSource)
to Form4 which will cause it to automatically add DB to the Uses list if it isn't already there. Mystery
solved.

Access violation adding a value in TChart Delphi component

I'm trying to use TChart component to export a graph to a bitmap file, but i got to a very odd error.
Everytime i try adding a value to the chart, i call the AddY function from the TLineSeries component passing the value as a parameter. When i try adding small values, the graph behaves completely normal as shown:
The problem happens when i try adding some big value at it's first point, i get an access violation like this:
Project Project1.exe raised exception class EAccessViolation with message 'Access violation at address 00450047 in module 'Project1.exe'. Write of address 022AC000'. Process stopped. Used Step or Run to continue.
And the callstack is completely empty, the only line there is the name of my project, and the highlighted line is the "end" of my dpr file.
As i keep pressing ok other erros pops up:
As i'm not skilled enough with those errors, i didn't manage to debug exactly what's going on, i presume its some sorte of corrupted heap, but i can't seem to find out where, since the code is so simple and the component has it's code hidden because it's a third party component.
The funny part is that if i just click ok until the errors are gone and add another value, it shows normally, as well as adding some small value first, and then a big value (by big i don't know exactly the number, but 2000+ starts happening this)
I isolated the TChart from my main software and build a snippet just to test things out, and here's the simple code i'm running:
procedure TdesktopForm.Button1Click(Sender: TObject);
var
vBMP: TBitmap;
begin
vBMP := TBitmap.Create();
try
config();
c.series[0].AddY(StrToFloat(edit.text));
c.PaintTo(vBMP.Canvas.Handle, 0, 0);
vBMP.SaveToFile('D:\test.bmp');
finally
vBMP.Free();
end;
end;
Where c is my visually added TChart component, edit is just a visual TEdit to manipulate what i'm adding and config is a method to configure visual stuff on the graphic with the following code:
procedure TdesktopForm.config();
begin
c.Height:=200;
c.Width:=200;
c.LeftAxis.LabelsFont.Size:=13;
c.BottomAxis.LabelsFont.Size:=13;
c.MarginBottom:=20;
c.MarginTop:=10;
c.LeftAxis.StartPosition:=10;
c.LeftAxis.EndPosition:=90;
c.BottomAxis.LabelsAngle:=0;
c.BottomAxis.Grid.Color:=clBlack;
c.LeftAxis.Grid.Color:=clBlack;
c.BottomAxis.Ticks.Color:=clBlack;
c.LeftAxis.Ticks.Color:=clBlack;
c.LeftAxis.MinorTicks.Color:=clBlack;
c.BottomAxis.MinorTicks.Color:=clBlack;
c.BottomAxis.LabelsMultiLine:=True;
c.BottomAxis.DateTimeFormat:='DD/MM/AAAA hh:mm:ss';
c.BottomAxis.StartPosition:=10;
c.BottomAxis.EndPosition:=90;
c.View3D:=False;
c.Color:= clWhite;
c.Legend.Visible:=False;
c.Series[0].Marks.Visible:=true;
c.Series[0].Marks.Transparent:=false;
c.Series[0].Marks.Style:= smsValue;
c.Series[0].Marks.Frame.Visible:=True;
c.Series[0].Marks.Frame.Color:=clBlack;
c.Series[0].Marks.BackColor:=clWhite;
c.Series[0].Marks.Font.Size:=12;
c.Series[0].Marks.Font.Color:=clBlack;
end;
If it wasn't strangely enough, all of the tests above was using the "Line series", if i try the same thing with Bar series for example, everything works completely normal, i tried adding some absurd values like 999999999 and no errors were raised.
All of the above was using Delphi 5, as my main software is built on Delphi 5.
Does anyone have an idea of what's going on?

Getting errors creating ChromiumOSR programmatically

I'm trying to create ChromiumOSR programmatically but I keep getting an error (access violation).
Here is sample code that causes the problem:
var
pChromiumOSR: TChromiumOSR;
begin
pChromiumOSR := TChromiumOSR.Create(Self);
pChromiumOSR.OnLoadEnd := pChromiumOSRLoadEnd;
pChromiumOSR.Browser.MainFrame.LoadUrl('www.google.com');
end;
The problem is that pChromiumOSR.Browser.MainFrame is always nil. If I do
pChromiumOSR.load('www.google.com'); I don't get any errors but it doesn't fire the onLoadend.
Can anyone give me any suggestions on what I might be doing wrong?
I'm using Delphi XE2 but not sure which version of chromium (where can I find the version?)
Your attempt to use Load method for loading a page was correct. The other one was wrong and failed because the Browser instance was not created. It's because the TChromiumOSR was designed to be a design time component rather than to be created dynamically.
Now, the only place where the Browser instance is created is the Loaded method, which is called for a component after its parent form is loaded from a stream. And since you are creating it dynamically, the Browser instance is never created.
For some reason also the CreateBrowser method (which creates the Browser instance) is declared as private, which complicates its calling a bit (unless you decide to modify the source and make it public). If you don't want to change your DCEF source code, you can use a class helper to provide access to the CreateBrowser method:
uses
ceflib, cefvcl;
type
TChromiumOSRHelper = class helper for TCustomChromiumOSR
public
procedure CreateBrowserInstance;
end;
implementation
{ TChromiumOSRHelper }
procedure TChromiumOSRHelper.CreateBrowserInstance;
begin
Self.CreateBrowser;
end;
Then to create a Browser instance add the CreateBrowserInstance call before the first accessing the Browser instance (which is here the Load method):
var
pChromiumOSR: TChromiumOSR;
begin
pChromiumOSR := TChromiumOSR.Create(Self);
pChromiumOSR.OnLoadEnd := pChromiumOSRLoadEnd;
pChromiumOSR.CreateBrowserInstance;
pChromiumOSR.Load('www.google.com');
end;

How to set THTTPRio.Converter.Options to soLiteralParams in OnBeforeExecuteEvent

This refer to the post Delphi SOAP Envelope and WCF.
Could someone please post a sample code which can show me how to set soLiteralParams in THTTPRio.Converter.Options in Delphi 7. I have the following code currently.
I have drag-dropped a HTTPRIO component into the document which has created a line HTTPRIO1: THTTPRIO at the beginning of the code. I basically want to understand how I set soLiteralParams in the above component. Following is the code I am trying to execute which is giving me error.
procedure TForm1.CleanUpSOAP(const MethodName: String; var SOAPRequest: WideString);
var RIO: THTTPRIO;
begin
//The following line is giving error
// RIO.Converter.options := [soLiteralParams];
end;
In the above code I have declared a variable RIO of the type THTTPRIO, which I am not sure is correct.
Just guessing, as you provide very little information in your question.
Use the variable assigned to the component you dropped on your form. Don't declare a new local one (which you never created anyway). To set the Converter.Options in code, you'll need to add OPToSOAPDomConv to your uses clause.
implementation
uses
OPToSOAPDomConv;
// BTW, this name might not be a good one if it's the
// OnBeforeExecute event handler as that isn't
// clear from the name.
procedure TForm1.CleanUpSOAP(const MethodName: String; var SOAPRequest: WideString);
begin
// Note this clears any previous options!
HTTPRIO1.Converter.Options := [soLiteralParams];
// If you want to keep the previous options instead of replacing them
// HTTPRIO1.Converter1.Options := HTTPRIO1.Converter1.Options + [soLiteralParams];
end;
If you've dropped the component on the form, I'm not sure why you're not handling this in the Object Inspector instead, however.
If this doesn't solve the problem, edit your question and provide the exact error message you're receiving, including any memory addresses in the case of an exception being raised.
I have cracked this. The issue was that I didn't refer to OPconvert.pas file, which contained the TSOAPConvertOption enumeration. I don't know whether copying this file into the same folder as my project files and referring to this in the "uses" section is the right way, but it worked fine.

AV When using a Procedure from one Component called by another

Im not sure if i have explaned this the best i can but, here we go...
I have 2 Custom components on a form, Which are link together at design time through the IDE. Whenever i call a procedure from on of the Component i get the Access violation,
Access violation at address 0049A614
in module 'Project2.exe'. Read of
address 00000034.
This is a small section of my code
TMyClient = class(TClientSocket)
{...}
end;
and...
TPresence = class(TComponent)
private
ftheClient: TMyClient
public
procedure SetStatus(status: string);
published
property UserName : string read fUserName write fUserName;
property theClient: TMyClient read ftheClient write ftheClient;
end;
procedure TPresence.SetStatus(status: string);
begin
try
***** if theClient = nil then
Exception.Create('theClient is Nil');
except
on e:Exception do
MessageDlg(e.classname+', '+e.message, mtWarning, [mbOK], 0);
end;
{...}
end;
0049A614 is at the *****, and the IDE stops here.
I Have also tried to do the assign at run time with
Presence1.theClient := MyClient1;
with no luck
using procedures from Presence1 or MyClient1 that do not rely on each other work fine.
Delphi 7
Follow Up:
from mghie comments, i rethought about it.
I removed the TPresence Component from the form (which caused some strange IDE errors, that might have had something to do with it) and created it design time, assigning everything that was needed. Now it works, but putting the TPresence Component back on the from brings the error back.
Thankyou for your help guys, i should be able to work this one out now, if i can't ill reopen another question :)
You seem to be thinking that the exception is raised because the client field of Presence1 is not set - if you do however get the exception "Read of address 00000034" it means that the Self pointer in the SetStatus() call is nil. That would indicate that you call SetStatus() on an unassigned TPresence reference. It is not really possible to tell the reason for that from the snippet you posted, but it should get you started debugging.
I would still advise you to write a proper setter method for all component references in your own custom components - first because you have a better hook when debugging such problems (you can set a breakpoint there), and second because you should always call TComponent.FreeNotification() on such linked components to be able to track their destruction and set the internal reference to nil.
We probably need more of your code. It is possible you are not correctly creating an instance of TPresence which would give you the error you are experiencing. Try to give us a simple as possible code snippet that causes your error.

Resources