Freigeben über


Rückwärtskompatibles Ändern von Schnittstellen

Die in Der Versionsverwaltungstheorie für RPC und COM erläuterten Methoden können aus vielen Gründen inakzeptabel sein. Das Ändern einer Schnittstellenversion gemäß den Regeln erfordert im Wesentlichen, dass neue Clients nicht mit alten Servern kommunizieren. Dies ist bei kommerzieller Software, die im Feld bereitgestellt wird, häufig nicht möglich. Manchmal hat Windows Schnittstellenänderungen ohne geänderte GUIDs oder Versionen eingeführt. Dies ist darauf zurückzuführen, dass neue Clients mit Legacyservern kommunizieren mussten, und weil die Lösung, die ein neuer Client sowohl die alten als auch die neuen Schnittstellen unterstützen würde, als unerwünscht eingestuft wurde.

Empfehlung

Dies sind die sinnvollen Methoden, um das Problem mit der Inkompatibilität von Kabeln zu umgehen, wenn die GUID und die Version der Schnittstelle nicht geändert werden können.

  1. Lassen Sie die Anwendung die Funktionen der anderen Seite kennen.

    Client und Server verfügen über ein Protokoll, das es jedem (oder zumindest dem neuen Client) ermöglicht, die Identität des Partners festzulegen. In der Regel reicht es aus, dass der neue Client die Features kennt, die von alten und neuen Servern unterstützt werden. Dies kann problemlos geschehen, wenn eine Anwendung an einem Verbindungskontext festhält und durch einen Funktionsaufruf vom Typ XxxGetInfo unterstützt wird, der vom Client ausgeführt wird, bevor RPC-Vorgänge ausgeführt werden. Wenn eine Anwendung die Features auf serverspezifischer Releasebasis verwaltet, kann kein Aufruf mit einer Inkompatibilität mit dem alten Server/Client erfolgen, da die Anwendung steuert, welche Aufrufe an welchen Server ausgegeben werden. Unter dem Strich verhindert die Anwendung proaktiv, dass es zu einem Konflikt kommt. Dies kann in Verbindung mit der zweiten Praxis durchgeführt werden.

  2. Einführung einer neuen Remote-API.

    Eine neue Remotemethode kollidiert nicht mit vorhandenen Methoden, wenn sie ganz am Ende der Schnittstelle hinzugefügt wird. Alte Clients können wie immer neue Server aufrufen. Der neue Client kann die neue Methode aufrufen, ohne die Identität des Servers zu kennen, vorausgesetzt, er überwacht die Fehler, die vom aufgerufenen Server stammen. Die RPC-Laufzeit überprüft immer die Methodennummer für jede Schnittstelle vor einer Versendung, um sicherzustellen, dass sich die Methode innerhalb einer entsprechenden v-Tabelle befindet. Bei einer Methode, die einem Server unbekannt ist, löst die RPC-Laufzeit die Ausnahme RPC_S_PROCNUM_OUT_OF_RANGE aus. Diese Ausnahme wird nur in dieser besonderen Situation ausgelöst. Daher kann ein neuer Client für die Ausnahme als Zeichen watch, dass der Aufruf an einen alten Server gegangen ist und sein Verhalten ordnungsgemäß ändern kann.

  3. Führen Sie neue Parameter oder neue Datentypen nur in den neuen Methoden ein.

    Ein Grund für die Einführung einer neuen Methode ist die Vermeidung von Dateninkompatibilität. Wenn ein neuer Datentyp eingeführt oder einfach geändert wird, sollte er grundsätzlich nur in einer neuen Methode (oder Methoden) verwendet werden. Beispiele für inkompatible Datentypänderungen finden Sie unter Beispiele für inkompatible Änderungen. Die einzige bemerkenswerte Ausnahme dieser Regel wird in Punkt 4 beschrieben.

  4. Ordnen Sie neue Parameter oder neue Datentypen über einen Wrapper zu.

    Diese Lösung gilt, wenn ein neuer Parameter oder Datentyp für einen Benutzer verfügbar gemacht werden muss, tatsächlich aber nicht separat remoteisiert werden muss oder den alten Datentypen oder Parametern zugeordnet werden kann. Beispielsweise wenden sich viele System-APIs um und führen einen Remoteaufruf aus. Sie können eine Art Zuordnung von den vom Benutzer bekannten Datentypen zu den Datentypen durchführen, die tatsächlich im zugrunde liegenden RPC-Aufruf verwendet werden. Es lohnt sich daher immer zu prüfen, ob die Änderung der Benutzeroberfläche als Änderung an eine Remoteschnittstelle weitergegeben werden muss.

    Eine ähnliche Situation kann auftreten, wenn der Benutzer eine Remote-API direkt aufruft, aber ein Wrapper kann eingeführt werden, um eine neue Typzuordnung oder andere zusätzliche Aktionen durchzuführen, die erforderlich geworden sind. Interface Definition Language (IDL) hat mehrere Möglichkeiten, eine solche Neuzuordnung zu erleichtern, nämlich [call_as], [transmit_as] und [wire_marshal]. Das Attribut [call_as] führt einen Funktions wrapper auf dem Client und Server ein. Beide werden zwischen dem Benutzercode und dem Marshaller platziert. Die anderen Attribute befassen sich mit der direkten Typzuordnung. Bei Erweiterungsproblemen wird [call_as] am häufigsten verwendet und ist am einfachsten zu verstehen und ohne Fallstricke zu bearbeiten.

  5. Ändern Sie Datentypen über eine standardmäßige Union.

    Das Ändern eines Attributs oder Datentyps führt in der Regel zu Einer Drahtinkompatibilität. Beispiele finden Sie unter Beispiele für inkompatible Änderungen . Im Fall einer Union ohne Standardklausel kann die Inkompatibilität jedoch ähnlich wie bei einem Verfahren außerhalb des Bereichs verwaltet werden, wie zuvor beschrieben. Dieses Schema kann problemlos auf die beliebten XxxINFO-Typen angewendet werden, die Unions verwenden.

    Ein Aufruf wie dieser

    XxxGetInfo( [in] level, [out] XxxINFO  * pInfo );
    

    kann Informationen auf Ebene 1, 2 oder 3 zurückgeben, wobei XxxINFO eine Union mit drei Zweigen ist: 1, 2 und 3.

  6. Verwenden Sie das [range]-Attribut, um bereich anzugeben.

    Sie können das [range]-Attribut für einen einfachen Skalierungstyp angeben, ohne die Abwärtskompatibilität zu beeinträchtigen. Dieses Attribut wirkt sich nicht auf das Kabelformat aus, aber beim Aufheben der Verbindung überprüft RPC den Wert in der Verbindung, um zu bestätigen, dass er sich innerhalb des in der IDL-Datei angegebenen Bereichs befindet. Andernfalls wird eine RPC_X_INVALID_BOUND Ausnahme ausgelöst. Dies ist besonders nützlich, wenn der Server die maximale Größe eines Arrays kennt.

    Beispiel:

    HRESULT Method1( [in, range(0,100)] ULONG m, [size_is(m)] ULONG *plong); 
    

