Question

Je suis en train de recevoir et envoyer potentiellement des valeurs complexes par TWebBrowser (en utilisant TEmbeddedWB) avec l'objet externe fourni. Par exemple; javascript Je voudrais essayer d'utiliser la méthode exposée avec un tableau comme paramètre:

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

Vérification de la VarType de ces deux exemples me dit qu'il est un IDispatch.

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

Je ne suis pas tout à fait familier avec COM et je ne suis pas sûr de savoir comment travailler avec cela.

Toute aide serait appréciée.

Était-ce utile?

La solution

Vous pouvez traiter l'objet JScript comme tout autre objet OleVariant COM. Il y a quelques gotchas en termes de tableaux (et à peu près tout objet JScript est essentiellement un tableau creux).

Après avoir obtenu l'objet JScript dans un OleVariant vous pouvez simplement l'appeler comme vous le feriez pour tout code normal (sans compilation de vérification bien sûr).

Voici un code pour traiter les tableaux:

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;

Autres conseils

Bien que je n'ai pas directement fait ce que vous vous essayez.

avec une variante, vous pouvez vous en fait des méthodes d'accès et propriétés dynamiquement.

En fait, je pense que vous devriez être en mesure d'accéder à tout directement.

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

Vous n'obtiendrez des erreurs de compilation de temps si vous avez des choses mal alors faites attention.

Par exemple, le code suivant compile, mais donnera une erreur d'exécution de l'opération de variante non valide car il n'y a rien dynamiquement assigné à cette variable.

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

Avez-vous envisagé sérialisation vos données complexes en utilisant JavaScript Object Notation (JSON)? Cela vous permettra de sérialiser des objets JavaScript arbitraires, les passer comme une simple chaîne de caractères et les réhydrater dans le code Delphi.

Delphi 2009 a le soutien de JSON dans le cadre de la nouvelle DataSnap (ne sais pas comment il est facile à utiliser autonome). Il y a aussi un certain nombre d'implémentations Delphi JSON là-bas qui pourrait se révéler utile:

lkjson et JSON - SuperObject

Je ne suis pas expert en JSON, mais il semble être une solution simple et efficace relative pour l'échange de données de langue croix.

David

Objets Javascript sont des tableaux associatifs , avec des noms de propriété étant clés: obj.prop est équivalent à obj['prop']

.

tableaux réguliers sont des objets simplement stocker des index comme des propriétés, de sorte qu'ils se comportent comme des tableaux rares.

Les OleVariants Delphi permettent un accès direct aux propriétés, mais seulement lorsque leurs noms sont valides Delphi identifiants , donc il n'aime pas utiliser un index numérique comme un nom de propriété (c.-à-obj.0 ne compile pas).

Propriétés avec des noms d'identification non valides peuvent être lus comme dans l'invocation DISPATCH_PROPERTYGET réponse de Ryan .

Cependant Delphi comprennent des routines propres à ComObjunit à faire directement ceci:

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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top