http://www.raysoftware.cn/?p=305
Delphi2010以后增加了新的RTTI信息,也就是通过RTTI可以在运行时获取/调用对象的公开成员或者函数.
ScriptControl可以添加外部的对象,这个对象是个IDispatch接口,脚本调用的时候实际上是调用IDispatch的Invoke方法.
那么我们只要实现了IDispatch的Invoke方法,在里面通过RTTI再转而调用Delphi对象的Public方法即可.通过这个可以代理任何Delphi的对象.
仅仅调用Delphi对象似乎还不够完美,对象事件如果能关联到脚本的函数就更好了.那好,封装一个事件代理的类就可以.
例子如下:
procedure
TForm1 . FormCreate(Sender: TObject);
begin Fscript := CreateScriptControl();
// 把Form1当成一个对象添加到Script中
Fscript . AddObject(Self . Name,
SA(Self), true );
Fscript . AddCode( 'function Form1_OnMouseMove(Sender,
shift, x, y)' // +
'{' // 在JS里面直接调用Form1上的任何Public的东西就都可以了,JS里面几乎没有类型的概念.事件的参数随便.计算也随便
+
'Form1.Button1.Caption = "x:"+x+";"+"y:"+y +";" + "shift:" + shift;'
// +
'}' //
+
'function Button1_Click(Sender)'
// +
'{' //调用Delphi对象的方法
+
'Form1.SetBounds(0,0,800,480);'
// +
'}' //
);
//关联Delphi的事件到JS的函数
Self . OnMouseMove := TEventDispatch . Create<TMouseMoveEvent>(Self,
Fscript, 'Form1_OnMouseMove' );
Button1 . OnClick := TEventDispatch . Create<TNotifyEvent>(Button1,
Fscript, 'Button1_Click' );
end ; |
看上去很爽吧.
不过这个仅供我自己玩的,代码实现的比较毛糙,也没有经过严格的测试,甚至自己也没从头到尾再检查一次.如果有需要实用的朋友最好谨慎,肯定有细节问题要解决.
另外这个ScriptControl仅仅有32位的,在64位Windows上的system32里面并没有这个DLL,仅仅在SysWow64中才有.也就是说如果你要开发64位Windows程序就不能用了.当然如果是在64位Windows中运行的32位程序则没问题.
下面是代码,写的比较丑.
{ 让Delphi使用windows自带的scriptcontrol,在javascript中可以调用delphi的对象,
并且可以使用事件.
wr960204武稀松 2013
} unit
ScriptObjectUtilsWithRTTI; interface { 是否使用外部的MSScriptControl_TLB单元.我把这个单元的接口声明都放在后面了,
可以避免引入ActiveX等单元
如果觉得我的声明太旧或者有问题,可以打开这个开关,使用外部自己Import生成的单元
} { .$DEFINE Use_External_TLB } { 这个开关是使用LoadLibrary方式加载COM DLL,也就及时COM组件没有注册也可以创建COM对象 } {$DEFINE COMOBJ_FROMDLL} uses {$IFDEF Use_External_TLB} MSScriptControl_TLB,
{ $ENDIF }
System . ObjAuto,
System . Classes, System . RTTI,
System . Variants,
Winapi . Windows, Winapi . ActiveX,
System . TypInfo;
type {$REGION 'MSScriptControl_TLB'} {$IFDEF Use_External_TLB} IScriptControl = MSScriptControl_TLB . IScriptControl;
{ $ELSE }
ScriptControlStates = TOleEnum;
IScriptModuleCollection = IDispatch;
IScriptError = IDispatch;
IScriptProcedureCollection = IDispatch;
IScriptControl =
interface (IDispatch)
[ '{0E59F1D3-1FBE-11D0-8FF2-00A0D10038BC}' ]
function
Get_Language: WideString ; safecall;
procedure
Set_Language( const
pbstrLanguage: WideString ); safecall;
function
Get_State: ScriptControlStates; safecall; procedure
Set_State(pssState: ScriptControlStates); safecall;
procedure
Set_SitehWnd(phwnd: Integer ); safecall;
function
Get_SitehWnd: Integer ; safecall;
function
Get_Timeout: Integer ; safecall;
procedure
Set_Timeout(plMilleseconds: Integer ); safecall;
function
Get_AllowUI: WordBool; safecall; procedure
Set_AllowUI(pfAllowUI: WordBool); safecall; function
Get_UseSafeSubset: WordBool; safecall; procedure
Set_UseSafeSubset(pfUseSafeSubset: WordBool); safecall;
function
Get_Modules: IScriptModuleCollection; safecall;
function
Get_Error: IScriptError; safecall; function
Get_CodeObject: IDispatch; safecall; function
Get_Procedures: IScriptProcedureCollection; safecall;
procedure
_AboutBox; safecall; procedure
AddObject( const
Name: WideString ;
const Object_: IDispatch;
AddMembers: WordBool); safecall;
procedure
Reset; safecall; procedure
AddCode( const
Code: WideString ); safecall;
function
Eval( const
Expression: WideString ): OleVariant; safecall;
procedure
ExecuteStatement( const
Statement: WideString ); safecall;
function
Run( const
ProcedureName: WideString ;
var Parameters: PSafeArray)
: OleVariant; safecall;
property
Language: WideString
read Get_Language write
Set_Language; property
State: ScriptControlStates read Get_State write
Set_State; property
SitehWnd: Integer
read Get_SitehWnd write
Set_SitehWnd; property
Timeout: Integer
read Get_Timeout write
Set_Timeout; property
AllowUI: WordBool read Get_AllowUI write
Set_AllowUI; property
UseSafeSubset: WordBool read Get_UseSafeSubset
write
Set_UseSafeSubset; property
Modules: IScriptModuleCollection read Get_Modules;
property
Error: IScriptError read Get_Error; property
CodeObject: IDispatch read Get_CodeObject; property
Procedures: IScriptProcedureCollection read Get_Procedures;
end ;
{ $ENDIF }
{$ENDREGION 'MSScriptControl_TLB'} { 事件代理的泛型类,可以把Delphi的事件映射到Javascript的函数上.
注意,这是一个TComponent的派生类.如果不指定Ownder的话要手工释放的.
} TEventDispatch =
class (TComponent)
private FScriptControl: IScriptControl;
FScriptFuncName:
string ;
FInternalDispatcher: TMethod;
FRttiContext: TRttiContext;
FRttiType: TRttiMethodType;
procedure
InternalInvoke(Params: PParameters; StackSize:
Integer ); function
ValueToVariant(Value: TValue): Variant; constructor
Create(AOwner: TComponent; ATTypeInfo: PTypeInfo);
reintroduce; overload;
public class
function Create<T>(AOwner: TComponent; ScriptControl: IScriptControl;
ScriptFuncName:
String ): T; reintroduce; overload;
destructor
Destroy; override; end ;
{ 很普通,创建一个MSWindows自带的ScriptControl实例,默认脚本是Javascript } function
CreateScriptControl(ScriptName: String
= 'javascript' ): IScriptControl;
{ 创建对象的IDispatch的代理, Owned表示这个IDispatch拥有代理对象的生杀大权,当代理的IDispatch
释放的时候这个Obj也会被释放掉 } function
SA(Obj: TObject; Owned: Boolean ): IDispatch; overload;
{ 创建对象的IDispatch的代理 } function
SA(Obj: TObject): IDispatch; overload; implementation uses {$IFNDEF COMOBJ_FROMDLL} System . Win . ComObj,
{ $ENDIF }
System . SysUtils;
function
CreateScriptControl(ScriptName: String ): IScriptControl;
const CLASS_ScriptControl: TGUID =
'{0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC}' ;
{$IFDEF COMOBJ_FROMDLL} MSSCRIPTMODULE =
'msscript.ocx' ;
var DllGetClassObject:
function ( const
clsid, IID: TGUID; var
Obj) : HRESULT; stdcall;
ClassFactory: IClassFactory;
hLibInst: HMODULE;
hr: HRESULT;
begin Result :=
nil ;
hLibInst := GetModuleHandle(MSSCRIPTMODULE);
if
hLibInst = 0
then hLibInst := LoadLibrary(MSSCRIPTMODULE);
if
hLibInst = 0
then Exit;
DllGetClassObject := GetProcAddress(hLibInst,
'DllGetClassObject' );
if
Assigned(DllGetClassObject) then begin hr := DllGetClassObject(CLASS_ScriptControl, IClassFactory, ClassFactory);
if
hr = S_OK then begin hr := ClassFactory . CreateInstance( nil ,
IScriptControl, Result); if
(hr = S_OK) and
(Result <> nil )
then Result . Language := ScriptName;
end ;
end ;
end ;
{ $ELSE }
begin Result := CreateComObject(CLASS_ScriptControl)
as IScriptControl;
if
Result <> nil
then Result . Language := ScriptName;
end ;
{ $ENDIF }
type TDispatchKind = (dkMethod, dkProperty, dkSubComponent);
TDispatchInfo =
record Instance: TObject;
case
Kind: TDispatchKind of dkMethod:
(MethodInfo: TRttiMethod);
dkProperty:
(PropInfo: TRttiProperty);
dkSubComponent:
(ComponentInfo: NativeInt);
end ;
TDispatchInfos =
array of
TDispatchInfo; {
IDispatch代理类.通过RTTI可以把Delphi对象的成员/属性/函数映射给IDispatch.
而且忽略调用协议.
} TScriptObjectAdapter =
class (TInterfacedObject, IDispatch)
private //
FRttiContext: TRttiContext;
FRttiType: TRttiType;
FDispatchInfoCount:
Integer ;
FDispatchInfos: TDispatchInfos;
FComponentNames: TStrings;
FInstance: TObject;
FOwned:
Boolean ;
function
AllocDispID(AKind: TDispatchKind; Value: Pointer ;
AInstance: TObject): TDispID;
protected property
Instance: TObject read FInstance; public { IDispatch } function
GetIDsOfNames( const
IID: TGUID; Names: Pointer ; NameCount:
Integer ;
LocaleID:
Integer ; DispIDs:
Pointer ): HRESULT; virtual; stdcall;
function
GetTypeInfo(Index: Integer ; LocaleID:
Integer ; out TypeInfo)
: HRESULT; stdcall;
function
GetTypeInfoCount(out Count: Integer ): HRESULT; stdcall;
function
Invoke(DispID: Integer ;
const IID: TGUID; LocaleID:
Integer ;
Flags:
Word ;
var Params; VarResult:
Pointer ; ExcepInfo:
Pointer ;
ArgErr:
Pointer ): HRESULT; virtual; stdcall;
public constructor
Create(Instance: TObject; Owned: Boolean
= False );
destructor
Destroy; override; end ;
function
SA(Obj: TObject; Owned: Boolean ): IDispatch;
begin Result := TScriptObjectAdapter . Create(Obj, Owned);
end ;
function
SA(Obj: TObject): IDispatch; begin Result := TScriptObjectAdapter . Create(Obj,
False );
end ;
const ofDispIDOffset =
100 ; { TScriptObjectAdapter } function
TScriptObjectAdapter . AllocDispID(AKind: TDispatchKind; Value:
Pointer ;
AInstance: TObject): TDispID;
var I:
Integer ;
dispatchInfo: TDispatchInfo;
begin for
I := FDispatchInfoCount - 1
downto 0
do with
FDispatchInfos[I] do if
(Kind = AKind) and
(MethodInfo = Value) then begin // Already have a dispid for this methodinfo
Result := ofDispIDOffset + I;
Exit;
end ;
if
FDispatchInfoCount = Length(FDispatchInfos) then SetLength(FDispatchInfos, Length(FDispatchInfos) +
10 ); Result := ofDispIDOffset + FDispatchInfoCount;
with
dispatchInfo do begin Instance := AInstance;
Kind := AKind;
MethodInfo := Value;
end ;
FDispatchInfos[FDispatchInfoCount] := dispatchInfo;
Inc(FDispatchInfoCount);
end ;
constructor
TScriptObjectAdapter . Create(Instance: TObject; Owned:
Boolean );
begin inherited
Create; FComponentNames := TStringList . Create;
FInstance := Instance;
FOwned := Owned;
FRttiContext := TRttiContext . Create;
FRttiType := FRttiContext . GetType(FInstance . ClassType);
end ;
destructor
TScriptObjectAdapter . Destroy;
begin if
FOwned then FInstance . Free;
FRttiContext . Free;
FComponentNames . Free;
inherited
Destroy; end ;
function
TScriptObjectAdapter . GetIDsOfNames( const
IID: TGUID; Names: Pointer ;
NameCount, LocaleID:
Integer ; DispIDs:
Pointer ): HRESULT;
type PNames = ^TNames;
TNames =
array [ 0
.. 100 ]
of POleStr;
PDispIDs = ^TDispIDs;
TDispIDs =
array [ 0
.. 100 ]
of Cardinal ;
var Name:
String ;
MethodInfo: TRttiMethod;
PropertInfo: TRttiProperty;
ComponentInfo: TComponent;
lDispId: TDispID;
begin Result := S_OK;
lDispId := - 1 ;
Name := WideCharToString(PNames(Names)^[ 0 ]);
MethodInfo := FRttiType . GetMethod(Name);
// MethodInfo.Invoke(FInstance, ['']);
if
MethodInfo <> nil
then begin lDispId := AllocDispID(dkMethod, MethodInfo, FInstance);
end else begin PropertInfo := FRttiType . GetProperty(Name);
if
PropertInfo <> nil
then begin lDispId := AllocDispID(dkProperty, PropertInfo, FInstance);
end else
if FInstance
is TComponent
then begin ComponentInfo := TComponent(FInstance).FindComponent(Name);
if
ComponentInfo <> nil
then begin lDispId := AllocDispID(dkSubComponent,
Pointer (FComponentNames . Add(Name)
), FInstance);
end ;
end ;
end ;
if
lDispId >= ofDispIDOffset then begin Result := S_OK;
PDispIDs(DispIDs)^[ 0 ] := lDispId;
end ;
end ;
function
TScriptObjectAdapter . GetTypeInfo(Index, LocaleID:
Integer ;
out TypeInfo): HRESULT;
begin Result := E_NOTIMPL;
end ;
function
TScriptObjectAdapter . GetTypeInfoCount(out Count:
Integer ): HRESULT;
begin Result := E_NOTIMPL;
end ;
function
TScriptObjectAdapter . Invoke(DispID:
Integer ;
const IID: TGUID;
LocaleID:
Integer ; Flags:
Word ;
var Params;
VarResult, ExcepInfo, ArgErr:
Pointer ): HRESULT;
type PVariantArray = ^TVariantArray;
TVariantArray =
array [ 0
.. 65535 ]
of Variant;
PIntegerArray = ^TIntegerArray;
TIntegerArray =
array [ 0
.. 65535 ]
of Integer ;
var Parms: PDispParams;
TempRet: Variant;
dispatchInfo: TDispatchInfo;
lParams: TArray<TValue>;
paramInfos: TArray<TRttiParameter>;
I:
Integer ;
component: TComponent;
propertyValue: TValue;
_SetValue: NativeInt;
tmpv: Variant;
begin Result := S_OK;
Parms := @Params;
try if
VarResult = nil
then VarResult := @TempRet;
if
(DispID - ofDispIDOffset >= 0 )
and (DispID - ofDispIDOffset < FDispatchInfoCount)
then begin dispatchInfo := FDispatchInfos[DispID - ofDispIDOffset];
case
dispatchInfo . Kind
of dkProperty:
begin if
Flags and
(DISPATCH_PROPERTYPUTREF or
DISPATCH_PROPERTYPUT) <> 0 then if
(Parms . cNamedArgs <>
1 ) or (PIntegerArray(Parms . rgdispidNamedArgs)^[ 0 ]
<> DISPID_PROPERTYPUT)
then Result := DISP_E_MEMBERNOTFOUND
else begin propertyValue := TValue . Empty;
case
dispatchInfo . PropInfo . PropertyType . Handle^.Kind
of tkInt64, tkInteger:
propertyValue :=
TValue . FromOrdinal
(dispatchInfo . PropInfo . PropertyType . Handle,
PVariantArray(Parms . rgvarg)^[ 0 ]);
tkFloat:
propertyValue := TValue . From< Extended >
(PVariantArray(Parms . rgvarg)^[ 0 ]);
tkString, tkUString, tkLString, tkWString:
propertyValue :=
TValue . From< String >(PVariantArray(Parms . rgvarg)^[ 0 ]);
tkSet:
begin _SetValue := PVariantArray(Parms . rgvarg)^[ 0 ];
TValue . Make(_SetValue,
dispatchInfo . PropInfo . PropertyType . Handle,
propertyValue);
end ;
else propertyValue :=
TValue . FromVariant(PVariantArray(Parms . rgvarg)^[ 0 ]);
end ;
dispatchInfo . PropInfo . SetValue(dispatchInfo . Instance,
propertyValue);
end else
if Parms . cArgs <>
0 then Result := DISP_E_BADPARAMCOUNT
else
if dispatchInfo . PropInfo . PropertyType . Handle^.Kind
= tkClass then POleVariant(VarResult)^ :=
SA(dispatchInfo . PropInfo . GetValue(dispatchInfo . Instance)
.AsObject())
as IDispatch
else POleVariant(VarResult)^ := dispatchInfo . PropInfo . GetValue
(dispatchInfo . Instance).AsVariant;
end ;
dkMethod:
begin paramInfos := dispatchInfo . MethodInfo . GetParameters;
SetLength(lParams, Length(paramInfos));
for
I := Low(paramInfos) to
High(paramInfos) do if
I < Parms . cArgs
then begin //因为IDispatch是COM对象,一般是stdcall或者safecall,参数是由右到左传递的
tmpv := PVariantArray(Parms . rgvarg)^[Parms . cArgs
- 1 - I];
lParams[I] := TValue . FromVariant(tmpv);
end else
//不足的参数补空 begin TValue . Make( 0 ,
paramInfos[I].ParamType . Handle, lParams[I]);
end ;
if
(dispatchInfo . MethodInfo . ReturnType <>
nil )
and (dispatchInfo . MethodInfo . ReturnType . Handle^.Kind
= tkClass) then begin POleVariant(VarResult)^ :=
SA(dispatchInfo . MethodInfo . Invoke(dispatchInfo . Instance,
lParams).AsObject())
as IDispatch;
end else begin POleVariant(VarResult)^ := dispatchInfo . MethodInfo . Invoke
(dispatchInfo . Instance, lParams).AsVariant();
end ;
end ;
dkSubComponent:
begin component := TComponent(dispatchInfo . Instance)
.FindComponent(FComponentNames[dispatchInfo . ComponentInfo]);
if
component = nil
then Result := DISP_E_MEMBERNOTFOUND;
POleVariant(VarResult)^ := SA(component)
as IDispatch;
end ;
end ;
end else Result := DISP_E_MEMBERNOTFOUND;
except if
ExcepInfo <> nil
then begin FillChar(ExcepInfo^, SizeOf(TExcepInfo),
0 ); with
TExcepInfo(ExcepInfo^) do begin bstrSource := StringToOleStr(ClassName);
if
ExceptObject is
Exception then bstrDescription := StringToOleStr(Exception(ExceptObject).Message);
scode := E_FAIL;
end ;
end ;
Result := DISP_E_EXCEPTION;
end ;
end ;
{ TEventDispatch<T> } class
function TEventDispatch . Create<T>(AOwner: TComponent;
ScriptControl: IScriptControl; ScriptFuncName:
String ): T;
type PT = ^T;
var ed: TEventDispatch;
begin ed := TEventDispatch . Create(AOwner, TypeInfo(T));
ed . FScriptControl := ScriptControl;
ed . FScriptFuncName := ScriptFuncName;
Result := PT(@ed . FInternalDispatcher)^;
end ;
constructor
TEventDispatch . Create(AOwner: TComponent; ATTypeInfo: PTypeInfo);
var LRttiType: TRttiType;
begin FRttiContext := TRttiContext . Create;
LRttiType := FRttiContext . GetType(ATTypeInfo);
if
not (LRttiType
is TRttiMethodType)
then begin raise
Exception . Create( 'T only is Method(Member function)!' );
end ;
FRttiType := TRttiMethodType(LRttiType);
Inherited
Create(AOwner); FInternalDispatcher := CreateMethodPointer(InternalInvoke,
GetTypeData(FRttiType . Handle));
end ;
destructor
TEventDispatch . Destroy;
begin ReleaseMethodPointer(FInternalDispatcher);
inherited
Destroy; end ;
function
TEventDispatch . ValueToVariant(Value: TValue): Variant;
var _SetValue: Int64Rec;
begin Result := EmptyParam;
case
Value . TypeInfo^.Kind
of tkClass:
Result := SA(Value . AsObject);
tkInteger:
Result := Value . AsInteger;
tkString, tkLString, tkChar, tkUString:
Result := Value . AsString;
tkSet:
begin Value . ExtractRawData(@_SetValue);
case
Value . DataSize
of 1 :
Result := _SetValue . Bytes[ 0 ];
2 :
Result := _SetValue . Words[ 0 ];
4 :
Result := _SetValue . Cardinals[ 0 ];
8 :
Result :=
Int64 (_SetValue);
end ;
end ;
else Result := Value . AsVariant;
end ;
end ;
function
GetParamSize(TypeInfo: PTypeInfo): Integer ;
begin if
TypeInfo = nil
then Exit( 0 );
case
TypeInfo^.Kind of tkInteger, tkEnumeration, tkChar, tkWChar, tkSet:
case
GetTypeData(TypeInfo)^.OrdType of otSByte, otUByte:
Exit( 1 );
otSWord, otUWord:
Exit( 2 );
otSLong, otULong:
Exit( 4 );
else Exit( 0 );
end ;
tkFloat:
case
GetTypeData(TypeInfo)^.FloatType of ftSingle:
Exit( 4 );
ftDouble:
Exit( 8 );
ftExtended:
Exit(SizeOf( Extended ));
ftComp:
Exit( 8 );
ftCurr:
Exit( 8 );
else Exit( 0 );
end ;
tkClass, tkClassRef:
Exit(SizeOf( Pointer ));
tkInterface:
Exit(-SizeOf( Pointer ));
tkMethod:
Exit(SizeOf(TMethod));
tkInt64:
Exit( 8 );
tkDynArray, tkUString, tkLString, tkWString:
Exit(-SizeOf( Pointer ));
tkString:
Exit(GetTypeData(TypeInfo)^.MaxLength +
1 ); tkPointer:
Exit(SizeOf( Pointer ));
tkRecord:
if
IsManaged(TypeInfo) then Exit(-GetTypeData(TypeInfo)^.RecSize)
else Exit(GetTypeData(TypeInfo)^.RecSize);
tkArray:
Exit(GetTypeData(TypeInfo)^.ArrayData . Size);
tkVariant:
Exit(-SizeOf(Variant));
else Exit( 0 );
end ;
end ;
procedure
TEventDispatch . InternalInvoke(Params: PParameters;
StackSize:
Integer );
var lRttiParameters, tmp: TArray<TRttiParameter>;
lRttiParam: TRttiParameter;
lParamValues: TArray<TValue>;
I, ParamSize:
Integer ;
PStack: PByte;
test:
string ;
ParamIsByRef:
Boolean ;
RegParamIndexs:
array [ 0
.. 2 ]
of Byte ;
RegParamIndex:
Integer ;
v, tmpv: Variant;
ParameterArray: PSafeArray;
begin tmp := FRttiType . GetParameters;
SetLength(lRttiParameters, Length(tmp) +
1 ); lRttiParameters[ 0 ] :=
nil ;
for
I := Low(tmp) to
High(tmp) do lRttiParameters[I +
1 ] := tmp[I];
SetLength(lParamValues, Length(lRttiParameters));
PStack := @Params . Stack[ 0 ];
if
(FRttiType . CallingConvention = ccReg)
then begin // 看那些参数用了寄存器传输
FillChar(RegParamIndexs, SizeOf(RegParamIndexs), - 1 );
RegParamIndexs[ 0 ] :=
0 ; RegParamIndex :=
1 ; for
I := 1
to High(lRttiParameters) do begin lRttiParam := lRttiParameters[I];
ParamSize := GetParamSize(lRttiParam . ParamType . Handle);
ParamIsByRef := (lRttiParam <>
nil )
and (([pfVar, pfConst, pfOut] * lRttiParam . Flags) <> []);
if
((ParamSize <= SizeOf( Pointer ))
and ( not (lRttiParam . ParamType . Handle . Kind
in [tkFloat])))
or (ParamIsByRef)
then begin RegParamIndexs[RegParamIndex] := I;
if
(RegParamIndex = High(RegParamIndexs)) or
(I = High(lRttiParameters)) then Break;
Inc(RegParamIndex);
end ;
end ;
for
I := High(lRttiParameters) downto
Low(lRttiParameters) do begin lRttiParam := lRttiParameters[I];
if
I = 0
then TValue . Make(Params . EAXRegister,
TypeInfo(TObject), lParamValues[I]) else begin ParamIsByRef := (lRttiParam <>
nil )
and (([pfVar, pfConst, pfOut] * lRttiParam . Flags) <> []);
ParamSize := GetParamSize(lRttiParam . ParamType . Handle);
if
(ParamSize < SizeOf( Pointer ))
or (ParamIsByRef)
then ParamSize := SizeOf( Pointer );
if
(I in
[RegParamIndexs[ 0 ], RegParamIndexs[ 1 ], RegParamIndexs[ 2 ]])
then begin if
ParamIsByRef then begin TValue . Make( Pointer (Params . Registers[RegParamIndex]),
lRttiParameters[I].ParamType . Handle, lParamValues[I]);
end else begin TValue . Make(Params . Registers[RegParamIndex],
lRttiParameters[I].ParamType . Handle, lParamValues[I]);
end ;
Dec(RegParamIndex);
end else begin if
ParamIsByRef then TValue . Make(PPointer(PStack)^, lRttiParameters[I].ParamType . Handle,
lParamValues[I])
else TValue . Make(PStack, lRttiParameters[I].ParamType . Handle,
lParamValues[I]);
Inc(PStack, ParamSize);
end ;
end ;
end ;
end else begin for
I := Low(lRttiParameters) to
High(lRttiParameters) do begin ParamIsByRef := (lRttiParameters[I] <>
nil )
and (([pfVar, pfConst, pfOut] * lRttiParameters[I].Flags) <> []);
if
I = 0
then begin
// Self ParamSize := SizeOf(TObject);
TValue . Make(PStack, TypeInfo(TObject), lParamValues[I]);
end else begin ParamSize := GetParamSize(lRttiParameters[I].ParamType . Handle);
if
ParamSize < SizeOf( Pointer )
then ParamSize := SizeOf( Pointer );
// TValue.Make(PStack, lRttiParameters[I].ParamType.Handle, lParamValues[I]);
if
ParamIsByRef then TValue . Make(PPointer(PStack)^, lRttiParameters[I].ParamType . Handle,
lParamValues[I])
else TValue . Make(PStack, lRttiParameters[I].ParamType . Handle,
lParamValues[I]);
end ;
Inc(PStack, ParamSize);
end ;
end ;
if
(FScriptControl <> nil )
and (FScriptFuncName <>
'' ) then begin v := VarArrayCreate([ 0 , Length(lParamValues) -
1 ], varVariant);
for
I := 1
to Length(lParamValues) - 1
do begin test := lRttiParameters[I].Name;
tmpv := ValueToVariant(lParamValues[I]);
v[I -
1 ] := tmpv;
end ;
ParameterArray := PSafeArray(TVarData(v).VArray);
FScriptControl . Run(FScriptFuncName, ParameterArray);
end ;
end ; |