Domanda

Sto cercando di ricevere e inviare i valori potenzialmente complessi attraverso TWebBrowser (usando TEmbeddedWB) con l'oggetto esterno fornito. Per esempio; in javascript cercherei di utilizzare il metodo esposto con un array come parametro:

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

Verifica della VarType di entrambi questi esempi mi dice che è un IDispatch.

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

Io non sono completamente familiarità con COM e non sono sicuro di come lavorare con questo.

Qualsiasi aiuto sarebbe apprezzato.

È stato utile?

Soluzione

Si può trattare l'oggetto JScript come qualsiasi altro oggetto COM OleVariant. Ci sono alcuni trucchi in termini di matrici (e praticamente qualsiasi oggetto JScript è essenzialmente un array sparso).

Dopo avere ottenuto l'oggetto JScript in un OleVariant si può semplicemente chiamare come si farebbe con qualsiasi codice normale (senza tempo di compilazione controllare ovviamente).

Un po 'di codice per trattare con gli array:

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;

Altri suggerimenti

Anche se non ho fatto direttamente quello che si sta cercando.

con una variante che si può effettivamente i metodi di accesso e le proprietà in modo dinamico.

In pratica ho il sospetto che si dovrebbe essere in grado di accedere a tutto direttamente.

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

Non si ottiene errori di compilazione di tempo se si sbaglia quindi state attenti.

Ad esempio il seguente codice compila, ma darà un errore di esecuzione di un'operazione variante non valida, non c'è niente assegnato dinamicamente a quella variabile.

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

Avete considerato la serializzazione dei dati complessi utilizzando JavaScript Object Notation (JSON)? Ciò consentirebbe di serializzare oggetti arbitrari JavaScript, li passa come una semplice stringa di caratteri e li ricostituire nel codice Delphi.

Delphi 2009 ha il supporto per JSON come parte del nuovo DataSnap (non so come sia facile da usare stand-alone). Ci sono anche una serie di implementazioni Delphi JSON là fuori che potrebbero rivelarsi utili:

lkjson e JSON - SuperObject

Non sono un esperto in JSON, ma sembra essere una soluzione semplice ed efficiente relativo per lo scambio di dati cross-language.

David

Oggetti in Javascript sono array associativi , con nomi di proprietà di essere chiavi: obj.prop è equivalente a obj['prop']

.

array regolari sono oggetti semplicemente memorizzare indici come proprietà, quindi si comportano come array sparsi.

OleVariants di Delphi consentono l'accesso diretto alle proprietà, ma solo quando i loro nomi sono validi Delphi identificatori , in modo che non piace utilizzando un indice numerico come un nome di proprietà (cioè obj.0 non compila).

Proprietà con i nomi di identificatori non validi possono essere letti DISPATCH_PROPERTYGET invocando come nel di Ryan risposta .

Tuttavia Delphi includono le routine appropriate in ComObjunit da fare direttamente in questo modo:

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top