Получение сложных значений JavaScript через внешний интерфейс - PullRequest
2 голосов
/ 29 мая 2009

Я пытаюсь получить и потенциально отправить сложные значения через 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 ]

3 голосов
/ 01 июня 2009

Вы можете обрабатывать объект 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;
2 голосов
/ 29 мая 2009

Хотя я прямо не сделал то, что вы пытаетесь.

с помощью Варианта вы можете на самом деле динамически обращаться к методам и свойствам.

В принципе, я подозреваю, что вы должны иметь доступ ко всему напрямую.

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

Вы не получите ошибок времени компиляции, если вы ошиблись, поэтому будьте осторожны.

Например, следующий код компилируется, но выдает ошибку во время выполнения неверной операции варианта, поскольку для этой переменной динамически ничего не назначено.

var
 vo : OleVariant;
 v  : Variant;
begin
  v.DoThis;
  vo.DoThat;
end;
1 голос
/ 29 мая 2009

Рассматривали ли вы сериализацию ваших сложных данных с использованием JavaScript Object Notation (JSON)? Это позволит вам сериализовать произвольные объекты JavaScript, передать их в виде простой строки символов и воссоздать их в коде Delphi.

Delphi 2009 поддерживает JSON как часть нового DataSnap (не уверен, насколько легко использовать автономный). Существует также ряд реализаций Delphi JSON, которые могут оказаться полезными:

Оформить заказ lkjson и JSON - SuperObject

Я не специалист по JSON, но, похоже, это относительно простое и эффективное решение для межязыкового обмена данными.

David

0 голосов
/ 25 июля 2013

Объекты в Javascript являются ассоциативными массивами , а имена свойств являются ключами: obj.prop эквивалентно obj['prop'].

Обычные массивы - это просто объекты, хранящие индексы в качестве свойств, поэтому они ведут себя как разреженные массивы.

Delphi OleVariants разрешают прямой доступ к свойствам, но только если их имена действительны Delphi идентификаторы , поэтому ему не нравится использовать числовой индекс в качестве имени свойства (то есть obj.0 не компилируется ).

Свойства с недопустимыми именами идентификаторов могут быть прочитаны с использованием DISPATCH_PROPERTYGET, как в Ответ Райана .

Однако 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;
...