2009-05-28 6 views
2

Ich versuche, komplexe Werte über TWebBrowser (mit TEmbeddedWB) mit dem bereitgestellten externen Objekt zu empfangen und möglicherweise zu senden. Zum Beispiel; in javascript würde ich versuchen, die freigelegte Methode mit einem Array als Parameter zu verwenden:Erhalten von komplexen Javascript-Werten über externe Schnittstelle

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

Überprüfung der VarType von diesen beiden Beispielen sagt mir, es ist ein IDispatch.

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

Ich bin nicht vollständig vertraut mit COM und ich bin mir nicht sicher, wie man damit arbeitet.

Jede Hilfe wäre willkommen.

Antwort

3

können Sie das Objekt JScript behandeln wie jede andere OleVariant COM-Objekt. Es gibt einige Fehler in Bezug auf Arrays (und fast jedes JScript-Objekt ist im Wesentlichen ein Sparse-Array).

Nachdem Sie das JScript-Objekt in einen OleVariant übernommen haben, können Sie es einfach wie normalen Code aufrufen (natürlich ohne Überprüfung der Kompilierzeit).

Hier ist ein Code mit Arrays für den Umgang:

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

Obwohl ich nicht direkt getan habe, was Sie versuchen.

mit einer Variante können Sie tatsächlich auf Methoden und Eigenschaften dynamisch zugreifen.

Grundsätzlich vermute ich, dass Sie in der Lage sein sollten, direkt auf alles zuzugreifen.

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

Sie werden keine Kompilierzeit Fehler bekommen, wenn Sie etwas falsch machen, seien Sie also vorsichtig.

Zum Beispiel kompiliert der folgende Code, aber wird einen Laufzeitfehler der ungültigen Variantenoperation geben, da dieser Variablen nichts dynamisch zugewiesen ist.

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

Sie haben Recht, Methoden und Eigenschaften zugänglich sind auf diese Weise. Ich hatte jedoch kein Glück mit den Arrays. Ich habe nicht versucht, ein einzelnes Element wie SomeArray [1] auszuwählen, das funktioniert, aber ich kann VarArrayHighBound (SomeArray, 1) oder niedrige Grenze nicht bekommen, um daran zu arbeiten. Es denkt nicht, dass es ein Array oder etwas ist. Dies ist der Fall, wenn ich ein Array alleine überlasse, anstatt das Array zu einer Eigenschaft eines Objekts zu machen. Hast du Erfahrung damit? – Tim

1

Haben Sie in Betracht gezogen, Ihre komplexen Daten mit JavaScript Object Notation (JSON) zu serialisieren? Auf diese Weise können Sie beliebige JavaScript-Objekte serialisieren, als einfache Zeichenfolge übergeben und in Delphi-Code neu erstellen.

Delphi 2009 unterstützt JSON als Teil des neuen DataSnap (nicht sicher, wie einfach es ist, eigenständig zu verwenden). Darüber hinaus gibt es eine Reihe von Delphi JSON-Implementierungen gibt, die vielleicht als nützlich erweisen:

Kasse lkjson und JSON - SuperObject

Ich bin kein Experte in JSON, aber es scheint eine relativ einfache und effiziente Lösung für Cross-Sprache zu sein Datenaustausch.

David

0

Objekte in Javascript are associative arrays, mit Eigenschaftsnamen Schlüssel sein: obj.prop-obj['prop'] entspricht.

Reguläre Arrays sind einfach Objekte, die Indizes als Eigenschaften speichern, so dass sie sich wie Sparse-Arrays verhalten.

Die OleVarianten von Delphi erlauben direkten Zugriff auf Eigenschaften, aber nur wenn ihre Namen gültig sind Delphi identifiers, so dass es keinen mag, einen numerischen Index als Eigenschaftsnamen zu verwenden (d. H. obj.0 kompiliert nicht).

Eigenschaften mit ungültigen Bezeichnernamen können unter Aufruf von DISPATCH_PROPERTYGET wie in Ryan's response gelesen werden.

Allerdings umfassen Delphi richtige Routinen in ComObj Gerät dies direkt zu tun:

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;