Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode hat? (https://www.delphipraxis.net/99969-wie-ermitteln-ob-ein-com-objekt-eine-bestimmte-methode-hat.html)

alzaimar 20. Sep 2007 09:20


Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode hat?
 
Also:

Ich habe einen Interfacezeige X mit 'late binding'. Vielleicht implementiert der eine Methode namens 'Foo', vielleicht aber auch nicht.

Ich will soetwas schreiben:

Delphi-Quellcode:
If InterfaceImplementsMethod (X,'Foo') Then
  X.Foo
Frage: Wie geht sowas?

negaH 20. Sep 2007 14:01

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
mit .GetIDsOfNames() geht dies. Ist schon länger her das ich das benutzt habe. Dein COM Object steht ja in einem Variant. Delphi erzeugt nun Code beim Aufruf einer Methode der im Codesegement den Namen der Methode als String ablegt, ebenso Paramater usw.

Falls du den Source für ComObj Delphi5 hast sieht das so aus:

Delphi-Quellcode:
{ Call GetIDsOfNames method on the given IDispatch interface }

procedure GetIDsOfNames(const Dispatch: IDispatch; Names: PChar;
  NameCount: Integer; DispIDs: PDispIDList);

  procedure RaiseNameException;
  begin
    raise EOleError.CreateResFmt(@SNoMethod, [Names]);
  end;

type
  PNamesArray = ^TNamesArray;
  TNamesArray = array[0..0] of PWideChar;
var
  N, SrcLen, DestLen: Integer;
  Src: PChar;
  Dest: PWideChar;
  NameRefs: PNamesArray;
  StackTop: Pointer;
  Temp: Integer;
begin
  Src := Names;
  N := 0;
  asm
    MOV StackTop, ESP
    MOV EAX, NameCount
    INC EAX
    SHL EAX, 2  // sizeof pointer = 4
    SUB ESP, EAX
    LEA EAX, NameRefs
    MOV [EAX], ESP
  end;
  repeat
    SrcLen := StrLen(Src);
    DestLen := MultiByteToWideChar(0, 0, Src, SrcLen, nil, 0) + 1;
    asm
      MOV EAX, DestLen
      ADD EAX, EAX
      ADD EAX, 3      // round up to 4 byte boundary
      AND EAX, not 3
      SUB ESP, EAX
      LEA EAX, Dest
      MOV [EAX], ESP
    end;
    if N = 0 then NameRefs[0] := Dest else NameRefs[NameCount - N] := Dest;
    MultiByteToWideChar(0, 0, Src, SrcLen, Dest, DestLen);
    Dest[DestLen-1] := #0;
    Inc(Src, SrcLen+1);
    Inc(N);
  until N = NameCount;
  Temp := Dispatch.GetIDsOfNames(GUID_NULL, NameRefs, NameCount,
    GetThreadLocale, DispIDs);
  if Temp = Integer(DISP_E_UNKNOWNNAME) then RaiseNameException else OleCheck(Temp);
  asm
    MOV ESP, StackTop
  end;
end;

{ Central call dispatcher }

procedure VarDispInvoke(Result: PVariant; const Instance: Variant;
  CallDesc: PCallDesc; Params: Pointer); cdecl;

  procedure RaiseException;
  begin
    raise EOleError.CreateRes(@SVarNotObject);
  end;

var
  Dispatch: Pointer;
  DispIDs: array[0..MaxDispArgs - 1] of Integer;
begin
  if TVarData(Instance).VType = varDispatch then
    Dispatch := TVarData(Instance).VDispatch
  else if TVarData(Instance).VType = (varDispatch or varByRef) then
    Dispatch := Pointer(TVarData(Instance).VPointer^)
  else RaiseException;
  GetIDsOfNames(IDispatch(Dispatch), @CallDesc^.ArgTypes[CallDesc^.ArgCount],
    CallDesc^.NamedArgCount + 1, @DispIDs);
  if Result <> nil then VarClear(Result^);
  DispatchInvoke(IDispatch(Dispatch), CallDesc, @DispIDs, @Params, Result);
end;
hoffe ich mache mich nicht strafbar ?

Bei einem Source wie

Delphi-Quellcode:
var
  Obj: Variant; // OleVariant
begin
  Obj := CreateCOMObject(); // oder ähnliches
  Obj.Print('Test');
end;
legt der Compiler quasi sowas an

Delphi-Quellcode:
const codesegemnt
  sProcName = 'Print'#0;
const BSS
  sParam = 'Test';
var
  Obj: Variant; // OleVariant
  Result: Variant;
begin
  Obj := CreateCOMObject(); // oder ähnliches
  VarDispInvoke(Result, Obj, sProcName, sParams);
  if Result then ;
end;
Das ist jetzt aber eine sehr abstrahierte Umschreibung.
Es könnte durchaus sein das es auch schon eine entsprechend einfachere Funktion in neueren Delphi Versionen dafür gibt.
Eines steht fest, späte Bindung funktioniert nur mit IDispatch abgeleiteten Interfaces und diese haben auch meistens eine ITypeLib. Über diese werden die DispIDs, Parameter und Namen hinterlegt.

Gruß Hagen

negaH 20. Sep 2007 14:04

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Ansonsten könntest du auch mit einem try except Block arbeiten (erinnert mich an den anderen Thread ;) ).

