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;

最新文章

  1. windows下mysql数据库定时备份。
  2. 监控jvm的一个坑
  3. 【转】png优化相关
  4. android 获取系统联系人 完全解析
  5. jstl表达式替换某些字符
  6. matlab 相关代码记录
  7. c语言之fopen参数(r+,w+,a+)
  8. QTP场景恢复之用例失败自动截图
  9. WPF发布程序后未授予信任的解决办法
  10. PowerManager和PowerManager.WakeLock详解
  11. Windows下ToroiseSVN基本使用&amp;&amp;在Visual studio中使用SVN
  12. laravle框架报错Malformed UTF-8 characters, possibly incorrectly encoded
  13. RabbitMQ Dead Lettering(死信)
  14. .18-浅析webpack源码之compile流程-rules参数处理(1)
  15. AGC019
  16. [ACM] poj 2017 Speed Limit
  17. Timer类注意事项
  18. R:魔兽世界终极版
  19. 异常:Batch update returned unexpected row count from update [0]; actual row count: 0;
  20. mediawiki安装实现代码高亮的插件GeSHiHighLight

热门文章

  1. PHP curl_reset函数
  2. python中匿名函数lambda如何用
  3. python format函数的使用
  4. centos 安装 Lamp(Linux + Apache + PHP) 并安装 phpmyadmin
  5. Linux命令 touch
  6. 使用postman做接口测试----柠檬不萌!
  7. SpringMVC入门及拦截器
  8. ACM之map常用用法
  9. 使用allure2生成精美报告
  10. HTML CSS的中英文对照