다음을 통해 공유


이전 버전과 호환되는 방식으로 인터페이스 변경

RPC 및 COM에 대한 버전 관리 이론에 설명된 메서드는 여러 가지 이유로 허용되지 않을 수 있습니다. 규칙에 따라 인터페이스 버전을 변경하려면 기본적으로 새 클라이언트가 이전 서버와 통신하지 않도록 해야 합니다. 이는 상용 소프트웨어가 필드에 배포되는 경우 종종 불가능합니다. Windows에서 변경된 GUID 또는 버전이 없는 인터페이스 변경이 도입된 경우도 있습니다. 이는 새 클라이언트가 레거시 서버와 통신해야 하는 결과이며, 새 클라이언트가 이전 인터페이스와 새 인터페이스를 모두 지원하는 솔루션이 바람직하지 않은 것으로 간주되었기 때문입니다.

모범 사례

인터페이스 GUID 및 버전을 변경할 수 없는 경우 유선 비호환성 문제를 해결하는 합리적인 방법입니다.

  1. 애플리케이션이 다른 쪽의 기능을 인식하게 합니다.

    클라이언트와 서버에는 각각(또는 적어도 새 클라이언트)이 파트너의 ID를 설정할 수 있는 프로토콜이 있습니다. 일반적으로 새 클라이언트가 이전 서버와 새 서버에서 지원하는 기능을 인식하도록 하기에 충분합니다. 이 작업은 애플리케이션이 연결 컨텍스트를 유지하고 RPC 작업을 수행하기 전에 클라이언트에서 실행한 XxxGetInfo 형식의 함수 호출을 통해 지원될 때 쉽게 수행할 수 있습니다. 애플리케이션이 서버별 릴리스 기준으로 기능을 관리하는 경우 애플리케이션이 어떤 서버에 대해 호출을 실행하도록 제어하기 때문에 이전 서버/클라이언트와 호환되지 않는 호출이 발생할 수 없습니다. 결론은 애플리케이션이 불일치가 발생하지 않도록 사전에 대응한다는 것입니다. 이는 두 번째 연습과 함께 수행될 수 있습니다.

  2. 새 원격 API를 소개합니다.

    새 원격 메서드는 인터페이스의 맨 끝에 추가된 경우 기존 메서드와 충돌하지 않습니다. 이전 클라이언트는 항상 새 서버를 호출할 수 있습니다. 호출되는 서버에서 발생하는 오류를 감시하는 경우 새 클라이언트는 서버의 ID를 모르고 새 메서드를 호출할 수 있습니다. RPC 런타임은 항상 디스패치 전에 각 인터페이스에 대한 메서드 번호를 확인하여 메서드가 적절한 v-테이블 내에 있는지 확인합니다. 서버에 알 수 없는 메서드의 경우 RPC 런타임에서 예외 RPC_S_PROCNUM_OUT_OF_RANGE 발생합니다. 이 예외는 이 특정 상황에서만 발생합니다. 따라서 새 클라이언트는 호출이 이전 서버로 이동하고 해당 동작을 정상적으로 수정할 수 있다는 신호로 예외에 대해 watch 수 있습니다.

  3. 새 메서드에서만 새 매개 변수 또는 새 데이터 형식을 소개합니다.

    새 메서드를 도입하는 한 가지 이유는 데이터 비호환성을 방지하기 위한 것입니다. 새 데이터 형식이 도입되거나 단순히 수정되는 경우 원칙적이면 새 메서드(또는 메서드)에서만 사용해야 합니다. 호환되지 않는 데이터 형식 변경 예제는 호환되지 않는 변경 예제를 참조하세요. 이 규칙의 유일한 주목할 만한 예외는 항목 4에 설명되어 있습니다.

  4. 래퍼를 통해 새 매개 변수 또는 새 데이터 형식을 매핑합니다.

    이 솔루션은 새 매개 변수 또는 데이터 형식을 사용자에게 노출해야 하지만 실제로는 별도로 원격으로 연결할 필요가 없거나 이전 데이터 형식 또는 매개 변수에 매핑될 수 있는 경우에 적용됩니다. 예를 들어 많은 시스템 API가 돌아서서 원격 호출을 실행합니다. 사용자가 알려진 데이터 형식에서 기본 RPC 호출에 실제로 사용되는 데이터 형식으로 매핑할 수도 있거나 그렇지 않을 수도 있습니다. 따라서 사용자 인터페이스의 변경 내용이 원격 인터페이스에 대한 변경으로 전파되어야 하는지 항상 검사할 가치가 있습니다.

    사용자가 원격 API를 직접 호출할 때도 비슷한 상황이 발생할 수 있지만 새 형식 매핑 또는 필요한 기타 추가 작업을 수행하도록 래퍼를 도입할 수 있습니다. IDL(인터페이스 정의 언어)에는 [call_as], [transmit_as] 및 [wire_marshal]와 같은 다시 매핑을 용이하게 하는 여러 가지 방법이 있습니다. [call_as] 특성은 클라이언트와 서버에 함수 래퍼를 도입합니다. 둘 다 사용자 코드와 마샬러 사이에 배치됩니다. 다른 특성은 직접 형식 매핑을 처리합니다. 확장 문제의 경우 [call_as]이 가장 자주 사용되며 함정 없이 이해하고 조작하는 것이 가장 쉽습니다.

  5. 기본값 없는 공용 구조체를 통해 데이터 형식을 수정합니다.

    특성 또는 데이터 형식을 변경하면 일반적으로 유선 비호환성이 발생합니다. 예제는 호환되지 않는 변경 예제를 참조하세요. 그러나 기본 절이 없는 공용 구조체의 경우 이전에 설명한 대로 범위를 벗어난 프로시저의 경우와 유사한 방식으로 비호환성을 관리할 수 있습니다. 이 체계는 공용 구조체를 사용하는 인기 있는 XxxINFO 형식에 쉽게 적용할 수 있습니다.

    예를 들어 다음과 같은 호출

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

    는 수준 1, 2 또는 3에서 정보를 반환할 수 있으며 XxxINFO 는 1, 2 및 3의 세 분기가 있는 공용 구조체입니다.

  6. [range] 특성을 사용하여 범위를 지정합니다.

    이전 버전과의 호환성을 손상하지 않고 간단한 배율 형식에서 [range] 특성을 지정할 수 있습니다. 이 특성은 와이어 형식에 영향을 주지 않지만, 경계를 해제하는 동안 RPC는 와이어의 값을 확인하여 .idl 파일에 지정된 범위 내에 있는지 확인합니다. 그렇지 않으면 RPC_X_INVALID_BOUND 예외가 throw됩니다. 이는 서버가 크기가 큰 배열의 최대 크기를 알고 있는 경우에 특히 유용합니다.

    예:

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

