Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2010-01

RTTI Bug or something else i did wrong...

7 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Jorge Aldo G. de F. Junior

The following code:
--------------------------------------------------------- Unit

	RTTIObject;
Interface

Uses
Classes,
SysUtils,
StrUtils,
Contnrs,

	TypInfo;
Type
 TRTTIObject = Class(TObject)
	Private
		fInstanceName: String;
  fTypeData: PTypeData;
  fPropList: PPropList;
  fNumProperties: Integer;
	Protected
		Procedure SetProperty(Const aName, aValue: String); Overload;
		Function GetProperty(Const aName: String): String; Overload;
		Procedure SetProperty(Const aIndex: Integer; aValue: String); Overload;
		Function GetProperty(Const aIndex: Integer): String; Overload;
		Function GetPropertyName(Const aIndex: Integer): String;
		Function GetPropertyType(Const aIndex: Integer): String;
		Function GetPropertyIndex(Const aName: String): Integer;
	Public
		Constructor Create(Const aInstanceName: String); Virtual;
		Destructor Destroy; Override;
		Property Properties[aName: String]: String Read GetProperty Write SetProperty;
		Property Properties[aIndex: Integer]: String Read GetProperty Write
SetProperty;
		Property PropertyCount: Integer Read fNumProperties;
	Published
		Property InstanceName: String Read fInstanceName;
	End;
Implementation
Procedure TRTTIObject.SetProperty(Const aName, aValue: String);
Var
  lRow : Integer;
Begin
	lRow := GetPropertyIndex(aName);
	SetProperty(lRow, aValue);
End;
Function TRTTIObject.GetProperty(Const aName: String): String;
Var
  lRow : Integer;
 Begin
	lRow := GetPropertyIndex(aName);
	Result := GetProperty(lRow);
End;
Procedure TRTTIObject.SetProperty(Const aIndex: Integer; aValue: String);
Var
	lName: String;
Begin
 lName := fPropList^[aIndex]^.Name;
	Case fPropList^[aIndex]^.PropType^.Kind Of
		tkInteger : SetOrdProp(Self, lName, StrToInt(aValue));
		tkFloat   : If fPropList^[aIndex]^.PropType^.Name = 'TDateTime' Then
															SetFloatProp(Self, lName, StrToDateTime(aValue))
														Else
															SetFloatProp(Self, lName, StrToFloat(aValue));
		tkSString : SetStrProp(Self, lName, aValue);
		tkLString : SetStrProp(Self, lName, aValue);
		tkAString : SetStrProp(Self, lName, aValue);
		tkWString : SetStrProp(Self, lName, aValue);
		tkVariant : SetVariantProp(Self, lName, aValue);
		tkBool    : SetOrdProp(Self, lName, Ord(LowerCase(aValue) = 'true'));
		tkInt64   : SetOrdProp(Self, lName, StrToInt(aValue));
		tkQWord   : SetOrdProp(Self, lName, StrToInt(aValue));
		tkUString : SetStrProp(Self, lName, aValue);
	End;
End;
Function TRTTIObject.GetProperty(Const aIndex: Integer): String;
Var
	lName: String;
Begin
	lName := fPropList^[aIndex]^.Name;
	Case fPropList^[aIndex]^.PropType^.Kind Of
		tkInteger : Result := IntToStr(GetOrdProp(Self, lName));
		tkFloat   : If fPropList^[aIndex]^.PropType^.Name = 'TDateTime' Then
															Result := DateTimeToStr(GetFloatProp(Self, lName))
														Else
															Result := FloatToStr(GetFloatProp(Self, lName));
		tkSString : Result := GetStrProp(Self, lName);
		tkLString : Result := GetStrProp(Self, lName);
		tkAString : Result := GetStrProp(Self, lName);
		tkWString : Result := GetStrProp(Self, lName);
		tkVariant : Result := GetVariantProp(Self, lName);
		tkBool    : If Boolean(GetOrdProp(Self, lName)) Then
															Result := 'True'
														Else
															Result := 'False';
		tkInt64   : Result := IntToStr(GetOrdProp(Self, lName));
		tkQWord   : Result := IntToStr(GetOrdProp(Self, lName));
		tkUString : Result := GetStrProp(Self, lName);
	End;
End;
Function TRTTIObject.GetPropertyName(Const aIndex: Integer): String;
Begin
	Result := fPropList^[aIndex]^.Name;
End;
Function TRTTIObject.GetPropertyType(Const aIndex: Integer): String;
Begin
	Result := fPropList^[aIndex]^.PropType^.Name;
End;
Function TRTTIObject.GetPropertyIndex(Const aName: String): Integer;
Var
  lRow : Integer;
  lName : String;
Begin
	Result := -1;
	For lRow := 0 To fNumProperties - 1 Do
			Begin
					lName := GetPropertyName(lRow);
					If lName = aName Then
							Begin
									Result := lRow;
									Break;
							End;
			End;
End;
Constructor TRTTIObject.Create(Const aInstanceName: String);
Begin
 Inherited Create;
 fInstanceName := aInstanceName;
 fTypeData := GetTypeData(Self.ClassInfo);
 GetMem(fPropList, fTypeData^.PropCount * SizeOf(Pointer));
 fNumProperties := GetPropList(Self.ClassInfo, [ tkInteger, tkFloat,
tkSString, tkLString, tkAString, tkWString, tkVariant, tkBool,
tkInt64, tkQWord, tkUString ], fPropList);
End;
Destructor TRTTIObject.Destroy;
Begin
 FreeMem(fPropList, fTypeData^.PropCount * SizeOf(Pointer));
	Inherited Destroy;
End;
End.
---------------------------------
Uses
	RTTIObject;
Var
	MyRTTIObject : TRTTIObject;
Begin
	MyRTTIObject := TRTTIObject.Create('MyRTTIObject');
	MyRTTIObject.Free;
End.
--------------------------------------

gives strange results...

the compiler issues no warning whatsoever but when i try to run the compiled test program, it gives this :

---------------------------------
C:\Programacao\testcase>rttiobject-testcase.exe
An unhandled exception occurred at $0040E1E7 :
EAccessViolation : Access violation
$0040E1E7 TRTTIOBJECT__DESTROY, line 143 of RTTIObject.pas $0040E18A TRTTIOBJECT__CREATE, line 139 of RTTIObject.pas $00401515 main, line 8 of rttiobject-testcase.pas ---------------------------------------------------------

looks like the constructor is calling the destructor before doing anything at all...

what i did wrong ?

Reply by email

cobines
to Jorge Aldo G. de F. Junior

2010/1/15 Jorge Aldo G. de F. Junior :

Show quoted text 13 lines
--------------------------------- C:\Programacao\testcase>rttiobject-testcase.exe An unhandled exception occurred at $0040E1E7 : EAccessViolation : Access violation  $0040E1E7  TRTTIOBJECT__DESTROY,  line 143 of RTTIObject.pas  $0040E18A  TRTTIOBJECT__CREATE,  line 139 of RTTIObject.pas  $00401515  main,  line 8 of rttiobject-testcase.pas --------------------------------------------------------- looks like the constructor is calling the destructor before doing anything at all... what i did wrong ?

Maybe there was an exception raised in the constructor in which case destructor is called automatically. And in destructor you may be accessing fTypeData without it being initialized. Try adding:

if Assigned(fTypeData) and Assigned(fPropList)

in destructor.

cobines

Reply by email

Jorge Aldo G. de F. Junior
to cobines

the error happens even if i remove all statements in the constructor...

Constructor TRTTIObject.Create(Const aInstanceName: String);
Begin
    Inherited Create;
End;

Still gives errors... (why should a constructor call the destructor anyway ?)

2010/1/15 cobines :

Show quoted text 29 lines
2010/1/15 Jorge Aldo G. de F. Junior : > --------------------------------- > C:\Programacao\testcase>rttiobject-testcase.exe > An unhandled exception occurred at $0040E1E7 : > EAccessViolation : Access violation >  $0040E1E7  TRTTIOBJECT__DESTROY,  line 143 of RTTIObject.pas >  $0040E18A  TRTTIOBJECT__CREATE,  line 139 of RTTIObject.pas >  $00401515  main,  line 8 of rttiobject-testcase.pas > --------------------------------------------------------- > > looks like the constructor is calling the destructor before doing > anything at all... > > what i did wrong ? Maybe there was an exception raised in the constructor in which case destructor is called automatically. And in destructor you may be accessing fTypeData without it being initialized. Try adding:  if Assigned(fTypeData) and Assigned(fPropList) in destructor. -- cobines _______________________________________________ fpc-pascal maillist  -   http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Paul Ishenin
to Jorge Aldo G. de F. Junior
Jorge Aldo G. de F. Junior wrote 9 lines
the error happens even if i remove all statements in the constructor... Constructor TRTTIObject.Create(Const aInstanceName: String); Begin Inherited Create; End; Still gives errors... (why should a constructor call the destructor anyway ?)

If a constructor is raises an exception it calls a destructor. This is so because allocated memory needs to be freed.

Best regards,
Paul Ishenin.

Reply by email

Jorge Aldo G. de F. Junior
to Paul Ishenin

well, the bug still stands...

	fTypeData := GetTypeData(Self.ClassInfo);

this line is the problem... looks like i cannot either "GetTypeData" of self in constructor or that Self.ClassInfo doesnt exists until constructor finishs, something like that broken in the RTTI code

Reply by email

Mattias Gaertner
to Jorge Aldo G. de F. Junior
well, the bug still stands... fTypeData := GetTypeData(Self.ClassInfo);

This works here.

Do you have a complete example?

this line is the problem... looks like i cannot either "GetTypeData" of self in constructor or that Self.ClassInfo doesnt exists until constructor finishs, something like that broken in the RTTI code

Mattias

Reply by email