Aber schön ist das wirklich nicht, ich halte es eher so wie du und würde auch versuchen sowas vorher abzufangen.
Allerdings beudetet das noch längst nicht das dann keine Exceptions merh ausgelösst werden. Also wenn man weis ob eine Methode mit Namen XYZ in einer Variante existent ist. Denn die Parameter müssen ja auch noch stimmen.

Schöner wäre es eine globale Funktion wie

TryVarDispInvoke()

zu haben mit einem globalen Exceptionhandler und Return Result.

Gruß Hagen

alzaimar 20. Sep 2007 15:25

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Hi Hagen,

Ich wusste doch, das es geht... Sieht aber ziemlich pervers aus. Das mit den Parametern ist schon ok, wenn es die Funktion gibt, dann weiss ich auch, wie man sie verwendet.

Es geht um eine neue Version eines Interfaces. Die Autoren haben eine neue Funktion eingebaut, die aber erst demnächst installiert wird. Ich muss aber heute schon den Client entsprechend anpassen. Also muss ich soetwas wie 'Kannst Du das schon?' implementieren.

Derzeit ist natürlich die Try...Except-Geschichte implementiert, aber neee. :kotz:

Dann lieber die perverse Lösung. Ich checke gleich mal, wie das so geht.

Danke.

OregonGhost 20. Sep 2007 15:44

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Zitat:

Es geht um eine neue Version eines Interfaces. Die Autoren haben eine neue Funktion eingebaut, die aber erst demnächst installiert wird. Ich muss aber heute schon den Client entsprechend anpassen. Also muss ich soetwas wie 'Kannst Du das schon?' implementieren.
Gab es nicht zu diesem Zweck die eiserne COM-Regel, dass ein Interface niemals verändert werden darf, weshalb z.B. bei Microsoft die Interfaces ja auch eine Nummer am Ende tragen? Dann kann man nämlich den vorgesehenen Weg gehen und das Objekt einfach per COM fragen, ob es das neue Interface schon unterstützt...

alzaimar 20. Sep 2007 15:50

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Jupp, große Firma voll mit Deppen.

alzaimar 20. Sep 2007 15:55

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Hier die Lösung:

Delphi-Quellcode:
Function InterfaceSupportsMember (anInterface : IDispatch; Const aMembername : WideString) : Boolean;
Var
  iDispID : TDispId;
  Res : Integer;

Begin
  Res :=anInterface.GetIDsOfNames(GUID_NULL, @aMembername, 1, LOCALE_SYSTEM_DEFAULT, @iDispID);
  Result := Res <> Integer(DISP_E_UNKNOWNNAME)
End;
Und ein Danke an Hagen und OregonGhost. Ich werd mich mal in der Firma beschweren gehen.

[edit] Const vor aMembername gesetzt [/edit]

shmia 20. Sep 2007 16:00

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Zitat:

Zitat von OregonGhost
Gab es nicht zu diesem Zweck die eiserne COM-Regel, dass ein Interface niemals verändert werden darf, weshalb z.B. bei Microsoft die Interfaces ja auch eine Nummer am Ende tragen? Dann kann man nämlich den vorgesehenen Weg gehen und das Objekt einfach per COM fragen, ob es das neue Interface schon unterstützt...

Eigentlich schon, aber das geht nur bei früher Bindung über die TLB.
Normalerweise holt man sich ein Interface (z.B. IHTMLElement) und prüft dann ob z.B. das Interface IHTMLElement2 verfügbar ist (in Delphi macht man das mit der Supports()-Funktion).
Bei später Bindung gibt es diese Möglichkeit in aller Regel nicht.
Dort ist man gezwungen immer auf dem gleichen Interface zu arbeiten.

negaH 20. Sep 2007 17:08

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Zitat:

Hier die Lösung:
setze noch ein const vor dem aMemberName parameter.

Gruß hagen

alzaimar 20. Sep 2007 17:11

Re: Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode
 
Jawoll!


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:02 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz