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;

奇技淫巧之Delphi和JavaScript互通的更多相关文章

  1. delphi与javascript互通

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  2. Delphi与Javascript的交互

    网络上也有人写了关于Delphi与Javascript的文章,其大多数使用ScriptControl等,均无法达到与Delphi自身融合的效果.我也是在翻阅自己的组件库的时候发现了这个以前收集来的代码 ...

  3. 开源项目ScriptGate,Delphi与JavaScript相互调用的神器

    ScriptGate是一个实现TWebBrowser上的JavaScript和Delphi代码相互调用的库,具体在这里:https://bitbucket.org/freeonterminate/sc ...

  4. WebViewJavascriptBridge-Obj-C和JavaScript互通消息的桥梁

    转载至:http://www.cocoachina.com/ios/20150629/12248.html 译者:@coderyi9 本文翻译自Marcus Westin的开源框架WebViewJav ...

  5. Delphi,C语言互通脚本引擎研究

    基于大神akuma的脚本引擎. 下面是demo

  6. 教程-delphi的开源json库:superobject,用法简介

    困惑一天的问题 一个语句搞定了... 回头细说. superobject中的{$DEFINE UNICODE} 就是它,这是json官方推荐的Delphi处理json的包,地址: http://www ...

  7. Delphi实现HTMLWebBrowser实现HTML界面

    HTML的界面有以下特点:图文混排,格式灵活,可以包含Flash.声音和视频等,实现图文声像的多媒体界面,而且易于建立和维护.另外,HTML的显示环境一般机器上都具备,通常不需要安装额外的软件.当然, ...

  8. javascript + sql编写SQL客户端工具tabris

    祝大家2018新年快乐, 前不久发现了一个创意的脚本JtSQL(java编写) 开源地址为:https://github.com/noear/JtSQL JtSQL 特点:*.结合了JS.SQL.模板 ...

  9. JS_call_APP native 与 html的交互

    1.***** 特点:下个版本的交互准备使用这个(http://www.knowsky.com/884428.html) https://github.com/lifei321/JS-OC http: ...

随机推荐

  1. 使用 v-html 绑定值

    <div id="app03"> <div v-html="message"></div> <!--这里使用v-htm ...

  2. Mac 终端SSH连接服务器

    1.打开终端 2.看是否是处于root目录下,是看第3步:否则执行sudo -i,输入电脑密码 3.执行 ssh root@host(host:ip地址或者域名) 4.如果不是第一次,则已成功连接.第 ...

  3. 匹配Luhn算法:可用于检测银行卡卡号

    匹配Luhn算法:可用于检测银行卡卡号 /** * http://www.cnblogs.com/JnKindle/p/5798974.html * * 匹配Luhn算法:可用于检测银行卡卡号 * * ...

  4. 【Flutter学习】事件处理与通知之通知(Notification)

    一,概述 Notification是Flutter中一个重要的机制,在Widget树中,每一个节点都可以分发通知,通知会沿着当前节点(context)向上传递,所有父节点都可以通过Notificati ...

  5. springcloud的config

    CONFIG服务端 加入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <arti ...

  6. layui弹出层回调的使用

    <%@page language="java" contentType="text/html; charset=UTF-8"%> <%@ in ...

  7. Struts1.3——使用MyEclipse集成工具开发Struts

    前面两篇通过手工写代码,手工配置struts-config.xml文件的方法来开发了一个最简单的struts项目,通过手工的方式旨在学习底层原理细节.当熟悉了以后,我们就不需要再通过纯手工的方式来开发 ...

  8. python学习笔记:模块——os模块(操作文件/目录)

    import os os.rename(old,new) #重命名文件或目录 os.remove(f)#删除文件 os.mkdir('china/beijing') #创建文件夹 os.makedir ...

  9. activiti7完成当前任务

    package com.zcc.acvitivi; import org.activiti.engine.ProcessEngine;import org.activiti.engine.Proces ...

  10. 厉害了,Spring团队又开源 nohttp 项目!

    作者:h4cd 来源:https://www.oschina.net/news/107377/spring-opensource-nohttp Spring 团队开源 nohttp 项目,用以查找.替 ...