Announcement

Collapse
No announcement yet.

Objekt im Objekt?

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

  • Objekt im Objekt?

    Hallo,

    nachdem ich "COM/DCOM für Delphi" sowie das Delphi 5-Handbuch und noch weitere Literatur durchgeackert habe, ist COM keim Problem mehr. Naja, fast: wie kann ich Objekte (eigentlich Interfaces) hintereinanderklemmen? Also kein Aggregate, so daß ich von einem Interface aus direkt mehrere Methoden/Eigenschaften erreiche, sondern etwas wie in den Office-Anwendungen bzw. diesem Beispiel:

    TPerson ist eine Klasse mit der Eigenschaft Name: string
    TAbteilung ist eine Klasse mit zwei Eigenschaften: Name: string und Leiter: TPerson
    TKunde ist eine Klasse mit zwei Eigenschaften: Name: string und EDVAbteilung: TAbteilung

    Wie gesagt, nicht sehr sinnvoll und nur ein Beispiel.
    Nun gut, unter Delphi kann ich, wenn alle Objekte erzeugt wurden, per Kunde.EDVAbteilung.Leiter.Name direkt auf den Namen des EDV-Leiters zugreifen. Genau das Verhalten will ich per COM exportieren. Ich kann zwar im Interface IKunde eine Eigenschaft IAbteilung definieren und dann auch darauf zugreifen. Aber auf die Eigenschaft Name der Abteilung komme ich nicht, Delphi liefert nur "undefinierter Bezeichner". Wo liegt mein Denkfehler?

  • #2
    Hallo,

    bei der <b>Aggregation</b> schmückt sich das COM-Objekt mit fremden Federn, da bestimmte Interfaces von anderen Objekten stammen. Damit dies funktioniert, muß <b>QueryInterface</b> in der Lage sein, die Aufrufe auf das zuständige Objekt umzuleiten:
    <pre>
    function TNativeAggregat.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
    if IsEqualGuid(IID, INativeAggregatB) then
    Result := FSrvB.QueryInterface(IID, Obj)
    else
    if IsEqualGuid(IID, INativeAggregatC) then
    Result := FSrvC.QueryInterface(IID, Obj)
    else
    Result := inherited QueryInterface(IID, Obj);
    end;
    </pre>

    Wenn das nicht gewünscht wird, kann ein COM-Objekt während seiner Initialisierung andere COM-Objekte (mit anderen Interfaces) erzeugen und einen Interface-Zeiger in eigenen Objektfeldern zwischenspeichern. Dann stellt dieses "Hauptobjekt" über Eigenschaften dem Client diese Interface-Zeiger zur Verfügung:

    <pre>
    IAbteilung = interface
    property Count : Integer;
    property Item[Index : Integer] : IPerson;
    ...
    end;
    </pre>

    Sollen gleichzeitig mehrere Personen abrufbar sein, liegt es auf der Hand, gleiche alle Objekte zu erstellen und die Interface-Zeiger darauf in einer <b>TInterfaceList</b> zu verwalten.

    Der Client würde somit immer nur auf das "Hauptobjekt" zugreifen (CoClass-Instanzierung) und sich dann über die Objekt-Eigenschaften zu den anderen Objekten "durchfragen". Die Instanz dieser anderen COM-Objekte wird jedoch nicht im Client, sondern direkt im "Hauptobjekt" (oder den nachgeordneten Objekten) erzeugt. Der Client erhält immer nur einen Interface-Zeiger auf ein bereits lebendes Objekt zurück.
    <pre>
    var
    aEDV : IAbteilung;
    aPerson : IPerson;
    begin
    aEDV := CoAbteilung.Create;
    if aEDV.Count > 0 then
    aPerson := aEDV.Item[1];
    ...
    end;
    </pre>

    Somit würde der eigene Server genau so eine Objekt-Hierarchie anbieten, wie es zum Beispiel Microsoft Office macht (Application-Objekt; Document-Objekt usw.)

    Comment


    • #3
      Danke für die Antwort.
      Ich habe gerade meinen Fehler gefunden: die "untegeordneten" Schnittstellen wurden nicht als Automatisierungs-Objekt erstellt. Und bei COM-Objekten werden die Eigenschaften (hier: Name) eben nicht publik gemacht (soweit meine Erfahrungen, bin noch nciht 100% fit bei COM).
      OK, ich kann Kunde.Abteilung.Name nutzen. Dummerweise finden sich in DCOMCNFG sowohl das Kunde- als auch das Abteilung-Objekt. Letzteres soll aber nicht allen ansprechbar sein. Wenn ich bein Interface IAbteilung das Flag "Hidden" setze, taucht es nicht auf. Ist das die richtige Vorgehensweise: alle Intefaces bis z.B. auf IKundenApplikation verstecken

      Comment


      • #4
        Hallo,

        um ein Interface vor den Clients zu "verstecken", stehen verschiedene Techniken zur Verfügung.

        1. Im Typbibliotheks-Editor wird <b>CanCreate</b> abgewählt und <b>Hidden</b> aktiviert. Das Interface ist jedoch für andere Tools immer noch sichtbar (da es in der Registry eingetragen wird), nur ein "normaler" Client kann keine Instanz mehr erzeugen.

        2. Anstelle eines normalen Automation-Objektes wird <b>TAutoIntfObject</b> verwendet. Somit erzeugt Delphi keine <b>CoClass</b> und keine <b>ClassFactory</b>. Damit muss allerdings das eigene Server-Objekt die TLB von Hand laden (eine Objekt-Instanz kann somit nur durch das eigene Server-Objekt erzeugt werden):
        <pre>
        var
        hr : HResult;
        TypeLib : ITypeLib;
        begin
        hr := LoadRegTypeLib(LIBID_MyProjectID, 1, 0, LANG_NEUTRAL, TypeLib);
        if(SUCCEEDED(hr)) then
        begin
        DetailObjekt := TDetailObjekt.Create(TypeLib, CLSID_Files)
        end;
        end;
        </pre>

        Diese Technik findet man gleich an mehreren Stellen in der VCL - und wenn Borland das so macht, gibt es keine Grund, dies nicht auch zu tun

        Comment

        Working...
        X