Das RPC-Verhalten, wenn die angegebene Ebene 4 ist und der Arm fehlt, hängt von der Definition der Union ab. Bei einer Union mit der definierten Standardklausel überträgt RPC einen typ, der in der Standardklausel angegeben ist, um sich von den bekannten Armbezeichnungen zu unterscheiden (in diesem Fall alles andere als 1, 2 oder 3). Bei einer standardmäßigen Union löst der Unmarshaler eine Ausnahme aus, da es per Definition keine Standardeinstellung gibt, auf die zurückgesetzt werden kann. Die Ausnahme ist RPC_S_INVALID_TAG.

Auch hier kann ein neuer Client sein Verhalten anpassen, wenn er feststellt, dass er einen alten Server aufgerufen hat.

Aus diesen empfohlenen Methoden folgt: Wenn ein remotable-Datentyp entworfen werden muss, der in Zukunft erweitert werden kann, verwenden Sie eine standardmäßige Union in der IDL-Datei. Bei einer Auswahl ist eine gekapselte Union etwas sauberer.

Aufgrund von Eigenheiten der internen Darstellung des NDR64-Drahtprotokolls muss die weiter oben in diesem Abschnitt angegebene Empfehlung für das Hinzufügen von Waffen wie folgt qualifiziert werden: Der neue Arm, der hinzugefügt wird, kann die Ausrichtung der Union nicht ändern, und insbesondere sollte sich die größte Ausrichtung der Arme nicht ändern. Dies ist in der Regel kein Problem, da ein Zeiger in einem Arm die Ausrichtung auf 8 erzwingt. Ein Design, bei dem jeder Arm ein Zeiger auf einen Armtyp ist, ist eine sauber Möglichkeit, die Anforderung zu erfüllen.