%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The TYPINFO unit
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{The TYPINFO unit}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Constants, Types and variables
\section{Constants, Types and variables}
\subsection{Constants}
The following constants are used in the implementation section of the unit.

\begin{verbatim}
BooleanIdents: array[Boolean] of String = ('False', 'True');
DotSep: String = '.';
\end{verbatim}
The following constants determine the access method for the \var{Stored} 
identifier of a property as used in the \var{PropProcs} field of the 
\var{TPropInfo} record:
\begin{verbatim}
ptField = 0;
ptStatic = 1;
ptVirtual = 2;
ptConst = 3;
\end{verbatim}
The following typed constants are used for easy selection of property types.
\begin{verbatim}
tkAny = [Low(TTypeKind)..High(TTypeKind)];
tkMethods = [tkMethod];
tkProperties = tkAny-tkMethods-[tkUnknown];
\end{verbatim}

\subsection{types}
The following pointer types are defined:
\begin{verbatim}
PShortString =^ShortString;
PByte        =^Byte;
PWord        =^Word;
PLongint     =^Longint;
PBoolean     =^Boolean;
PSingle      =^Single;
PDouble      =^Double;
PExtended    =^Extended;
PComp        =^Comp;
PFixed16     =^Fixed16;
Variant      = Pointer;
\end{verbatim}

The \var{TTypeKind} determines the type of a property:
\begin{verbatim}
TTypeKind = (tkUnknown,tkInteger,tkChar,tkEnumeration,
             tkFloat,tkSet,tkMethod,tkSString,tkLString,tkAString,
             tkWString,tkVariant,tkArray,tkRecord,tkInterface,
             tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord,
             tkDynArray,tkInterfaceRaw);
tkString = tkSString;
\end{verbatim}
\var{tkString} is an alias that is introduced for Delphi compatibility.

If the property is and ordinal type, then \var{TTOrdType} determines the 
size and sign of the ordinal type:
\begin{verbatim}
TTOrdType = (otSByte,otUByte,otSWord,otUWord,otSLong,otULong);
\end{verbatim}
The size of a float type is determined by \var{TFloatType}:
\begin{verbatim}
TFloatType = (ftSingle,ftDouble,ftExtended,ftComp,ftCurr,
              ftFixed16,ftFixed32);
\end{verbatim}
A method property (e.g. an event) can have one of several types:
\begin{verbatim}
TMethodKind = (mkProcedure,mkFunction,mkConstructor,mkDestructor,
               mkClassProcedure, mkClassFunction);
\end{verbatim}
The kind of parameter to a method is determined by \var{TParamFlags}:
\begin{verbatim}
TParamFlags = set of (pfVar,pfConst,pfArray,pfAddress,pfReference,pfOut);
\end{verbatim}
Interfaces are described further with \var{TntfFlags}:
\begin{verbatim}
TIntfFlags = set of (ifHasGuid,ifDispInterface,ifDispatch);
\end{verbatim}
The following defines a set of \var{TTypeKind}:
\begin{verbatim}
TTypeKinds = set of TTypeKind;
\end{verbatim}
The \var{TypeInfo} function returns a pointer to a \var{TTypeInfo} record:
\begin{verbatim}
TTypeInfo = record
  Kind : TTypeKind;
  Name : ShortString;
end;
PTypeInfo = ^TTypeInfo;
PPTypeInfo = ^PTypeInfo;
\end{verbatim}
Note that the Name is stored with as much bytes as needed to store the name,
it is not padded to 255 characters. 
The type data immediatly follows the \var{TTypeInfo} record as a \var{TTypeData} record:
\begin{verbatim}
PTypeData = ^TTypeData;
TTypeData = packed record
case TTypeKind of
  tkUnKnown,tkLString,tkWString,tkAString,tkVariant:
    ();
  tkInteger,tkChar,tkEnumeration,tkWChar:
    (OrdType : TTOrdType;
     case TTypeKind of
       tkInteger,tkChar,tkEnumeration,tkBool,tkWChar : (
         MinValue,MaxValue : Longint;
         case TTypeKind of
           tkEnumeration: (
             BaseType : PTypeInfo;
             NameList : ShortString
           )
         );
       tkSet: (
             CompType : PTypeInfo
         )
     );
  tkFloat: (
    FloatType : TFloatType
    );
  tkSString:
    (MaxLength : Byte);
  tkClass:
    (ClassType : TClass;
     ParentInfo : PTypeInfo;
     PropCount : SmallInt;
     UnitName : ShortString
     );
  tkMethod:
    (MethodKind : TMethodKind;
     ParamCount : Byte;
     ParamList : array[0..1023] of Char
     {in reality ParamList is a array[1..ParamCount] of:
	  record
	    Flags : TParamFlags;
	    ParamName : ShortString;
	    TypeName : ShortString;
	  end;
	followed by
	  ResultType : ShortString}
    );
  tkInt64:
   (MinInt64Value, MaxInt64Value: Int64);
  tkQWord:
   (MinQWordValue, MaxQWordValue: QWord);
  tkInterface:
	();
end;
\end{verbatim}
If the typeinfo kind is \var{tkClass}, then the property 
information follows the \var{UnitName} string, as an array of \var{TPropInfo} records.

The \var{TPropData} record is not used, but is provided for completeness.
\begin{verbatim}
TPropData = packed record
  PropCount : Word;
  PropList : record end;
end;
\end{verbatim}
The \var{TPropInfo} record describes one published property of a class:
\begin{verbatim}
PPropInfo = ^TPropInfo;
TPropInfo = packed record
  PropType : PTypeInfo;
  GetProc : Pointer;
  SetProc : Pointer;
  StoredProc : Pointer;
  Index : Integer;
  Default : Longint;
  NameIndex : SmallInt;
  PropProcs : Byte;
  Name : ShortString;
end;
\end{verbatim}
The \var{Name} field is stored not with 255 characters, but with just as many characters
as required to store the name.
\begin{verbatim}
TProcInfoProc = procedure(PropInfo : PPropInfo) of object;
\end{verbatim}
The following pointer and array types are used for typecasts:
\begin{verbatim}
PPropList = ^TPropList;
TPropList = array[0..65535] of PPropInfo;
\end{verbatim}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Functions and procedures
\section{Functions and Procedures}

\begin{function}{GetTypeData}
\Declaration
Function GetTypeData(TypeInfo : PTypeInfo) : PTypeData;
\Description
\var{GetTypeData} returns a pointer to the \var{TTypeData} record that
follows after the \var{TTypeInfo} record pointed to by \var{TypeInfo}.
It essentially skips the \var{Kind} and \var{Name} fields in the 
\var{TTypeInfo} record.
\Errors
None.
\SeeAlso
\end{function}


\begin{function}{GetPropInfo}
\Declaration
function GetPropInfo(TypeInfo: PTypeInfo; 
                     const PropName: string) : PPropInfo;
\Description
\var{GetPropInfo} returns a pointer to the \var{TPropInfo} record for a the \var{PropName}
property of a class that has \var{TypeInfo} as class info. 
\Errors
If the property \var{PropName} does not exist, \var{Nil} is returned.
\SeeAlso
\seep{GetPropInfos},\seef{GetPropList}
\end{function}


\begin{procedure}{GetPropInfos}
\Declaration
Procedure GetPropInfos(TypeInfo: PTypeInfo;PropList: PPropList);
\Description
\var{GetPropInfos} stores pointers to the property information of all published
properties of a class with class info \var{TypeInfo} in the list pointed to by
\var{Proplist}. The \var{PropList} pointer must point to a memory location that
contains enough space to hold all properties of the class and its parent classes.
\Errors
No checks are done to see whether \var{PropList} points to a memory area that 
is big enough to hold all pointers.
\SeeAlso
\seef{GetPropInfo},\seef{GetPropList}
\end{procedure}


\begin{function}{GetPropList}
\Declaration
Function GetPropList(TypeInfo : PTypeInfo;
                     TypeKinds : TTypeKinds; 
                     PropList : PPropList) : Integer;
\Description
\var{GetPropList} stores pointers to property information of the class with class
info \var{TypeInfo} for properties of kind \var{TypeKinds} in the list pointed to
by \var{Proplist}. \var{PropList} must contain enough space to hold all properties.

The function returns the number of pointers that matched the criteria and were stored
in \var{PropList}.
\Errors
No checks are done to see whether \var{PropList} points to a memory area that is big enough
to hold all pointers.
\SeeAlso
\seep{GetPropInfos}, \seef{GetPropInfo}
\end{function}


\begin{function}{IsStoredProp}
\Declaration
Function IsStoredProp(Instance : TObject;PropInfo : PPropInfo) : Boolean;
\Description
\var{IsStoredProp} returns \var{True} if the \var{Stored} modifier evaluates
to \var{True} for the property described by \var{PropInfo} for object 
\var{Instance}. It returns \var{False} otherwise. If the function returns
\var{True}, this indicates that the property should be written when
streaming the object \var{Instance}.

