Access Violation when handling forms - delphi

I have procedure to show/hide one element on TForm like that:
procedure ShowHideControl(const ParentForm: TForm; const ControlName: String; ShowControl: Boolean);
var
i: Integer;
begin
for i := 0 to pred(ParentForm.ComponentCount) do
begin
if (ParentForm.Components[i].Name = ControlName) then
begin
if ShowControl then
TControl(ParentForm.Components[i]).Show
else
TControl(ParentForm.Components[i]).Hide;
Break;
end;
end;
end;
then I try to use it like:
procedure TForm1.Button6Click(Sender: TObject);
begin
ShowHideEveryControl(TForm(TForm1), 'Button4', True);
end;
Why do I get Access Violation on Button6 click?
For me everything is OK... Button4 exists as a child :)

This cast is wrong:
TForm(TForm1)
You are telling the compiler to ignore the fact that TForm1 is not a TForm instance, and asking it to pretend that it is. That is fine until you actually try to use it as an instance, and then the error occurs.
You need to pass a real instance to a TForm descendent. You can write it like this:
ShowHideEveryThing(Self, 'Button4', True);
Just in case you are not clear on this, the parameter of your procedure is of type TForm. That means you need to supply an instance of a class that either is, or derives from TForm. I repeat, you must supply an instance. But you supply TForm1 which is a class.
And then the next problem comes here:
if (ParentForm.Components[i].Name = FormName) then
begin
if ShowForm then
TForm(ParentForm.Components[i]).Show
else
TForm(ParentForm.Components[i]).Hide;
Break;
end;
Again you have used an erroneous cast. When the compiler tells you that it a particular object does not have a method, you must listen to it. It's no good telling the compiler to shut up and pretend that an object of one type is really an object of a different type. Your button is categorically not a form, so don't try to cast it to TForm.
It is very hard to know what you are actually trying to do here. When you write:
ShowHideEveryThing(Self, 'Button4', True);
It would seem to me to me more sensible to write:
Button4.Show;
It is not a good idea to refer to controls using their names represented as text. It is much safer and cleaner to refer to them using reference variables. That way you let the compiler do its job and check the type safety of your program.
The names used in your function are suspect:
procedure ShowHideEveryThing(const ParentForm: TForm; const FormName: String;
ShowForm: Boolean);
Let's look at them:
ShowHideEveryThing: but you claim that the function should show/hide one element. That does not tally with the use of everything.
FormName: you actually pass a component name, and then look for components owned by ParentForm that have that name. It seems that FormName is wrong.
ShowForm: again, do you want to control visibility of the form, or a single element?
Clearly you need to step back and be clear on the intent of this function.
As an aside, you should generally never need to write:
if b then
Control.Show
else
Control.Hide;
Instead you can write:
Control.Visible := b;
My number one piece of advice to you though is to stop casting until you understand it properly. Once you understand it properly, design your code if at all possible so that you don't need to cast. If you ever really do need to cast, make sure that your cast is valid, ideally by using a checked cast with the as operator. Or at least testing first with the is operator.
Your code shows all the hallmarks of a classic mistake. The compiler objects to the code that you write. You have learnt from somewhere that casting can be used to suppress these compiler errors and now you apply this technique widely as a means to make your program compile. The problem is that the compiler invariably knows what it is talking about. When it objects, listen to it. If ever you find yourself suppressing a compiler error with a cast, take a step back and think carefully about what you are doing. The compiler is your friend.

Related

Delphi Custom Component Knowing Which Referee Called A Method

I have created a custom component which has a property that the user can assign to another custom component..
TComp1 = class(TComponent)
public
property Comp2: TComp2 read GetComp2 write SetComp2;
property Something;
end;
TComp2 = class(TComponent)
public
procedure DoSomething;
end;
There could be multiple TComp1 components that assign the same TComp2. I need TComp2 to know which TComp1 called it because it needs to reference property "something" of that specific referee..
var
comp1a, comp1b: TComp1;
comp2: TComp2;
comp2 := TComp2.create;
comp1a := TComp1.create;
comp1b := TComp1.create;
comp1a.comp2 := comp2;
comp1b.comp2 := comp2;
comp1b.comp2.dosomething; <-- needs to know this was from comp1b not comp1a
obviously, the code above is just to illustrate my point and is not including the notification mechanisms that I have to put in place, etc.
so far, I have considered using the getter for TComp1.Comp2 to set an "activeComponent" property on the assigned TComp2 so that TComp2 can use that property to get the right component. While this should work, I believe it is unsafe and if someone tries to use comp2 directly or passes the reference to another variable entirely (comp := comp1a.comp2; comp.dosomething;), or tries to use it from multiple threads, there could be issues.
has anybody else encountered this issue? what is the best solution?
I hope somebody will be able to help :)
In the line:
comp1b.comp2.dosomething; <-- needs to know this was from comp1b not comp1a
The call to doSomething has absolutely no knowledge of comp1b. You should think of this as two separate lines of code:
LocalComp2 := comp1b.comp2;
LocalComp2.doSomething;
So as per David's comment, you need to pass the other component as a parameter. I.e.
comp1b.comp2.doSomething(comp1b);
This, by the way, is a stock-standard technique used throughout Delphi code. The best example is TNotifyEvent = procedure (Sender: TObject) of object; and is used in calls like:
ButtonClick(Self);
MenuItemClick(MainMenu);
You ask in a comment:
I have thought about that too but it seems somewhat redundant to effectively reference the same component twice.. comp1a.comp2.domsomething(comp1a); is there no better way?
As I said, the bit comp2.domsomething has no knowledge of the comp1a. just before it. So as far as the compiler is concerned it's not redundant. In fact it's also possible to call comp1a.comp2.domsomething(SomeOtherComponent).
However, that said, there is a better way.
Currently your code violates a princple called the Law of Demeter. Users of TComp1 are exposed to details abobut TComp2 even if they don't care about TComp2. This means that you can find yourself repeatedly writing:
comp1a.comp2.doSomething(comp1a);
comp1b.comp2.doSomething(comp1b);
comp1a.comp2.doSomething(comp1a);
comp1c.comp2.doSomething(comp1c);
To avoid that, fix the Law of Demeter violation by writing:
procedure TComp1.doSomething;
begin
comp2.doSomething(Self);
end;
Now your earlier lines become:
comp1a.doSomething;
comp1b.doSomething;
comp1a.doSomething;
comp1c.doSomething;
The obvious solution is to pass the extra information as a parameter. Like this:
comp1b.comp2.dosomething(comp1b);
Expecting comp2 to be able to work out whether it was referenced from comp1a or comp1b is unrealistic, and frankly would be an indication of a poor design.
Parameters are explicit and so demonstrate clear intent to the reader.

Why Delphi compiler can't see I'm trying to free an interface?

I've done a small mistake while coding this week-end.
In the following code, I'm creating an object and cast it to an interface. Later, I'm trying to free it with FreeAndNil();
type
IMyIntf = interface
[...]
end;
TMyClass = class(TInterfacedObject, IMyIntf)
[...]
end;
var
Myintf : IMyIntf;
begin
Myintf := TMyClass.Create;
[...] // Some process
FreeAndNil(Myintf); // CRASH !!!
end;
Of course, the program crash at this line.
I totally understand the issue, but what I don't understand is why the compiler doesn't warn me about it ? There is no dynamic things behind, it's just that I'm trying to free an interface !!! Why don't it write me an error / warning ?
Is there any real explanation behind or is it just a compiler limitation ?
As you know, the correct way to do this is to write Myintf := nil, or just to let it go out of scope. The question you ask is why the compiler accepts FreeAndNil(Myintf) and does not complain at compile time.
The declaration of FreeAndNil is
procedure FreeAndNil(var Obj);
This is an untyped parameter. Consequently it will accept anything. You passed an interface, but you could have passed an integer, a string and so on.
Why did the designers choose an untyped parameter? Well, they needed to use a var parameter since the whole purpose of FreeAndNil is to free the object and set the object reference to nil. That can't be done by a method of the target object and so a var parameter of a standalone function is needed.
You might imagine that you could write
procedure FreeAndNil(var Obj: TObject);
since all objects are descended from TObject. But this does not do the job. The reason being that the object you pass to a var parameters must be exactly the type of that parameter. If FreeAndNil was declared this way you would have to cast to TObject every time you called it.
So, the designers decided that the best solution to the design problem, the least bad choice, is to use the untyped var parameter.

How To Get the Name of the Current Procedure/Function in Delphi (As a String)

