Empfangen komplexe JavaScript Werte durch externe Schnittstelle
-
06-09-2019 - |
Frage
Ich versuche, möglicherweise zu empfangen und komplexe Werte durch TWebBrowser (mit TEmbeddedWB) mit dem mitgelieferten externen Objekt. Zum Beispiel; in javascript würde ich versuchen, die freigelegte Methode mit einem Array als Parameter zu verwenden:
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üfen 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 ganz vertraut mit COM und ich bin nicht sicher, wie man damit arbeiten.
Jede mögliche Hilfe würde geschätzt.
Lösung
Sie können die JScript-Objekt wie jedes andere OleVariant COM-Objekt behandeln. Es gibt ein paar Fallstricke in Bezug auf Arrays (und fast jedes JScript-Objekt ist im Wesentlichen eine spärliche Array).
Nach dem JScript-Objekt in einen OleVariant bekommen, können Sie einfach nennen es wie jeder normaler Code (ohne Kompilierung natürlich Prüfung).
Hier ist ein Code für Arrays zu tun:
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;
Andere Tipps
Obwohl ich nicht direkt getan, was Sie Sie versuchen.
mit einer Variante Sie können Sie tatsächlich Zugang Methoden und Eigenschaften dynamisch.
Im Grunde nehme ich an Sie sollte alles der Lage sein, direkt zugreifen zu können.
Param.Someproperty
Param.SomeArray[1]
Param.SomeMethod();
Sie werden keine Zeit bekommen Fehler kompilieren, wenn Sie die Dinge falsch so vorsichtig sein.
Zum Beispiel der folgende Code kompiliert, wird aber einen Laufzeitfehler ungültiger Variante Betrieb geben, da es nichts zu dieser Variablen dynamisch zugewiesen ist.
var
vo : OleVariant;
v : Variant;
begin
v.DoThis;
vo.DoThat;
end;
Haben Sie darüber nachgedacht Ihre komplexen Daten Serialisierung JavaScript Object Notation (JSON)? Dies würde erlauben Sie beliebige JavaScript-Objekte serialisiert werden, so dass sie als einfache Zeichenfolge übergeben und sie in Delphi Code wiederherzustellen.
Delphi 2009 hat die Unterstützung für JSON als Teil des neuen DataSnap (nicht sicher, wie einfach es ist, Standalone zu verwenden). Darüber hinaus gibt es eine Reihe von Delphi JSON-Implementierungen gibt, die nützlich sein könnten:
Ich bin kein Experte in JSON, aber es scheint eine relativ einfache und effiziente Lösung für die sprachübergreifende Datenaustausch zu sein.
David
Objekte in Javascript sind assoziative Arrays , mit Eigenschaftsnamen Schlüssel sein: entspricht obj.prop
obj['prop']
ist
Regelmäßige Arrays sind einfach Objekte Indizes als Eigenschaften zu speichern, so verhalten sie sich wie spärlich Arrays.
Delphi OleVariants ermöglichen den direkten Zugriff auf die Eigenschaften, aber nur dann, wenn ihre Namen gültig sind Delphi-Bezeichner , so dass es nicht wie einen numerischen Index als Eigenschaftsnamen verwenden (dh obj.0
nicht kompilieren).
Eigenschaften mit ungültigen Bezeichnernamen können Aufruf DISPATCH_PROPERTYGET
wie in Ryans Antwort .
Allerdings Delphi gehört richtige Routinen in ComObj
unit dazu 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;