📄 jclrtti.pas
字号:
{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is JclRTTI.pas. }
{ }
{ The Initial Developer of the Original Code is Marcel Bestebroer. }
{ Portions created Marcel Bestebroer are Copyright (C) Marcel Bestebroer. All rights reserved. }
{ }
{ Contributor(s): }
{ Theo Bebekis }
{ Marcel Bestebroer (marcelb) }
{ Robert Marquardt (marquardt) }
{ Robert Rossmair (rrossmair) }
{ Matthias Thoma (mthoma) }
{ Petr Vones (pvones) }
{ }
{**************************************************************************************************}
{ }
{ Various RunTime Type Information routines. Includes retrieving RTTI information for different }
{ types, declaring/generating new types, data conversion to user displayable values and 'is'/'as' }
{ operator hooking. }
{ }
{ Unit owner: Marcel Bestebroer }
{ }
{**************************************************************************************************}
// Last modified: $Date: 2005/03/08 16:10:08 $
// For history see end of file
unit JclRTTI;
{$I jcl.inc}
interface
uses
{$IFDEF HAS_UNIT_TYPES}
Types,
{$IFDEF SUPPORTS_INLINE}
Windows,
{$ENDIF SUPPORTS_INLINE}
{$ELSE}
Windows,
{$ENDIF HAS_UNIT_TYPES}
Classes, SysUtils, TypInfo,
JclBase;
type
// TypeInfo writing
IJclInfoWriter = interface
['{7DAD522D-46EA-11D5-B0C0-4854E825F345}']
function GetWrap: Integer;
procedure SetWrap(const Value: Integer);
procedure Write(const S: string);
procedure Writeln(const S: string = '');
procedure Indent;
procedure Outdent;
property Wrap: Integer read GetWrap write SetWrap;
end;
TJclInfoWriter = class(TInterfacedObject, IJclInfoWriter)
private
FCurLine: string;
FIndentLevel: Integer;
FWrap: Integer;
protected
function GetWrap: Integer;
procedure SetWrap(const Value: Integer);
procedure DoWrap;
procedure DoWriteCompleteLines;
procedure PrimWrite(const S: string); virtual; abstract;
property CurLine: string read FCurLine write FCurLine;
property IndentLevel: Integer read FIndentLevel write FIndentLevel;
public
constructor Create(const AWrap: Integer = 80);
destructor Destroy; override;
procedure Indent;
procedure Outdent;
procedure Write(const S: string);
procedure Writeln(const S: string = '');
property Wrap: Integer read GetWrap write SetWrap;
end;
TJclInfoStringsWriter = class(TJclInfoWriter)
private
FStrings: TStrings;
protected
procedure PrimWrite(const S: string); override;
public
constructor Create(const AStrings: TStrings; const AWrap: Integer = 80);
property Strings: TStrings read FStrings;
end;
// TypeInfo retrieval
IJclBaseInfo = interface
procedure WriteTo(const Dest: IJclInfoWriter);
procedure DeclarationTo(const Dest: IJclInfoWriter);
end;
IJclTypeInfo = interface(IJclBaseInfo)
['{7DAD5220-46EA-11D5-B0C0-4854E825F345}']
function GetName: string;
function GetTypeData: PTypeData;
function GetTypeInfo: PTypeInfo;
function GetTypeKind: TTypeKind;
property Name: string read GetName;
property TypeData: PTypeData read GetTypeData;
property TypeInfo: PTypeInfo read GetTypeInfo;
property TypeKind: TTypeKind read GetTypeKind;
end;
// Ordinal types
IJclOrdinalTypeInfo = interface(IJclTypeInfo)
['{7DAD5221-46EA-11D5-B0C0-4854E825F345}']
function GetOrdinalType: TOrdType;
property OrdinalType: TOrdType read GetOrdinalType;
end;
IJclOrdinalRangeTypeInfo = interface(IJclOrdinalTypeInfo)
['{7DAD5222-46EA-11D5-B0C0-4854E825F345}']
function GetMinValue: Int64;
function GetMaxValue: Int64;
property MinValue: Int64 read GetMinValue;
property MaxValue: Int64 read GetMaxValue;
end;
IJclEnumerationTypeInfo = interface(IJclOrdinalRangeTypeInfo)
['{7DAD5223-46EA-11D5-B0C0-4854E825F345}']
function GetBaseType: IJclEnumerationTypeInfo;
function GetNames(const I: Integer): string;
{$IFDEF COMPILER6_UP}
function GetUnitName: string;
{$ENDIF COMPILER6_UP}
function IndexOfName(const Name: string): Integer;
property BaseType: IJclEnumerationTypeInfo read GetBaseType;
property Names[const I: Integer]: string read GetNames; default;
{$IFDEF COMPILER6_UP}
property UnitName: string read GetUnitName;
{$ENDIF COMPILER6_UP}
end;
IJclSetTypeInfo = interface(IJclOrdinalTypeInfo)
['{7DAD5224-46EA-11D5-B0C0-4854E825F345}']
function GetBaseType: IJclOrdinalTypeInfo;
procedure GetAsList(const Value; const WantRanges: Boolean;
const Strings: TStrings);
procedure SetAsList(out Value; const Strings: TStrings);
property BaseType: IJclOrdinalTypeInfo read GetBaseType;
end;
// Float types
IJclFloatTypeInfo = interface(IJclTypeInfo)
['{7DAD5225-46EA-11D5-B0C0-4854E825F345}']
function GetFloatType: TFloatType;
property FloatType: TFloatType read GetFloatType;
end;
// Short string types
IJclStringTypeInfo = interface(IJclTypeInfo)
['{7DAD5226-46EA-11D5-B0C0-4854E825F345}']
function GetMaxLength: Integer;
property MaxLength: Integer read GetMaxLength;
end;
// Class types
TJclPropSpecKind = (pskNone, pskStaticMethod, pskVirtualMethod, pskField,
pskConstant);
IJclPropInfo = interface
['{7DAD5227-46EA-11D5-B0C0-4854E825F345}']
function GetPropType: IJclTypeInfo;
function GetReader: Pointer;
function GetWriter: Pointer;
function GetStoredProc: Pointer;
function GetIndex: Integer;
function GetDefault: Longint;
function GetNameIndex: Smallint;
function GetName: string;
function GetReaderType: TJclPropSpecKind;
function GetWriterType: TJclPropSpecKind;
function GetStoredType: TJclPropSpecKind;
function GetReaderValue: Integer;
function GetWriterValue: Integer;
function GetStoredValue: Integer;
function IsStored(const AInstance: TObject): Boolean;
function HasDefault: Boolean;
function HasIndex: Boolean;
property PropType: IJclTypeInfo read GetPropType;
property Reader: Pointer read GetReader;
property Writer: Pointer read GetWriter;
property StoredProc: Pointer read GetStoredProc;
property ReaderType: TJclPropSpecKind read GetReaderType;
property WriterType: TJclPropSpecKind read GetWriterType;
property StoredType: TJclPropSpecKind read GetStoredType;
property ReaderValue: Integer read GetReaderValue;
property WriterValue: Integer read GetWriterValue;
property StoredValue: Integer read GetStoredValue;
property Index: Integer read GetIndex;
property Default: Longint read GetDefault;
property NameIndex: Smallint read GetNameIndex;
property Name: string read GetName;
end;
IJclClassTypeInfo = interface(IJclTypeInfo)
['{7DAD5228-46EA-11D5-B0C0-4854E825F345}']
function GetClassRef: TClass;
function GetParent: IJclClassTypeInfo;
function GetTotalPropertyCount: Integer;
function GetPropertyCount: Integer;
function GetProperties(const PropIdx: Integer): IJclPropInfo;
function GetUnitName: string;
property ClassRef: TClass read GetClassRef;
property Parent: IJclClassTypeInfo read GetParent;
property TotalPropertyCount: Integer read GetTotalPropertyCount;
property PropertyCount: Integer read GetPropertyCount;
property Properties[const PropIdx: Integer]: IJclPropInfo
read GetProperties;
property UnitName: string read GetUnitName;
end;
// Event types
IJclEventParamInfo = interface
['{7DAD5229-46EA-11D5-B0C0-4854E825F345}']
function GetFlags: TParamFlags;
function GetName: string;
function GetRecSize: Integer;
function GetTypeName: string;
function GetParam: Pointer;
property Flags: TParamFlags read GetFlags;
property Name: string read GetName;
property RecSize: Integer read GetRecSize;
property TypeName: string read GetTypeName;
property Param: Pointer read GetParam;
end;
IJclEventTypeInfo = interface(IJclTypeInfo)
['{7DAD522A-46EA-11D5-B0C0-4854E825F345}']
function GetMethodKind: TMethodKind;
function GetParameterCount: Integer;
function GetParameters(const ParamIdx: Integer): IJclEventParamInfo;
function GetResultTypeName: string;
property MethodKind: TMethodKind read GetMethodKind;
property ParameterCount: Integer read GetParameterCount;
property Parameters[const ParamIdx: Integer]: IJclEventParamInfo
read GetParameters;
property ResultTypeName: string read GetResultTypeName;
end;
// Interface types
IJclInterfaceTypeInfo = interface(IJclTypeInfo)
['{7DAD522B-46EA-11D5-B0C0-4854E825F345}']
function GetParent: IJclInterfaceTypeInfo;
function GetFlags: TIntfFlagsBase;
function GetGUID: TGUID;
{$IFDEF COMPILER6_UP}
function GetPropertyCount: Integer;
{$ENDIF COMPILER6_UP}
function GetUnitName: string;
property Parent: IJclInterfaceTypeInfo read GetParent;
property Flags: TIntfFlagsBase read GetFlags;
property GUID: TGUID read GetGUID;
{$IFDEF COMPILER6_UP}
property PropertyCount: Integer read GetPropertyCount;
{$ENDIF COMPILER6_UP}
property UnitName: string read GetUnitName;
end;
// Int64 types
IJclInt64TypeInfo = interface(IJclTypeInfo)
['{7DAD522C-46EA-11D5-B0C0-4854E825F345}']
function GetMinValue: Int64;
function GetMaxValue: Int64;
property MinValue: Int64 read GetMinValue;
property MaxValue: Int64 read GetMaxValue;
end;
{$IFDEF COMPILER6_UP}
// Dynamic array types
IJclDynArrayTypeInfo = interface(IJclTypeInfo)
['{7DAD522E-46EA-11D5-B0C0-4854E825F345}']
function GetElementSize: Longint;
function GetElementType: IJclTypeInfo;
function GetElementsNeedCleanup: Boolean;
function GetVarType: Integer;
function GetUnitName: string;
property ElementSize: Longint read GetElementSize;
property ElementType: IJclTypeInfo read GetElementType;
property ElementsNeedCleanup: Boolean read GetElementsNeedCleanup;
property VarType: Integer read GetVarType;
property UnitName: string read GetUnitName;
end;
{$ENDIF COMPILER6_UP}
EJclRTTIError = class(EJclError);
function JclTypeInfo(ATypeInfo: PTypeInfo): IJclTypeInfo;
// Enumeration types
const
PREFIX_CUT_LOWERCASE = 255;
PREFIX_CUT_EQUAL = 254;
MaxPrefixCut = 250;
function JclEnumValueToIdent(TypeInfo: PTypeInfo; const Value): string;
function JclGenerateEnumType(const TypeName: ShortString;
const Literals: array of string): PTypeInfo;
function JclGenerateEnumTypeBasedOn(const TypeName: ShortString;
BaseType: PTypeInfo; const PrefixCut: Byte): PTypeInfo;
function JclGenerateSubRange(BaseType: PTypeInfo; const TypeName: string;
const MinValue, MaxValue: Integer): PTypeInfo;
// Integer types
function JclStrToTypedInt(Value: string; TypeInfo: PTypeInfo): Integer;
function JclTypedIntToStr(Value: Integer; TypeInfo: PTypeInfo): string;
// Sets
function JclSetToList(TypeInfo: PTypeInfo; const Value; const WantBrackets: Boolean;
const WantRanges: Boolean; const Strings: TStrings): string;
function JclSetToStr(TypeInfo: PTypeInfo; const Value;
const WantBrackets: Boolean = False; const WantRanges: Boolean = False): string;
procedure JclStrToSet(TypeInfo: PTypeInfo; var SetVar; const Value: string);
procedure JclIntToSet(TypeInfo: PTypeInfo; var SetVar; const Value: Integer);
function JclSetToInt(TypeInfo: PTypeInfo; const SetVar): Integer;
function JclGenerateSetType(BaseType: PTypeInfo; const TypeName: ShortString): PTypeInfo;
// User generated type info managment
procedure RemoveTypeInfo(TypeInfo: PTypeInfo);
// Is/As hooking
function JclIsClass(const AnObj: TObject; const AClass: TClass): Boolean;
function JclIsClassByName(const AnObj: TObject; const AClass: TClass): Boolean;
implementation
uses
{$IFDEF HAS_UNIT_RTLCONSTS}
RtlConsts,
{$ENDIF HAS_UNIT_RTLCONSTS}
SysConst,
JclLogic, JclResources, JclStrings, JclSysUtils;
//=== { TJclInfoWriter } =====================================================
constructor TJclInfoWriter.Create(const AWrap: Integer);
begin
inherited Create;
Wrap := AWrap;
end;
destructor TJclInfoWriter.Destroy;
begin
if CurLine <> '' then
Writeln('');
inherited Destroy;
end;
function TJclInfoWriter.GetWrap: Integer;
begin
Result := FWrap;
end;
procedure TJclInfoWriter.SetWrap(const Value: Integer);
begin
FWrap := Value;
end;
procedure TJclInfoWriter.DoWrap;
var
TmpLines: TStringList;
I: Integer;
TmpLines2: TStringList;
EndedInCRLF: Boolean;
LineBreakLength: integer;
begin
LineBreakLength := Length(AnsiLineBreak);
EndedInCRLF := Copy(CurLine, Length(CurLine) - LineBreakLength + 1, LineBreakLength) = AnsiLineBreak;
TmpLines := TStringList.Create;
try
TmpLines.Text := CurLine;
TmpLines2 := TStringList.Create;
try
I := TmpLines.Count-1;
if not EndedInCRLF then
Dec(I);
while I >= 0 do
begin
TmpLines[I] := StringOfChar(' ', 2 * IndentLevel) + TmpLines[I];
if (Wrap > 0) and (Length(TmpLines[I]) > Wrap) then
begin
TmpLines2.Text := WrapText(
TmpLines[I],
AnsiLineBreak + StringOfChar(' ', 2 * (IndentLevel+1)),
[#0..' ', '-'],
Wrap);
TmpLines.Delete(I);
TmpLines.Insert(I, Copy(TmpLines2.Text, 1,
Length(TmpLines2.Text) - 2));
end;
Dec(I);
end;
CurLine := TmpLines.Text;
if not EndedInCRLF then
Delete(FCurLine, Length(FCurLine) - LineBreakLength + 1, LineBreakLength);
finally
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -