2

我正在尝试使用提供的外部对象通过 TWebBrowser(使用 TEmbeddedWB)接收并可能发送复杂值。例如; 在javascript中,我会尝试使用带有数组作为参数的暴露方法:

var test = [123, 'abc'];
external.someFunction(test);

//Or something more complex
var complexObject = {
  someMethod : function(){ return 1; },
  someProperty : 123,
  someArray : ['xyz', 3.14]
}
external.someFunction(complexObject);

检查这两个示例的 VarType 告诉我这是一个 IDispatch。

function TSomeClass.someFunction(var Param : OleVariant) : OleVariant;
var
  vType : Integer;
begin
  vType := (VarType(Param) and VarTypeMask); //Says 9 (varDispatch)
  Result := true;
end;

我对 COM 并不完全熟悉,也不知道如何使用它。

任何帮助,将不胜感激。

4

4 回答 4

3

您可以将 JScript 对象视为任何其他 OleVariant COM 对象。在数组方面有一些陷阱(几乎任何 JScript 对象本质上都是一个稀疏数组)。

将 JScript 对象放入 OleVariant 后,您可以像调用任何普通代码一样简单地调用它(当然无需编译时间检查)。

下面是一些处理数组的代码:

type
  TJScriptArray = class
  private
    FArray:   IDispatchEx;
    FCount:   Integer;
    function  GetProperty( const AName: String ): OleVariant;
    function  GetItem(Index: Integer): OleVariant;
  public
    constructor Create( AObj: OleVariant );
    destructor  Destroy; override;
  public
    property  Count: Integer read FCount;
    property  Item[Index: Integer]: OleVariant read GetItem; default;
  end;

function  VarToDispatchEx( const AObject: OleVariant ): IDispatchEx;
begin
  Result := nil;
  if VarType( AObject ) <> varDispatch then
    Exit;
  Supports( IDispatch(AObject), IDispatchEx, Result );
end;

function  IsJScriptArray( const AObject: OleVariant ): Boolean;
var
  temp: IDispatchEx;
begin
  temp := VarToDispatchEx( AObject );
  Result := temp <> nil;
end;


constructor TJScriptArray.Create(AObj: OleVariant);
begin
  inherited Create;
  FArray := VarToDispatchEx( AObj );
  if FArray = nil then
    raise Exception.Create( 'TJscriptArray called with invalid parameters.' );
  FCount := GetProperty( 'length' );
end;

destructor TJScriptArray.Destroy;
begin
  inherited Destroy;
end;

function TJScriptArray.GetItem(Index: Integer): OleVariant;
begin
  if Index > FCount then
    raise Exception.Create( 'Index out of bounds.' );
  Result := GetProperty( IntToStr( Index ) );
end;

function TJScriptArray.GetProperty(const AName: String): OleVariant;
var
  sz: WideString;
  id: Integer;
  res: Variant;
  ei: TExcepInfo;
  params: TDispParams;
  hr: HResult;
begin
  {
    ACTION: return the specified property from the jscript array
    NOTE:   since a jscript array is a sparse array there may be
            gaps. In that case a null variant is returned. This is
            signalled by the name (id) not existing.
  }
  sz := AName;
  hr := FArray.GetDispID( PWideChar(sz), 0, id );
  if hr = disp_e_UnknownName then begin
    Result := Null;
    Exit;
    end
  else
    OleCheck( hr );

  VarClear( res );
  FillChar( ei, sizeof(ei), 0 );
  FillChar( params, sizeof(params), 0 );
  OleCheck( FArray.InvokeEx( id, 0, dispatch_PropertyGet, @params, @res, @ei, nil ) );
  Result := res;
end;
于 2009-06-01T13:15:27.123 回答
2

虽然我没有直接做你正在尝试的事情。

使用 Variant,您实际上可以动态访问方法和属性。

基本上我怀疑您应该能够直接访问所有内容。

Param.Someproperty
Param.SomeArray[1]
Param.SomeMethod();

如果你弄错了,你不会得到编译时错误,所以要小心。

例如,以下代码可以编译,但会给出无效变体操作的运行时错误,因为没有动态分配给该变量。

var
 vo : OleVariant;
 v  : Variant;
begin
  v.DoThis;
  vo.DoThat;
end;
于 2009-05-29T04:10:25.783 回答
1

您是否考虑过使用 JavaScript Object Notation (JSON) 序列化复杂数据?这将允许您序列化任意 JavaScript 对象,将它们作为简单的字符串传递并在 Delphi 代码中重构它们。

Delphi 2009 支持 JSON 作为新 DataSnap 的一部分(不确定独立使用是否容易)。还有一些可能有用的 Delphi JSON 实现:

出 lkjsonJSON - SuperObject

我不是 JSON 方面的专家,但它似乎是一种相对简单有效的跨语言数据交换解决方案。

大卫

于 2009-05-29T05:28:44.987 回答
0

Javascript 中的对象是关联数组,属性名是键:obj.prop等价于obj['prop'].

常规数组只是将索引存储为属性的对象,因此它们的行为类似于稀疏数组。

Delphi 的 OleVariants 允许直接访问属性,但仅当它们的名称是有效的Delphi 标识符时,它不喜欢使用数字索引作为属性名称(即obj.0不编译)。

可以读取具有无效标识符名称的属性,DISPATCH_PROPERTYGETRyan 的响应中那样调用。

然而,Delphi 在ComObj单元中包含适当的例程来直接执行此操作:

uses ComObj;

...

function TSomeClass.someFunction(var Param : OleVariant) : OleVariant;
begin
  ShowMessage(Param.someProperty); // 123
  ShowMessage(GetDispatchPropValue(Param, 'someProperty')); // 123

  ShowMessage(Param.someArray.length); // 2
  ShowMessage(GetDispatchPropValue(Param.someArray, '0')); // xyz

  Result := true;
end;
于 2013-07-24T20:05:47.673 回答