표시된 수준이 4이고 팔이 누락된 경우 RPC 동작은 공용 구조체의 정의에 따라 달라집니다. 기본 절이 정의된 공용 구조체의 경우 RPC는 알려진 arm 레이블과 다른 항목에 대해 기본 절에 표시된 형식을 전송합니다(이 경우 1, 2 또는 3 이외의 항목). 기본값이 없는 공용 구조체의 경우 정의상 대체되는 기본값이 없으므로 unmarshaler는 예외를 발생합니다. 예외는 RPC_S_INVALID_TAG.

다시 말하지만 새 클라이언트는 이전 서버라고 하는 것을 발견할 때 동작을 조정할 수 있습니다.

이러한 권장 사례의 다음 사항은 나중에 확장할 수 있는 원격 가능 데이터 형식을 설계해야 하는 경우 IDL 파일에서 기본값 없는 공용 구조체를 사용한다는 것입니다. 선택의 여지가 있는 경우 캡슐화된 공용 구조체는 약간 더 깨끗합니다.

NDR64 와이어 프로토콜의 내부 표현의 단점으로 인해 이 섹션의 앞부분에서 제공된 무기를 추가하는 권장 사항은 다음과 같이 자격을 갖추어야 합니다. 추가되는 새 팔은 노조의 정렬을 변경할 수 없으며 특히 무기의 가장 큰 맞춤은 변경되지 않아야 합니다. 이것은 일반적으로 문제가 되지 않습니다., 8에 정렬 하는 군대의 포인터로. 각 팔이 팔 형식에 대한 포인터인 디자인은 요구 사항을 충족하는 한 가지 클린 방법입니다.