Is it possible to obtain the name of the current procedure/function as a string, within a procedure/function? I suppose there would be some "macro" that is expanded at compile-time.
My scenario is this: I have a lot of procedures that are given a record and they all need to start by checking the validity of the record, and so they pass the record to a "validator procedure". The validator procedure (the same one for all procedures) raises an exception if the record is invalid, and I want the message of the exception to include not the name of the validator procedure, but the name of the function/procedure that called the validator procedure (naturally).
That is, I have
procedure ValidateStruct(const Struct: TMyStruct; const Sender: string);
begin
if <StructIsInvalid> then
raise Exception.Create(Sender + ': Structure is invalid.');
end;
and then
procedure SomeProc1(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc1');
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProcN');
...
end;
It would be somewhat less error-prone if I instead could write something like
procedure SomeProc1(const Struct: TMyStruct);
begin
ValidateStruct(Struct, {$PROCNAME});
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
begin
ValidateStruct(Struct, {$PROCNAME});
...
end;
and then each time the compiler encounters a {$PROCNAME}, it simply replaces the "macro" with the name of the current function/procedure as a string literal.
Update
The problem with the first approach is that it is error-prone. For instance, it happens easily that you get it wrong due to copy-paste:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc1');
...
end;
or typos:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SoemProc3');
...
end;
or just temporary confusion:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SameProc3');
...
end;
We are doing something similar and only rely on a convention: putting a const SMethodName holding the function name at the very beginning.
Then all our routines follow the same template, and we use this const in Assert and other Exception raising.
Because of the proximity of the const with the routine name, there is little chance a typo or any discrepancy would stay there for long.
YMMV of course...
procedure SomeProc1(const Struct: TMyStruct);
const
SMethodName = 'SomeProc1';
begin
ValidateStruct(Struct, SMethodName);
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
const
SMethodName = 'SomeProcN';
begin
ValidateStruct(Struct, SMethodName);
...
end;
I think this is a duplicate of this question: How to get current method's name in Delphi 7?
The answer there is that to do so, you need some form of debug info in your project, and to use, for example, the JCL functions to extract information from it.
I'll add that I haven't used the new RTTI support in D2009/2010, but it wouldn't surprise me if there was something clever you could do with it. For example, this shows you how to list all methods of a class, and each method is represented by a TRttiMethod. That descends from TRttiNamedObject which has a Name property which "specifies the name of the reflected entity". I'm sure there must be a way to get a reference to where you currently are, ie the method that you're currently in. This is all guesswork, but try giving that a go!
No compile time macro, but if you include enough debug information you can use the callstack to find it out. See this same question.
Another way to achieve the effect is to enter source metadata into a special comment like
ValidateStruct(Struct, 'Blah'); // LOCAL_FUNCTION_NAME
And then run a third-party tool over your source in a pre-compile build event to find lines with "LOCAL_FUNCTION_NAME" in such a comment, and replace all string literals with the method name in which such code appears, so that e.g. the code becomes
ValidateStruct(Struct, 'SomeProc3'); // LOCAL_FUNCTION_NAME
if the code line is inside the "SomeProc3" method. It would not be difficult at all to write such a tool in Python, for example, and this text substitution done in Delphi would be easy enough too.
Having the substitution done automatically means you never have to worry about synchronization. For example, you can use refactoring tools to change your method names, and then your string literals will be automatically updated on the next compiler pass.
Something like a custom source pre-processor.
I gave this question a +1, this is a situation I have had numerous times before, especially for messages for assertion failures. I know the stack trace contains the data, but having the routine name inside the assertion message makes things that little bit easier, and doing it manually creates the danger of stale messages, as the OP pointed out.
EDIT: The JcdDebug.pas methods as highlighted in other answers appear to be far simpler than my answer, provided that debug info is present.
I've solved similar problems through design. Your example confuses me because you seem to already be doing this.
You wrap your validation functions once like this:
procedure SomeValidateProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc3');
end;
Then instead of repeatedly calling:
ValidateStruct(Struct, 'SomeProc3");
You call:
SomeValidateProc3(Struct);
If you have a typo, the compiler will catch it:
SoemValidateProc3(Struct);
If you use a more meaningful name for your wrapper functions like "ValidateName", the code becomes more readable also.
I think you are doing it the wrong way round:
First, check whether there is an error and only then (that is: You need the name of the caller) use some tool like JclDebug to get the name of the caller by passing the return address from the stack to it.
Getting the procedure name is very expensive performance wise, so you only want to do it when absolutely necessary.

Why is Self assignable in Delphi?

This code in a GUI application compiles and runs:
procedure TForm1.Button1Click(Sender: TObject);
begin
Self := TForm1.Create(Owner);
end;
(tested with Delphi 6 and 2009)
why is Self writable and not read-only?
in which situations could this be useful?
Edit:
is this also possible in Delphi Prism? (I think yes it is, see here)
Update:
Delphi applications/libraries which make use of Self assignment:
python4delphi
That's not as bad as it could be. I just tested it in Delphi 2009, and it would seem that, while the Self parameter doesn't use const semantics, which you seem to be implying it should, it also doesn't use var semantics, so you can change it all you want within your method without actually losing the reference the caller holds to your object. That would be a very bad thing.
As for the reason why, one of two answers. Either a simple oversight, or what Marco suggested: to allow you to pass Self to a var parameter.
Maybe to allow passing to const or var parameters?
It could be an artefact, since system doesn't have self anywhere on the left of := sign.
Assigning to Self is so illogical and useless that this 'feature' is probably an oversight. And as with assignable constants, it's not always easy to correct such problems.
The simple advice here is: don't do it.
In reality, "Self" is just a name reference to a place on the stack that store address pointing to object in the heap. Forcing read-only on this variable is possible, apparently the designer decided not to. I believe the decision is arbitrary.
Can't see any case where this is useful, that'd merely change a value in stack. Also, changing this value can be dangerous as there is no guarantee that the behavior of the code that reference instance's member will be consistence across compiler versions.
Updated: In response to PatrickvL comment
The 'variable' "Self" is not on the
stack (to my knowledge, it never is);
Instead it's value is put in a
register (EAX to be exact) just before
a call to any object method is made. –
Nope, Self has actual address on the memory. Try this code to see for yourself.
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(Integer(#Self)));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
newform: TForm;
p: ^Integer;
begin
Self.Caption := 'TheOriginal';
newform := TForm.Create(nil);
try
newform.Caption := 'TheNewOne';
// The following two lines is, technically, the same as
// Self := newform;
p := Pointer(#Self);
p^ := Integer(newform);
ShowMessage(Self.Caption); // This will show 'TheNewOne' instead of 'TheOriginal'
finally
Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
end;
end;
Sometimes, when you want to optimize a method for as far as you can take it (without resorting to assembly), 'Self' can be (ab)used as a 'free' variable - it could just mean the difference between using stack and using registers.
Sure, the contents of the stack are most probably already present in the CPU cache, so it should be fast to access, but registers are even faster still.
As a sidenote : I'm still missing the days when I was programming on the Amiga's Motorola 68000 and had the luxury of 16 data and 16 address registers.... I can't believe the world chose to go with the limited 4 registers of the 80x86 line of processors!
And as a final note, I choose to use Self sometimes, as the Delphi's optimizer is, well, not optimizing that well, actually. (At least, it pales compared to what trickery one can find in the various LLVM optimizers for example.) IMHO, and YMMV of course.

How to know what type is a var?

TypeInfo(Type) returns the info about the specified type, is there any way to know the typeinfo of a var?
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= TypeInfo(S);
Info:= TypeInfo(Instance);
Info:= TypeInfo(Obj);
end
This code returns:
[DCC Error] Unit1.pas(354): E2133 TYPEINFO standard function expects a type identifier
I know a non instantiated var is only a pointer address.
At compile time, the compiler parses and do the type safety check.
At run time, is there any way to know a little more about a var, only passing its address?
No.
First, there's no such thing as a "non-instantiated variable." You instantiate it by the mere act of typing its name and type into your source file.
Second, you already know all there is to know about a variable by looking at it in your source code. The variable ceases to exist once your program is compiled. After that, it's all just bits.
A pointer only has a type at compile time. At run time, everything that can be done to that address has already been determined. The compiler checks for that, as you already noted. Checking the type of a variable at run time is only useful in languages where a variable's type could change, as in dynamic languages. The closest Delphi comes to that is with its Variant type. The type of the variable is always Variant, but you can store many types of values in it. To find out what it holds, you can use the VarType function.
Any time you could want to use TypeInfo to get the type information of the type associated with a variable, you can also directly name the type you're interested in; if the variable is in scope, then you can go find its declaration and use the declared type in your call to TypeInfo.
If you want to pass an arbitrary address to a function and have that function discover the type information for itself, you're out of luck. You will instead need to pass the PTypeInfo value as an additional parameter. That's what all the built-in Delphi functions do. For example, when you call New on a pointer variable, the compiler inserts an additional parameter that holds the PTypeInfo value for the type you're allocating. When you call SetLength on a dynamic array, the compiler inserts a PTypeInfo value for the array type.
The answer that you gave suggests that you're looking for something other than what you asked for. Given your question, I thought you were looking for a hypothetical function that could satisfy this code:
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= GetVariableTypeInfo(#S);
Assert(Info = TypeInfo(string));
Info:= GetVariableTypeInfo(#Instance);
Assert(Info = TypeInfo(IObjectType));
Info:= GetVariableTypeInfo(#Obj);
Assert(Info = TypeInfo(TDBGrid));
end;
Let's use the IsClass and IsObject functions from the JCL to build that function:
function GetVariableTypeInfo(pvar: Pointer): PTypeInfo;
begin
if not Assigned(pvar) then
Result := nil
else if IsClass(PPointer(pvar)^) then
Result := PClass(pvar).ClassInfo
else if IsObject(PPointer(pvar)^) then
Result := PObject(pvar).ClassInfo
else
raise EUnknownResult.Create;
end;
It obviously won't work for S or Instance above, but let's see what happens with Obj:
Info := GetVariableTypeInfo(#Obj);
That should give an access violation. Obj has no value, so IsClass and IsObject both will be reading an unspecified memory address, probably not one that belongs to your process. You asked for a routine that would use a variable's address as its input, but the mere address isn't enough.
Now let's take a closer look at how IsClass and IsObject really behave. Those functions take an arbitrary value and check whether the value looks like it might be a value of the given kind, either object (instance) or class. Use it like this:
// This code will yield no assertion failures.
var
p: Pointer;
o: TObject;
a: array of Integer;
begin
p := TDBGrid;
Assert(IsClass(p));
p := TForm.Create(nil);
Assert(IsObject(p));
// So far, so good. Works just as expected.
// Now things get interesting:
Pointer(a) := p;
Assert(IsObject(a));
Pointer(a) := nil;
// A dynamic array is an object? Hmm.
o := nil;
try
IsObject(o);
Assert(False);
except
on e: TObject do
Assert(e is EAccessViolation);
end;
// The variable is clearly a TObject, but since it
// doesn't hold a reference to an object, IsObject
// can't check whether its class field looks like
// a valid class reference.
end;
Notice that the functions tell you nothing about the variables, only about the values they hold. I wouldn't really consider those functions, then, to answer the question of how to get type information about a variable.
Furthermore, you said that all you know about the variable is its address. The functions you found do not take the address of a variable. They take the value of a variable. Here's a demonstration:
var
c: TClass;
begin
c := TDBGrid;
Assert(IsClass(c));
Assert(not IsClass(#c)); // Address of variable
Assert(IsObject(#c)); // Address of variable is an object?
end;
You might object to how I'm abusing these functions by passing what's obviously garbage into them. But I think that's the only way it makes sense to talk about this topic. If you know you'll never have garbage values, then you don't need the function you're asking for anyway because you already know enough about your program to use real types for your variables.
Overall, you're asking the wrong question. Instead of asking how you determine the type of a variable or the type of a value in memory, you should be asking how you got yourself into the position where you don't already know the types of your variables and your data.
With generics, it is now possible to get the type info without specifying it.
Certain users indicated the following code doesn't compile without errors.
As of Delphi 10 Seattle, version 23.0.20618.2753, it compiles without errors, as seen below in the screenshot.
program TypeInfos;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.TypInfo;
type
TTypeInfo = class
class procedure ShowTypeInfo<T>(const X: T);
end;
{ TTypeInfo }
class procedure TTypeInfo.ShowTypeInfo<T>(const X: T);
var
LTypeInfo: PTypeInfo;
begin
LTypeInfo := TypeInfo(T);
WriteLn(LTypeInfo.Name);
end;
var
L: Exception;
B: Boolean;
begin
// Console output
TTypeInfo.ShowTypeInfo(L); // Exception
TTypeInfo.ShowTypeInfo(B); // Boolean
end.
Not that I know of. You can get RTTI (Run Time Type Information) on published properties of a class, but not for "normal" variables like strings and integers and so forth. The information is simply not there.
Besides, the only way you could pass a var without passing a type is to use either a generic TObject parameter, a generic type (D2008, as in ), or as an untyped parameter. I can't think of another way of passing it that would even compile.

Resources