Pregunta

Estoy tratando de recibir y enviar valores potencialmente complejas a través de TWebBrowser (usando TEmbeddedWB) con el objeto externo proporcionado. Por ejemplo; en javascript me gustaría tratar de utilizar el método expuesto con una matriz como un parámetro:

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);

Comprobación del VarType de estos dos ejemplos me dice que es un IDispatch.

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

No estoy completamente familiarizado con COM y no estoy seguro de cómo trabajar con esto.

Cualquier ayuda sería apreciada.

¿Fue útil?

Solución

Puede tratar el objeto JScript al igual que cualquier otro objeto COM OleVariant. Hay unos pocos aspectos críticos en términos de arrays (y casi cualquier objeto JScript es esencialmente una matriz dispersa).

Después de conseguir el objeto JScript en un OleVariant simplemente puede llamar como lo haría con cualquier código normal (sin tiempo de compilación, por supuesto).

Aquí hay un código para hacer frente a las matrices:

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;

Otros consejos

A pesar de que no lo han hecho directamente lo que usted está tratando.

con una variante que se puede realmente métodos de acceso y propiedades de forma dinámica.

Básicamente sospecho que debe ser capaz de acceder a todo directamente.

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

Usted no recibirá errores de compilación de tiempo si usted consigue las cosas mal, así que tenga cuidado.

Por ejemplo el siguiente código compila, pero dará un error de ejecución de la operación variante no válida como no hay nada asignado dinámicamente a esa variable.

var
 vo : OleVariant;
 v  : Variant;
begin
  v.DoThis;
  vo.DoThat;
end;

¿Ha considerado la serialización de los datos complejos usando JavaScript Object Notation (JSON)? Esto le permitiría a serializar objetos JavaScript arbitrario, pasar como una simple cadena de caracteres y lo reconstituye en código de Delphi.

Delphi 2009 tiene soporte para JSON como parte de la nueva DataSnap (no estoy seguro de lo fácil que es utilizar independiente). También hay una serie de implementaciones Delphi JSON por ahí que podrían resultar útiles:

lkjson y JSON - SuperObject

No soy experto en JSON, pero parece ser una solución sencilla y eficaz relativa para el intercambio de datos entre diferentes idiomas.

David

Los objetos en Javascript son matrices asociativas , con los nombres de propiedades siendo claves: obj.prop es equivalente a obj['prop']

.

matrices regulares son simplemente objetos de almacenamiento de índices como las propiedades, por lo que se comportan como matrices dispersas.

OleVariants de Delphi permiten el acceso directo a las propiedades, pero sólo cuando sus nombres son válidos Delphi identificadores , por lo que no le gusta el uso de un índice numérico como un nombre de propiedad (es decir obj.0 no compila).

Las propiedades con nombres de identificadores no válidos pueden ser leídos DISPATCH_PROPERTYGET invocando como en de Ryan respuesta .

Sin embargo Delphi incluye rutinas adecuadas en ComObjunit que ver directamente lo siguiente:

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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top