Announcement

Collapse
No announcement yet.

Mehrere Interfaces in COM-Schnittstelle und Zugriff VBS

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mehrere Interfaces in COM-Schnittstelle und Zugriff VBS

    Hallo,

    ich habe einen COM-Server welchen ich um eine weitere Schnittstelle erweitern will

    IMyInterface ist Dual-Interface (gab es schon)<br>
    Neue Funktion: getInft2 welches IMyInterface2 zurückliefert (für Delphi eigentlich unnötig)<br>
    IMyInterface2 ist Dual-Interface (neu)

    COMMyInterface implementiert IMyInterface und neu auch IMyInterface2.

    Mit Delphi ist der Zugriff kein Problem

    <pre>
    myIntf := CoCOMWorkbench.Create;
    myIntf.FunctionAusMyInterface();

    (myIntf as IMyInterface2).FunctionAusNeuemInterface;

    bzw.

    myIntf.getIntf2.FunctionAusNeuemInterface;
    </pre>

    Jedoch bekomme ich den Zugriff für VBS nicht hin. :-(<br>

    Versuch:

    Set MyIntf = CreateObject("MyApp.MyServer")
    MyIntf.FunctionAusMyInterface // Ist OK

    Set MyIntf2 = MyIntf.getIntf2; // geht

    MyIntf2.FunctionAusNeuemInterface // geht nicht: Das Objekt unterstützt diese Eigenschaft oder Methode nicht

  • #2
    Hallo,

    &gt;Jedoch bekomme ich den Zugriff für VBS nicht hin.

    das ist normal - denn bei der späten Bindung über IDispatch kann es nur ein einziges Interface geben. Wenn eine Scriptsprache einen Interface-Zeiger anfordert, kann der Interface-Typ nicht definiert werden, so dass dieser Script-Client immer nur die <b>IDispatch</b>-Implementierung des <b>Default</b>-Interfaces nutzen kann.

    Immer dann, wenn zwischen dem Client und der Objektinstanz eine Apartment- oder Prozess-Grenze liegt, richtet der Marshaler für jedes Interface ein Proxy-/Stub-Objekt dazwischen ein. Allerdings benötigt der Client in dem o.g. Fall beim Zugriff über die späte Bindung gleich zwei verschiedene Implementierungen des IDispatch-Interfaces - einmal für das Default-Interface und einmal für das zweite Interface. Aus Performancegründen richtet der Marshaler jedoch das Proxy-/Stub-Paar immer nur einmal je Interface ein, so dass jeder Aufruf über immer über das gleiche Proxy-/Stub-Paar läuft. Der WSH liefert daher beim Aufruf nur einen Fehlercode (wie 800A000D) zurück, da der Aufruf ins Leere greift.

    Für die Zugriffe über die späte Bindung muss das COM-Objekt daher ein Wrapper-Interface bereitstellen, dass alle separaten Interfaces an einer Stelle neu verpackt. Das könnte zum Beispiel so aussehen:
    <pre>
    <b>unit</b> MultiInterfaceSrvWrapperObj_Impl;

    <font color="#003399"><i>{$WARN SYMBOL_PLATFORM OFF}</i></font>

    <b>interface</b>

    <b>uses</b>
    ComObj, ActiveX, MultiInterfaceSrv_TLB, StdVcl;

    <b>type</b>
    TMultiInterfaceSrvWrapperObj = <b>class</b>(TAutoObject, IMultiInterfaceSrvWrapperObj)
    <b>private</b>
    FSrv : IMultiInterfaceServer;
    <b>protected</b>
    <b>function</b> DoWork1(vText: OleVariant): OleVariant; <b>safecall</b>;
    <b>function</b> Get_GetInfo: OleVariant; <b>safecall</b>;
    <font color="#003399"><i>{ Protected-Deklarationen }</i></font>
    <b>public</b>
    <b>procedure</b> Initialize; <b>override</b>;
    <b>destructor</b> Destroy; <b>override</b>;
    <b>end</b>;

    <b>implementation</b>

    <b>uses</b> ComServ;

    <font color="#003399"><i>{-----------------------------------------------------------------------}</i></font>
    <font color="#003399"><i>{ Client erzeugt Instanz des Wrapper-Objekts: Original-Instanz erzeugen }</i></font>
    <font color="#003399"><i>{-----------------------------------------------------------------------}</i></font>

    <b>procedure</b> TMultiInterfaceSrvWrapperObj.Initialize;
    <b>begin</b>
    <b>inherited</b>;
    FSrv := CoMultiInterfaceServer.Create;
    <b>end</b>;

    <b>destructor</b> TMultiInterfaceSrvWrapperObj.Destroy;
    <b>begin</b>
    FSrv := <b>nil</b>;
    <b>inherited</b>;
    <b>end</b>;

    <font color="#003399"><i>{-----------------------------------------------------------------------}</i></font>
    <font color="#003399"><i>{ Interface-Methoden des Wrapper-Objekts rufen das Original-Objekt auf }</i></font>
    <font color="#003399"><i>{-----------------------------------------------------------------------}</i></font>

    <b>function</b> TMultiInterfaceSrvWrapperObj.DoWork1(vText: OleVariant): OleVariant;
    <b>var</b>
    swMsg : WideString;
    <b>begin</b>
    FSrv.DoWork1(vText, swMsg);
    Result := swMsg;
    <b>end</b>;

    <b>function</b> TMultiInterfaceSrvWrapperObj.Get_GetInfo: OleVariant;
    <b>begin</b>
    Result := FSrv.InfoObject.GetInfo;
    <b>end</b>;

    <b>initialization</b>
    TAutoObjectFactory.Create(ComServer, TMultiInterfaceSrvWrapperObj, Class_MultiInterfaceSrvWrapperObj,
    ciMultiInstance, tmApartment);
    <b>end</b>.
    </pre>
    Der Aufruf aus dem VBScript für den WSH heraus ist dann erfolgreich:
    <pre>
    Dim Obj, sInput, sOutput
    Set Obj = CreateObject("MultiInterfaceSrv.MultiInterfaceSrvW rapperObj")
    MsgBox Obj.GetInfo
    sInput = "Daten aus dem VBS"
    MsgBox Obj.DoWork1(sInput)
    Set Obj = Nothing
    MsgBox "Das WSH-Script wurde vollständig abgearbeitet"
    </pre&gt

    Comment


    • #3
      Hallo Andreas,

      eigentlich wollte ich nicht alle Funktionen in einem Interface zusammenfassen. Die Gründe dafür liegen in der Übersichtlichkeit und Beschreibung der Schnittstelle.

      In der Version 1.0 gibt es nur die Funktionen welche in der Schnittstelle IMyInterface definiert sind.

      In der neuen Version 2.0 sollen alle neu hinzugekommenen Funktionen in die Schnittstelle IMyInterface2 aufgenommen werden.

      In einer Version 3.0 wird es dann eine Schnittstelle IMyInterface3 geben.

      Damit hätte ich eine einfach Beschreibung welche Funktionen mit welcher Programmversion verfügbar wären. Dies wäre damit ähnlich der IWebBrowser/2/3...5-Schnittstellen des Internet-Explorers.

      Alternativ könnte ich die Unterstützung von VBS wegfallen lassen, wenn ich wüßte welche Schalter in der Typbibliothek gesetzt werden müssen, damit unter Access-2000 die frühe Typbindung verfügbar wäre. Bisher bekomme ich unter Access 2000 nur den VBS-Web über späte Bindung hin. Unter VB.NET/C# ist die frühe Bindung keine Problem

      Comment


      • #4
        Hallo,

        &gt;..damit unter Access-2000 die frühe Typbindung verfügbar wäre.

        ich bin mir nicht sicher, ob das dort tatsächlich geht. Microsoft spricht auch gern in diesem Umfeld bereits dann von der "frühen" Bindung, wenn die DISPIDs der über IDispatch ausgeführten Methoden aus der TLB ausgelesen werden. Somit erspart sich ACCESS2000 den vorherigen Aufruf von <i>IDispatch.GetIDsOfNames</i>, aber die Methoden werden dann trotzdem über <i>Invoke</i> aufgerufen. Im Borland-Umfeld wird dies als ID-Bindung bezeichnet (d.h. in Delphi stehen gleich 3 Alternativen zur Verfüung: 1. Späte Bindung; 2. ID-Bindung; 3. Frühe Bindung).

        &gt;..welche Schalter in der Typbibliothek gesetzt werden müssen.

        Delphi kennzeichnet die TLB automatisch als duales Interface:
        <pre>
        typelib Project1
        [ uuid '{E80EB406-31DB-4119-A63E-3DFD968AD73D}',
        version 1.0,
        helpstring 'Project1 Bibliothek' ];

        uses stdole2.tlb, STDVCL40.DLL;

        IDelphiDualInterface = interface(IDispatch)
        [ uuid '{3F09D715-D6BB-4CFB-8C89-F3BE7043640D}',
        version 1.0,
        helpstring 'Dispatch-Schnittstelle für DelphiDualInterface-Objekt',
        <b>dual,
        oleautomation</b> ]
        end;

        DelphiDualInterface = coclass(IDelphiDualInterface [default] )
        [ uuid '{41D01464-8A8E-4A2B-86A6-794A5DFF9666}',
        version 1.0,
        helpstring 'DelphiDualInterface Objekt' ];

        end.
        </pre&gt

        Comment


        • #5
          Hallo Andreas,

          die Schalter dual und oleautomation sind in der TLB für das Interface gesetzt, jedoch bekomme ich in Access mein Object nicht in die Liste der ActivX-Steuerelement (oder etwas ähnliches was ich nocht nicht gefunden habe).<br>
          Wahrscheinlich hätte ich die Schnittstelle als ActiveX-Element und nicht als Automatisierungsobject anlegen müssen damit Access es in seine Liste aufnimmt. Aber es ist nun mal mehr als ein ActiveX-Element

          Comment


          • #6
            Hallo,

            im <i>Microsoft Visual Basic</i>-Fenster von ACCESS muss der Menüpunkt <b>Extras | Verweise</b> verwendet werden, um eine TLB einzubinden. Bei mir werden dort alle TLBs angezeigt - sogar die TLBs meiner C# .NET Enterprise Services Objekte (alias COM+).

            Comment


            • #7
              Hallo Andreas,

              Ich glaube dieser "Wink mit dem Zaumpfahl" kann mein Problem lösen. Muß noch Abklären ob man die VBS-Untertützung wegfallen lassen kann. Muß dann jedoch ein Access-Basic oder C#/VB.NET-Beispiel in der Dokumentation aufnehmen.

              Danke für deine (wie immer) sehr kompetente Unterstützung

              Comment

              Working...
              X