1
0
mirror of https://github.com/salvadordf/CEF4Delphi.git synced 2024-11-24 08:02:15 +02:00
CEF4Delphi/source/uCEFv8Handler.pas
salvadordf ca8bc9dff4 Added cef4delphi.chm help file
Added the PDS file to extract the HTML Help files using PasDoc
Added more XML documentation
Fixed some XML errors.
Removed the license copy from the pas units.
Updated the LICENSE.md file
2023-08-09 19:38:57 +02:00

961 lines
27 KiB
ObjectPascal

unit uCEFv8Handler;
{$IFDEF FPC}
{$MODE OBJFPC}{$H+}
{$ENDIF}
{$I cef.inc}
{$IFNDEF TARGET_64BITS}{$ALIGN ON}{$ENDIF}
{$MINENUMSIZE 4}
interface
uses
{$IFDEF DELPHI16_UP}
{$IFDEF MSWINDOWS}WinApi.Windows,{$ENDIF} System.Rtti, System.TypInfo, System.Variants,
System.SysUtils, System.Classes, System.Math, System.SyncObjs,
{$ELSE}
{$IFDEF DELPHI14_UP}Rtti,{$ENDIF} TypInfo, Variants, SysUtils, Classes, Math, SyncObjs, {$IFDEF MSWINDOWS}Windows,{$ENDIF}
{$ENDIF}
uCEFBaseRefCounted, uCEFInterfaces, uCEFTypes;
type
TCefv8HandlerRef = class(TCefBaseRefCountedRef, ICefv8Handler)
protected
function Execute(const name: ustring; const object_: ICefv8Value; const arguments: TCefv8ValueArray; var retval: ICefv8Value; var exception: ustring): Boolean;
public
class function UnWrap(data: Pointer): ICefv8Handler;
end;
TCefv8HandlerOwn = class(TCefBaseRefCountedOwn, ICefv8Handler)
protected
function Execute(const name: ustring; const object_: ICefv8Value; const arguments: TCefv8ValueArray; var retval: ICefv8Value; var exception: ustring): Boolean; virtual;
public
constructor Create; virtual;
end;
{$IFDEF DELPHI14_UP}
TCefRTTIExtension = class(TCefv8HandlerOwn)
protected
FValue: TValue;
FCtx: TRttiContext;
FSyncMainThread: Boolean;
function GetValue(pi: PTypeInfo; const v: ICefv8Value; var ret: TValue): Boolean;
function SetValue(const v: TValue; var ret: ICefv8Value): Boolean;
{$IFDEF TARGET_64BITS}
class function StrToPtr(const str: ustring): Pointer;
class function PtrToStr(p: Pointer): ustring;
{$ENDIF}
function HandleProperties(const name: ustring; const arguments: TCefv8ValueArray; var retval: ICefv8Value): boolean;
function Execute(const name: ustring; const object_: ICefv8Value; const arguments: TCefv8ValueArray; var retval: ICefv8Value; var exception: ustring): Boolean; override;
public
constructor Create(const value: TValue; SyncMainThread: Boolean = False); reintroduce;
destructor Destroy; override;
class function Register(const name: ustring; const value: TValue; SyncMainThread: Boolean = False) : boolean;
end;
{$ENDIF}
implementation
uses
uCEFMiscFunctions, uCEFLibFunctions, uCEFv8Value, uCEFConstants;
function cef_v8_handler_execute( self : PCefv8Handler;
const name : PCefString;
object_ : PCefv8Value;
argumentsCount : NativeUInt;
const arguments : PPCefV8Value;
var retval : PCefV8Value;
exception : PCefString): Integer; stdcall;
var
TempArgs : TCefv8ValueArray;
i : NativeUInt;
TempReturnValue : ICefv8Value;
TempException : ustring;
TempObject : TObject;
TempRecObject : ICefv8Value;
begin
Result := Ord(False);
TempObject := CefGetObject(self);
if (TempObject <> nil) and (TempObject is TCefv8HandlerOwn) then
try
TempRecObject := TCefv8ValueRef.UnWrap(object_);
TempReturnValue := nil;
TempArgs := nil;
TempException := '';
if (arguments <> nil) and (argumentsCount > 0) then
begin
SetLength(TempArgs, argumentsCount);
i := 0;
while (i < argumentsCount) do
begin
TempArgs[i] := TCefv8ValueRef.UnWrap(arguments^[i]);
inc(i);
end;
end;
Result := Ord(TCefv8HandlerOwn(TempObject).Execute(CefString(name),
TempRecObject,
TempArgs,
TempReturnValue,
TempException));
retval := CefGetData(TempReturnValue);
if (exception <> nil) then
begin
CefStringFree(exception);
exception^ := CefStringAlloc(TempException);
end;
finally
i := 0;
while (i < argumentsCount) do
begin
TempArgs[i] := nil;
inc(i);
end;
TempRecObject := nil;
TempReturnValue := nil;
end;
end;
function TCefv8HandlerRef.Execute(const name : ustring;
const object_ : ICefv8Value;
const arguments : TCefv8ValueArray;
var retval : ICefv8Value;
var exception : ustring): Boolean;
var
TempArgs : array of PCefV8Value;
TempLen, i : integer;
TempReturnValue : PCefV8Value;
TempException : TCefString;
TempName : TCefString;
begin
i := 0;
TempLen := Length(arguments);
SetLength(TempArgs, TempLen);
while (i < TempLen) do
begin
TempArgs[i] := CefGetData(arguments[i]);
inc(i);
end;
CefStringInitialize(@TempException);
TempReturnValue := nil;
TempName := CefString(name);
Result := PCefv8Handler(FData)^.execute(PCefv8Handler(FData), @TempName, CefGetData(object_), TempLen, @TempArgs, TempReturnValue, @TempException) <> 0;
retval := TCefv8ValueRef.UnWrap(TempReturnValue);
exception := CefStringClearAndGet(@TempException);
end;
class function TCefv8HandlerRef.UnWrap(data: Pointer): ICefv8Handler;
begin
if (data <> nil) then
Result := Create(data) as ICefv8Handler
else
Result := nil;
end;
// TCefv8HandlerOwn
constructor TCefv8HandlerOwn.Create;
begin
inherited CreateData(SizeOf(TCefv8Handler));
PCefv8Handler(FData)^.execute := {$IFDEF FPC}@{$ENDIF}cef_v8_handler_execute;
end;
function TCefv8HandlerOwn.Execute(const name: ustring; const object_: ICefv8Value; const arguments: TCefv8ValueArray; var retval: ICefv8Value; var exception: ustring): Boolean;
begin
Result := False;
end;
{$IFDEF DELPHI14_UP}
// TCefRTTIExtension
constructor TCefRTTIExtension.Create(const value: TValue; SyncMainThread: Boolean);
begin
inherited Create;
FCtx := TRttiContext.Create;
FSyncMainThread := SyncMainThread;
FValue := value;
end;
destructor TCefRTTIExtension.Destroy;
begin
FCtx.Free;
inherited Destroy;
end;
function TCefRTTIExtension.GetValue(pi: PTypeInfo; const v: ICefv8Value; var ret: TValue): Boolean;
function ProcessInt: Boolean;
var
sv: record
case byte of
0: (ub: Byte);
1: (sb: ShortInt);
2: (uw: Word);
3: (sw: SmallInt);
4: (si: Integer);
5: (ui: Cardinal);
end;
pd: PTypeData;
begin
pd := GetTypeData(pi);
if (v.IsInt or v.IsBool) and (v.GetIntValue >= pd.MinValue) and (v.GetIntValue <= pd.MaxValue) then
begin
case pd.OrdType of
otSByte: sv.sb := v.GetIntValue;
otUByte: sv.ub := v.GetIntValue;
otSWord: sv.sw := v.GetIntValue;
otUWord: sv.uw := v.GetIntValue;
otSLong: sv.si := v.GetIntValue;
otULong: sv.ui := v.GetIntValue;
end;
TValue.Make(@sv, pi, ret);
end else
Exit(False);
Result := True;
end;
function ProcessInt64: Boolean;
var
i: Int64;
begin
i := StrToInt64(v.GetStringValue); // hack
TValue.Make(@i, pi, ret);
Result := True;
end;
function ProcessUString: Boolean;
var
vus: string;
begin
if v.IsString then
begin
vus := v.GetStringValue;
TValue.Make(@vus, pi, ret);
end else
Exit(False);
Result := True;
end;
function ProcessLString: Boolean;
var
vas: AnsiString;
begin
if v.IsString then
begin
vas := AnsiString(v.GetStringValue);
TValue.Make(@vas, pi, ret);
end else
Exit(False);
Result := True;
end;
function ProcessWString: Boolean;
var
vws: WideString;
begin
if v.IsString then
begin
vws := v.GetStringValue;
TValue.Make(@vws, pi, ret);
end else
Exit(False);
Result := True;
end;
function ProcessFloat: Boolean;
var
sv: record
case byte of
0: (fs: Single);
1: (fd: Double);
2: (fe: Extended);
3: (fc: Comp);
4: (fcu: Currency);
end;
begin
if v.IsDouble or v.IsInt then
begin
case GetTypeData(pi).FloatType of
ftSingle: sv.fs := v.GetDoubleValue;
ftDouble: sv.fd := v.GetDoubleValue;
ftExtended: sv.fe := v.GetDoubleValue;
ftComp: sv.fc := v.GetDoubleValue;
ftCurr: sv.fcu := v.GetDoubleValue;
end;
TValue.Make(@sv, pi, ret);
end else
if v.IsDate then
begin
sv.fd := v.GetDateValue;
TValue.Make(@sv, pi, ret);
end else
Exit(False);
Result := True;
end;
function ProcessSet: Boolean;
var
sv: record
case byte of
0: (ub: Byte);
1: (sb: ShortInt);
2: (uw: Word);
3: (sw: SmallInt);
4: (si: Integer);
5: (ui: Cardinal);
end;
begin
if v.IsInt then
begin
case GetTypeData(pi).OrdType of
otSByte: sv.sb := v.GetIntValue;
otUByte: sv.ub := v.GetIntValue;
otSWord: sv.sw := v.GetIntValue;
otUWord: sv.uw := v.GetIntValue;
otSLong: sv.si := v.GetIntValue;
otULong: sv.ui := v.GetIntValue;
end;
TValue.Make(@sv, pi, ret);
end else
Exit(False);
Result := True;
end;
function ProcessVariant: Boolean;
var
vr : Variant;
i, j : Integer;
vl : TValue;
begin
VarClear(vr);
if v.IsString then vr := v.GetStringValue else
if v.IsBool then vr := v.GetBoolValue else
if v.IsInt then vr := v.GetIntValue else
if v.IsDouble then vr := v.GetDoubleValue else
if v.IsUndefined then TVarData(vr).VType := varEmpty else
if v.IsNull then TVarData(vr).VType := varNull else
if v.IsArray then
begin
i := 0;
j := v.GetArrayLength;
vr := VarArrayCreate([0, j], varVariant);
while (i < j) do
begin
if not GetValue(pi, v.GetValueByIndex(i), vl) then Exit(False);
VarArrayPut(vr, vl.AsVariant, i);
inc(i);
end;
end else
Exit(False);
TValue.Make(@vr, pi, ret);
Result := True;
end;
function ProcessObject: Boolean;
var
ud: ICefv8Value;
i: Pointer;
td: PTypeData;
rt: TRttiType;
begin
if v.IsObject then
begin
ud := v.GetUserData;
if (ud = nil) then Exit(False);
{$IFDEF TARGET_64BITS}
rt := StrToPtr(ud.GetValueByIndex(0).GetStringValue);
{$ELSE}
rt := TRttiType(ud.GetValueByIndex(0).GetIntValue);
{$ENDIF}
td := GetTypeData(rt.Handle);
if (rt.TypeKind = tkClass) and td.ClassType.InheritsFrom(GetTypeData(pi).ClassType) then
begin
{$IFDEF TARGET_64BITS}
i := StrToPtr(ud.GetValueByIndex(1).GetStringValue);
{$ELSE}
i := Pointer(ud.GetValueByIndex(1).GetIntValue);
{$ENDIF}
TValue.Make(@i, pi, ret);
end else
Exit(False);
end else
Exit(False);
Result := True;
end;
function ProcessClass: Boolean;
var
ud: ICefv8Value;
i: Pointer;
rt: TRttiType;
begin
if v.IsObject then
begin
ud := v.GetUserData;
if (ud = nil) then Exit(False);
{$IFDEF TARGET_64BITS}
rt := StrToPtr(ud.GetValueByIndex(0).GetStringValue);
{$ELSE}
rt := TRttiType(ud.GetValueByIndex(0).GetIntValue);
{$ENDIF}
if (rt.TypeKind = tkClassRef) then
begin
{$IFDEF TARGET_64BITS}
i := StrToPtr(ud.GetValueByIndex(1).GetStringValue);
{$ELSE}
i := Pointer(ud.GetValueByIndex(1).GetIntValue);
{$ENDIF}
TValue.Make(@i, pi, ret);
end else
Exit(False);
end else
Exit(False);
Result := True;
end;
function ProcessRecord: Boolean;
var
r: TRttiField;
f: TValue;
rec: Pointer;
begin
if v.IsObject then
begin
TValue.Make(nil, pi, ret);
{$IFDEF DELPHI15_UP}
rec := TValueData(ret).FValueData.GetReferenceToRawData;
{$ELSE}
rec := IValueData(TValueData(ret).FHeapData).GetReferenceToRawData;
{$ENDIF}
for r in FCtx.GetType(pi).GetFields do
begin
if not GetValue(r.FieldType.Handle, v.GetValueByKey(r.Name), f) then
Exit(False);
r.SetValue(rec, f);
end;
Result := True;
end else
Result := False;
end;
function ProcessInterface: Boolean;
begin
if pi = TypeInfo(ICefV8Value) then
begin
TValue.Make(@v, pi, ret);
Result := True;
end else
Result := False; // todo
end;
begin
case pi.Kind of
tkInteger, tkEnumeration: Result := ProcessInt;
tkInt64: Result := ProcessInt64;
tkUString: Result := ProcessUString;
tkLString: Result := ProcessLString;
tkWString: Result := ProcessWString;
tkFloat: Result := ProcessFloat;
tkSet: Result := ProcessSet;
tkVariant: Result := ProcessVariant;
tkClass: Result := ProcessObject;
tkClassRef: Result := ProcessClass;
tkRecord: Result := ProcessRecord;
tkInterface: Result := ProcessInterface;
else
Result := False;
end;
end;
function TCefRTTIExtension.SetValue(const v: TValue; var ret: ICefv8Value): Boolean;
function ProcessRecord: Boolean;
var
rf: TRttiField;
vl: TValue;
ud, v8: ICefv8Value;
rec: Pointer;
rt: TRttiType;
begin
ud := TCefv8ValueRef.NewArray(1);
rt := FCtx.GetType(v.TypeInfo);
{$IFDEF TARGET_64BITS}
ud.SetValueByIndex(0, TCefv8ValueRef.NewString(PtrToStr(rt)));
{$ELSE}
ud.SetValueByIndex(0, TCefv8ValueRef.NewInt(Integer(rt)));
{$ENDIF}
ret := TCefv8ValueRef.NewObject(nil, nil);
ret.SetUserData(ud);
{$IFDEF DELPHI15_UP}
rec := TValueData(v).FValueData.GetReferenceToRawData;
{$ELSE}
rec := IValueData(TValueData(v).FHeapData).GetReferenceToRawData;
{$ENDIF}
if FSyncMainThread then
begin
v8 := ret;
TThread.Synchronize(nil, procedure
var
rf: TRttiField;
o: ICefv8Value;
begin
for rf in rt.GetFields do
begin
vl := rf.GetValue(rec);
SetValue(vl, o);
v8.SetValueByKey(rf.Name, o, V8_PROPERTY_ATTRIBUTE_NONE);
end;
end)
end else
for rf in FCtx.GetType(v.TypeInfo).GetFields do
begin
vl := rf.GetValue(rec);
if not SetValue(vl, v8) then
Exit(False);
ret.SetValueByKey(rf.Name, v8, V8_PROPERTY_ATTRIBUTE_NONE);
end;
Result := True;
end;
function ProcessObject: Boolean;
var
m: TRttiMethod;
p: TRttiProperty;
fl: TRttiField;
f: ICefv8Value;
_r, _g, _s, ud: ICefv8Value;
_a: TCefv8ValueArray;
rt: TRttiType;
begin
rt := FCtx.GetType(v.TypeInfo);
ud := TCefv8ValueRef.NewArray(2);
{$IFDEF TARGET_64BITS}
ud.SetValueByIndex(0, TCefv8ValueRef.NewString(PtrToStr(rt)));
ud.SetValueByIndex(1, TCefv8ValueRef.NewString(PtrToStr(v.AsObject)));
{$ELSE}
ud.SetValueByIndex(0, TCefv8ValueRef.NewInt(Integer(rt)));
ud.SetValueByIndex(1, TCefv8ValueRef.NewInt(Integer(v.AsObject)));
{$ENDIF}
ret := TCefv8ValueRef.NewObject(nil, nil); // todo
ret.SetUserData(ud);
for m in rt.GetMethods do
if m.Visibility > mvProtected then
begin
f := TCefv8ValueRef.NewFunction(m.Name, Self);
ret.SetValueByKey(m.Name, f, V8_PROPERTY_ATTRIBUTE_NONE);
end;
for p in rt.GetProperties do
if (p.Visibility > mvProtected) then
begin
if _g = nil then _g := ret.GetValueByKey('__defineGetter__');
if _s = nil then _s := ret.GetValueByKey('__defineSetter__');
SetLength(_a, 2);
_a[0] := TCefv8ValueRef.NewString(p.Name);
if p.IsReadable then
begin
_a[1] := TCefv8ValueRef.NewFunction('$pg' + p.Name, Self);
_r := _g.ExecuteFunction(ret, _a);
end;
if p.IsWritable then
begin
_a[1] := TCefv8ValueRef.NewFunction('$ps' + p.Name, Self);
_r := _s.ExecuteFunction(ret, _a);
end;
end;
for fl in rt.GetFields do
if (fl.Visibility > mvProtected) then
begin
if _g = nil then _g := ret.GetValueByKey('__defineGetter__');
if _s = nil then _s := ret.GetValueByKey('__defineSetter__');
SetLength(_a, 2);
_a[0] := TCefv8ValueRef.NewString(fl.Name);
_a[1] := TCefv8ValueRef.NewFunction('$vg' + fl.Name, Self);
_r := _g.ExecuteFunction(ret, _a);
_a[1] := TCefv8ValueRef.NewFunction('$vs' + fl.Name, Self);
_r := _s.ExecuteFunction(ret, _a);
end;
Result := True;
end;
function ProcessClass: Boolean;
var
m: TRttiMethod;
f, ud: ICefv8Value;
c: TClass;
rt: TRttiType;
begin
c := v.AsClass;
rt := FCtx.GetType(c);
ud := TCefv8ValueRef.NewArray(2);
{$IFDEF TARGET_64BITS}
ud.SetValueByIndex(0, TCefv8ValueRef.NewString(PtrToStr(rt)));
ud.SetValueByIndex(1, TCefv8ValueRef.NewString(PtrToStr(c)));
{$ELSE}
ud.SetValueByIndex(0, TCefv8ValueRef.NewInt(Integer(rt)));
ud.SetValueByIndex(1, TCefv8ValueRef.NewInt(Integer(c)));
{$ENDIF}
ret := TCefv8ValueRef.NewObject(nil, nil); // todo
ret.SetUserData(ud);
if c <> nil then
begin
for m in rt.GetMethods do
if (m.Visibility > mvProtected) and (m.MethodKind in [mkClassProcedure, mkClassFunction]) then
begin
f := TCefv8ValueRef.NewFunction(m.Name, Self);
ret.SetValueByKey(m.Name, f, V8_PROPERTY_ATTRIBUTE_NONE);
end;
end;
Result := True;
end;
function ProcessVariant: Boolean;
var
vr: Variant;
begin
vr := v.AsVariant;
case TVarData(vr).VType of
varSmallint, varInteger, varShortInt:
ret := TCefv8ValueRef.NewInt(vr);
varByte, varWord, varLongWord:
ret := TCefv8ValueRef.NewUInt(vr);
varUString, varOleStr, varString:
ret := TCefv8ValueRef.NewString(vr);
varSingle, varDouble, varCurrency, varUInt64, varInt64:
ret := TCefv8ValueRef.NewDouble(vr);
varBoolean:
ret := TCefv8ValueRef.NewBool(vr);
varNull:
ret := TCefv8ValueRef.NewNull;
varEmpty:
ret := TCefv8ValueRef.NewUndefined;
else
ret := nil;
Exit(False)
end;
Result := True;
end;
function ProcessInterface: Boolean;
var
m: TRttiMethod;
f: ICefv8Value;
ud: ICefv8Value;
rt: TRttiType;
begin
if TypeInfo(ICefV8Value) = v.TypeInfo then
begin
ret := ICefV8Value(v.AsInterface);
Result := True;
end else
begin
rt := FCtx.GetType(v.TypeInfo);
ud := TCefv8ValueRef.NewArray(2);
{$IFDEF TARGET_64BITS}
ud.SetValueByIndex(0, TCefv8ValueRef.NewString(PtrToStr(rt)));
ud.SetValueByIndex(1, TCefv8ValueRef.NewString(PtrToStr(Pointer(v.AsInterface))));
{$ELSE}
ud.SetValueByIndex(0, TCefv8ValueRef.NewInt(Integer(rt)));
ud.SetValueByIndex(1, TCefv8ValueRef.NewInt(Integer(v.AsInterface)));
{$ENDIF}
ret := TCefv8ValueRef.NewObject(nil, nil);
ret.SetUserData(ud);
for m in rt.GetMethods do
if m.Visibility > mvProtected then
begin
f := TCefv8ValueRef.NewFunction(m.Name, Self);
ret.SetValueByKey(m.Name, f, V8_PROPERTY_ATTRIBUTE_NONE);
end;
Result := True;
end;
end;
function ProcessFloat: Boolean;
begin
if v.TypeInfo = TypeInfo(TDateTime) then
ret := TCefv8ValueRef.NewDate(TValueData(v).FAsDouble) else
ret := TCefv8ValueRef.NewDouble(v.AsExtended);
Result := True;
end;
begin
case v.TypeInfo.Kind of
tkUString, tkLString, tkWString, tkChar, tkWChar:
ret := TCefv8ValueRef.NewString(v.AsString);
tkInteger: ret := TCefv8ValueRef.NewInt(v.AsInteger);
tkEnumeration:
if v.TypeInfo = TypeInfo(Boolean) then
ret := TCefv8ValueRef.NewBool(v.AsBoolean) else
ret := TCefv8ValueRef.NewInt(TValueData(v).FAsSLong);
tkFloat: if not ProcessFloat then Exit(False);
tkInt64: ret := TCefv8ValueRef.NewDouble(v.AsInt64);
tkClass: if not ProcessObject then Exit(False);
tkClassRef: if not ProcessClass then Exit(False);
tkRecord: if not ProcessRecord then Exit(False);
tkVariant: if not ProcessVariant then Exit(False);
tkInterface: if not ProcessInterface then Exit(False);
else
Exit(False)
end;
Result := True;
end;
class function TCefRTTIExtension.Register(const name: ustring; const value: TValue; SyncMainThread: Boolean) : boolean;
var
TempCode : ustring;
TempHandler : ICefv8Handler;
begin
try
TempHandler := TCefRTTIExtension.Create(value, SyncMainThread);
TempCode := format('this.__defineSetter__(''%s'', function(v){native function $s();$s(v)});' +
'this.__defineGetter__(''%0:s'', function(){native function $g();return $g()});',
[name]);
Result := CefRegisterExtension(name, TempCode, TempHandler);
finally
TempHandler := nil;
end;
end;
{$IFDEF TARGET_64BITS}
class function TCefRTTIExtension.StrToPtr(const str: ustring): Pointer;
begin
HexToBin(PWideChar(str), @Result, SizeOf(Result));
end;
class function TCefRTTIExtension.PtrToStr(p: Pointer): ustring;
begin
SetLength(Result, SizeOf(p)*2);
BinToHex(@p, PWideChar(Result), SizeOf(p));
end;
{$ENDIF}
function TCefRTTIExtension.HandleProperties(const name : ustring;
const arguments : TCefv8ValueArray;
var retval : ICefv8Value): boolean;
begin
Result := True;
if name = '$g' then
SetValue(FValue, retval)
else if name = '$s' then
GetValue(FValue.TypeInfo, arguments[0], FValue)
else
Result := False;
end;
function TCefRTTIExtension.Execute(const name : ustring;
const object_ : ICefv8Value;
const arguments : TCefv8ValueArray;
var retval : ICefv8Value;
var exception : ustring): Boolean;
var
p: PChar;
ud: ICefv8Value;
rt: TRttiType;
val: TObject;
cls: TClass;
m: TRttiMethod;
pr: TRttiProperty;
vl: TRttiField;
args: array of TValue;
prm: TArray<TRttiParameter>;
i: Integer;
ret: TValue;
begin
Result := True;
if HandleProperties(name, arguments, retval) then
exit;
p := PChar(name);
m := nil;
if assigned(object_) and object_.IsValid then
begin
ud := object_.GetUserData;
if ud <> nil then
begin
{$IFDEF TARGET_64BITS}
rt := StrToPtr(ud.GetValueByIndex(0).GetStringValue);
{$ELSE}
rt := TRttiType(ud.GetValueByIndex(0).GetIntValue);
{$ENDIF}
case rt.TypeKind of
tkClass:
begin
{$IFDEF TARGET_64BITS}
val := StrToPtr(ud.GetValueByIndex(1).GetStringValue);
{$ELSE}
val := TObject(ud.GetValueByIndex(1).GetIntValue);
{$ENDIF}
cls := GetTypeData(rt.Handle).ClassType;
if p^ = '$' then
begin
inc(p);
case p^ of
'p':
begin
inc(p);
case p^ of
'g':
begin
inc(p);
pr := rt.GetProperty(p);
if FSyncMainThread then
begin
TThread.Synchronize(nil, procedure begin
ret := pr.GetValue(val);
end);
Exit(SetValue(ret, retval));
end else
Exit(SetValue(pr.GetValue(val), retval));
end;
's':
begin
inc(p);
pr := rt.GetProperty(p);
if GetValue(pr.PropertyType.Handle, arguments[0], ret) then
begin
if FSyncMainThread then
TThread.Synchronize(nil, procedure begin
pr.SetValue(val, ret) end) else
pr.SetValue(val, ret);
Exit(True);
end else
Exit(False);
end;
end;
end;
'v':
begin
inc(p);
case p^ of
'g':
begin
inc(p);
vl := rt.GetField(p);
if FSyncMainThread then
begin
TThread.Synchronize(nil, procedure begin
ret := vl.GetValue(val);
end);
Exit(SetValue(ret, retval));
end else
Exit(SetValue(vl.GetValue(val), retval));
end;
's':
begin
inc(p);
vl := rt.GetField(p);
if GetValue(vl.FieldType.Handle, arguments[0], ret) then
begin
if FSyncMainThread then
TThread.Synchronize(nil, procedure begin
vl.SetValue(val, ret) end) else
vl.SetValue(val, ret);
Exit(True);
end else
Exit(False);
end;
end;
end;
end;
end else
m := rt.GetMethod(name);
end;
tkClassRef:
begin
val := nil;
{$IFDEF TARGET_64BITS}
cls := StrToPtr(ud.GetValueByIndex(1).GetStringValue);
{$ELSE}
cls := TClass(ud.GetValueByIndex(1).GetIntValue);
{$ENDIF}
m := FCtx.GetType(cls).GetMethod(name);
end;
else
m := nil;
cls := nil;
val := nil;
end;
prm := m.GetParameters;
i := Length(prm);
if i = Length(arguments) then
begin
SetLength(args, i);
for i := 0 to i - 1 do
if not GetValue(prm[i].ParamType.Handle, arguments[i], args[i]) then
Exit(False);
case m.MethodKind of
mkClassProcedure, mkClassFunction:
if FSyncMainThread then
TThread.Synchronize(nil, procedure begin
ret := m.Invoke(cls, args) end) else
ret := m.Invoke(cls, args);
mkProcedure, mkFunction:
if (val <> nil) then
begin
if FSyncMainThread then
TThread.Synchronize(nil, procedure begin
ret := m.Invoke(val, args) end) else
ret := m.Invoke(val, args);
end else
Exit(False)
else
Exit(False);
end;
if m.MethodKind in [mkClassFunction, mkFunction] then
if not SetValue(ret, retval) then
Exit(False);
end else
Exit(False);
end else
Exit(False);
end else
Exit(False);
end;
{$ENDIF}
end.