[fpc-pascal] RTTI Bug or something else i did wrong...

Jorge Aldo G. de F. Junior jagfj80 at gmail.com
Fri Jan 15 10:41:23 CET 2010


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 ?



More information about the fpc-pascal mailing list