If there was no \var{stored} modifier in the declaration of the property, 
\var{True} will be returned. 
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid property of \var{Instance}.
\SeeAlso
\end{function}


\begin{function}{GetOrdProp}
\Declaration
Function GetOrdProp(Instance : TObject;PropInfo : PPropInfo) : Longint;
\Description
\var{GetOrdProp} returns the value of the ordinal property described by
\var{PropInfo} for the object \var{Instance}. The value is returned as a
longint, which should be typecasted to the needed type.

Ordinal properties that can be retrieved include:
\begin{description}
\item[Integers and subranges of integers] The value of the integer will be
returned.
\item[Enumerated types and subranges of enumerated types] The ordinal value
of the enumerated type will be returned.
\item[Sets] If the base type of the set has less than 31 possible values.
If a bit is set in the return value, then the corresponding element of the
base ordinal class of the set type must be included in the set.
\end{description}
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid ordinal property of \var{Instance}
\SeeAlso
\seep{SetOrdProp}, \seef{GetStrProp}, \seef{GetFloatProp},
\seef{GetInt64Prop},\seef{GetMethodProp}

\end{function}


\begin{procedure}{SetOrdProp}
\Declaration
Procedure SetOrdProp(Instance : TObject;PropInfo : PPropInfo; Value : Longint);
\Description
\var{SetOrdProp} assigns \var{Value} to the the ordinal property described by 
\var{PropInfo} for the object \var{Instance}. 

Ordinal properties that can be set include:
\begin{description}
\item[Integers and subranges of integers] The actual value of the integer must be 
passed.
\item[Enumerated types and subranges of enumerated types] The ordinal value
of the enumerated type must be passed.
\item[Subrange types] of integers or enumerated types. Here the ordinal
value must be passed.
\item[Sets] If the base type of the set has less than 31 possible values.
For each possible value; the corresponding bit of \var{Value} must be set.
\end{description}
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid ordinal property of \var{Instance}. 
No range checking is performed.
\SeeAlso
\seef{GetOrdProp}, \seep{SetStrProp}, \seep{SetFloatProp},
\seep{SetInt64Prop},\seep{SetMethodProp}
\end{procedure}


\begin{function}{GetStrProp}
\Declaration
Function GetStrProp(Instance : TObject;PropInfo : PPropInfo) : Ansistring;
\Description
\var{GetStrProp} returns the value of the string property described by
\var{PropInfo} for object \var{Instance}. 
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid string property of \var{Instance}.
\SeeAlso
\seep{SetStrProp}, \seef{GetOrdProp}, \seef{GetFloatProp},
\seef{GetInt64Prop},\seef{GetMethodProp}
\end{function}

\begin{procedure}{SetStrProp}
\Declaration
    procedure SetStrProp(Instance : TObject;PropInfo : PPropInfo;
      const Value : Ansistring);
\Description
\var{GetStrProp} assigns \var{Value} to the string property described by
\var{PropInfo} for object \var{Instance}. 
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid string property of \var{Instance}.
\SeeAlso
\seef{GetStrProp}, \seep{SetOrdProp}, \seep{SetFloatProp},
\seep{SetInt64Prop},\seep{SetMethodProp}


\end{procedure}

\begin{function}{GetFloatProp}
\Declaration
Function GetFloatProp(Instance : TObject;PropInfo : PPropInfo) : Extended;
\Description
\var{GetFloatProp} returns the value of the float property described by 
\var{PropInfo} for the object \var{Instance}. All float types are converted
to extended.
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid float property of \var{Instance}.
\SeeAlso
\seep{SetFloatProp}, \seef{GetOrdProp}, \seef{GetStrProp},
\seef{GetInt64Prop},\seef{GetMethodProp}
\end{function}


\begin{procedure}{SetFloatProp}
\Declaration
Procedure SetFloatProp(Instance : TObject;
                       PropInfo : PPropInfo;
                       Value : Extended);
\Description
\var{SetFloatProp} assigns \var{Value} to the property described by
\var{PropInfo} for the object \var{Instance}.
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid float property of \var{Instance}.
\SeeAlso
\seef{GetFloatProp}, \seep{SetOrdProp}, \seep{SetStrProp},
\seep{SetInt64Prop},\seep{SetMethodProp}

\end{procedure}


\begin{function}{GetVariantProp}
\Declaration
Function GetVariantProp(Instance : TObject;PropInfo : PPropInfo): Variant;
\Description
Not yet implemented. Provided for Delphi compatibility only.
\Errors
\SeeAlso
\end{function}


\begin{procedure}{SetVariantProp}
\Declaration
Procedure SetVariantProp(Instance : TObject;
                         PropInfo : PPropInfo;
                         Const Value: Variant);
\Description
Not yet implemented. Provided for Delphi compatibility only.
\Errors
\SeeAlso
\end{procedure}


\begin{function}{GetMethodProp}
\Declaration
Function GetMethodProp(Instance : TObject;PropInfo : PPropInfo) : TMethod;
\Description
\var{GetMethodProp} returns the method the property described by
\var{PropInfo} for object \var{Instance}.
The return type \var{TMethod} is defined in the \file{SysUtils} unit as:
\begin{verbatim}
TMethod = packed record
  Code, Data: Pointer;
end;                                                                         
\end{verbatim}
\var{Data} points to the instance of the class with the method \var{Code}.

\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid method property of \var{Instance}.
\SeeAlso
\seep{SetMethodProp}, \seef{GetOrdProp}, \seef{GetStrProp},
\seef{GetFloatProp}, \seef{GetInt64Prop}
\end{function}


\begin{procedure}{SetMethodProp}
\Declaration
Procedure SetMethodProp(Instance : TObject;PropInfo : PPropInfo; const Value : TMethod);
\Description
\var{SetMethodProp} assigns \var{Value} to the method the property described 
by \var{PropInfo} for object \var{Instance}.

The type \var{TMethod} of the \var{Value} parameter is defined in the
\file{SysUtils} unit as:
\begin{verbatim}
TMethod = packed record
  Code, Data: Pointer;
end;                                                                         
\end{verbatim}
\var{Data} should point to the instance of the class with the method \var{Code}.

\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid method property of \var{Instance}.
\SeeAlso
\seef{GetMethodProp}, \seep{SetOrdProp}, \seep{SetStrProp},
\seep{SetFloatProp}, \seep{SetInt64Prop}
\end{procedure}

\begin{function}{GetInt64Prop}
\Declaration
Function GetInt64Prop(Instance: TObject; PropInfo: PPropInfo): Int64;
\Description
\var{GetInt64Prop} returns the value of the property of type
\var{Int64} that is described by \var{PropInfo} for the object
\var{Instance}.

\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid \var{Int64} property of \var{Instance}.
\SeeAlso
\seep{SetInt64Prop}, \seef{GetOrdProp}, \seef{GetStrProp},
\seef{GetFloatProp}, \seef{GetMethodProp}

\end{function}

\begin{procedure}{SetInt64Prop}
\Declaration
Procedure SetInt64Prop(Instance: TObject; PropInfo: PPropInfo; const Value: Int64);
\Description
\var{SetInt64Prop} assigns \var{Value} to the property of type
\var{Int64} that is described by \var{PropInfo} for the object
\var{Instance}.
\Errors
No checking is done whether \var{Instance} is non-nil, or whether
\var{PropInfo} describes a valid \var{Int64} property of \var{Instance}.
\SeeAlso
\seef{GetInt64Prop}, \seef{GetMethodProp}, \seep{SetOrdProp}, \seep{SetStrProp},
\seep{SetFloatProp}
\end{procedure}

\begin{function}{GetEnumName}
\Declaration
Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
\Description
\var{GetEnumName} scans the type information for the enumeration type
desribed by \var{TypeInfo} and returns the name of the enumeration 
constant for the element with ordinal value equal to \var{Value}.

If \var{Value} is out of range, the first element of the enumeration type
is returned. The result is lowercased, but this may change in the future.

This can be used in combination with \var{GetOrdProp} to stream a property
of an enumerated type.
\Errors
No check is done whether \var{TypeInfo} points to the type information
for an enumerated type. 
\SeeAlso
\seef{GetOrdProp}, \seef{GetEnumValue}
\end{function}

\begin{function}{GetEnumValue}
\Declaration
Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer;
\Description
\var{GetEnumValue} scans the type information for the enumeration type
described by \var{TypeInfor} and returns the ordinal value for the element
in the enumerated type that has identifier \var{Name}. The identifier is
searched in a case-insensitive manner.

This can be used to set the value of enumerated properties from a stream. 
\Errors
If \var{Name} is not found in the list of enumerated values, then -1 is
returned. No check is done whether \var{TypeInfo} points to the type information
for an enumerated type. 
\SeeAlso
\seef{GetEnumName}, \seep{SetOrdProp}
\end{function}
