AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Wie ermitteln, ob ein COM-Objekt eine bestimmte Methode hat?
Thema durchsuchen
Ansicht
Themen-Optionen

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

Ein Thema von alzaimar · begonnen am 20. Sep 2007 · letzter Beitrag vom 20. Sep 2007
Antwort Antwort
Seite 1 von 2  1 2      
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#1

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

  Alt 20. Sep 2007, 10:20
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?
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#2

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

  Alt 20. Sep 2007, 15:01
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
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#3

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

  Alt 20. Sep 2007, 15:04
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
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#4

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

  Alt 20. Sep 2007, 16:25
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.

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

Danke.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
OregonGhost

Registriert seit: 8. Jun 2002
Ort: Lübeck
1.216 Beiträge
 
Delphi 3 Professional
 
#5

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

  Alt 20. Sep 2007, 16:44
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...
Oregon Ghost
---
Wenn NULL besonders groß ist, ist es fast schon wie ein bisschen eins.
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#6

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

  Alt 20. Sep 2007, 16:50
Jupp, große Firma voll mit Deppen.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#7

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

  Alt 20. Sep 2007, 16:55
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]
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#8

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

  Alt 20. Sep 2007, 17:00
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.
Andreas
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#9

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

  Alt 20. Sep 2007, 18:08
Zitat:
Hier die Lösung:
setze noch ein const vor dem aMemberName parameter.

Gruß hagen
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#10

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

  Alt 20. Sep 2007, 18:11
Jawoll!
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:40 Uhr.
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