IMarshal 인터페이스(objidl.h)

COM 개체가 해당 인터페이스 포인터의 마샬링을 정의하고 관리할 수 있도록 합니다.

상속

IMarshal 인터페이스는 IUnknown 인터페이스에서 상속됩니다. IMarshal 에는 다음과 같은 유형의 멤버도 있습니다.

메서드

IMarshal 인터페이스에는 이러한 메서드가 있습니다.

 
IMarshal::D isconnectObject

IMarshal::D isconnectObject 메서드(objidl.h)는 종료하기 전에 개체에 대한 모든 연결을 해제합니다.
IMarshal::GetMarshalSizeMax

마샬링하는 동안 필요한 버퍼의 최대 크기를 검색합니다.
IMarshal::GetUnmarshalClass

경계 해제 코드의 CLSID를 검색합니다.
IMarshal::MarshalInterface

IMarshal::MarshalInterface 메서드(objidl.h)는 인터페이스 포인터를 마샬링합니다.
IMarshal::ReleaseMarshalData

IMarshal::ReleaseMarshalData 메서드(objidl.h)는 마샬링된 데이터 패킷을 삭제합니다.
IMarshal::UnmarshalInterface

IMarshal::UnmarshalInterface 메서드(objidl.h)는 인터페이스 포인터를 숨기지 않습니다.

설명

마샬링 은 데이터를 다른 프로세스 또는 컴퓨터로 전송하기 위해 패킷으로 패키징하는 프로세스입니다. 경계 해제는 수신 끝에서 해당 데이터를 복구하는 프로세스입니다. 지정된 호출에서 메서드 인수는 한 방향으로 마샬링되고 마샬링되지 않은 반면 반환 값은 마샬링되고 다른 방향으로는 마샬링되지 않습니다.

마샬링이 모든 데이터 형식에 적용되지만 인터페이스 포인터에는 특별한 처리가 필요합니다. 근본적인 문제는 한 주소 공간에서 실행되는 클라이언트 코드가 다른 주소 공간에 있는 개체의 인터페이스에 대한 포인터를 올바르게 역참조할 수 있는 방법입니다. COM 솔루션은 클라이언트 애플리케이션이 클라이언트 프로세스에 있는 서로게이트 개체 또는 프록시를 통해 원래 개체와 통신하는 것입니다. 프록시는 원래 개체의 인터페이스에 대한 참조를 보유하고 클라이언트에 인터페이스 자체에 대한 포인터를 건네 주세요. 클라이언트가 원래 개체에서 인터페이스 메서드를 호출하는 경우 해당 호출은 실제로 프록시로 진행됩니다. 따라서 클라이언트의 관점에서 모든 호출이 처리 중입니다.

호출을 수신할 때 프록시는 메서드 인수를 마샬링하고 RPC와 같은 일부 프로세스 간 통신 수단을 통해 서버 프로세스의 코드에 전달하여 인수를 숨기지 않고 원래 개체에 전달합니다. 이 동일한 코드 마샬링이 프록시로 다시 전송하기 위한 값을 반환합니다. 이 값은 값을 숨기지 않고 클라이언트 애플리케이션에 전달합니다.

IMarshal 은 클라이언트 프로세스에서 프록시를 만들고, 초기화하고, 관리하는 메서드를 제공합니다. 프록시가 원래 개체와 통신하는 방법을 지시하지 않습니다. IMarshal의 COM 기본 구현은 RPC를 사용합니다. 이 인터페이스를 직접 구현할 때 애플리케이션에 적합한 것으로 간주되는 프로세스 간 통신 방법(공유 메모리, 명명된 파이프, 창 핸들, RPC)을 자유롭게 선택할 수 있습니다.

IMarshal 기본 구현

COM은 IMarshal 인터페이스의 자체 내부 구현을 사용하여 자체 구현을 제공하지 않는 모든 개체를 마샬링합니다. COM은 IMarshal에 대한 개체를 쿼리하여 이 결정을 내린다. 인터페이스가 누락된 경우 COM은 기본적으로 내부 구현으로 설정됩니다.

IMarshal의 COM 기본 구현은 각 개체에 대해 제네릭 프록시를 사용하고 개체에 구현된 각 인터페이스에 대해 필요에 따라 개별 스텁 및 프록시를 만듭니다. COM은 지정된 개체가 구현할 수 있는 특정 인터페이스를 미리 알 수 없으므로 이 메커니즘이 필요합니다. COM 기본 마샬링을 사용하지 않고 대신 자신의 프록시 및 마샬링 루틴을 작성하도록 선택한 개발자는 컴파일 시간에 개체에서 찾을 수 있는 모든 인터페이스를 알고 있으므로 필요한 마샬링 코드를 정확하게 이해합니다. COM은 모든 개체에 대한 마샬링 지원을 제공할 때 런타임에 마샬링을 수행해야 합니다.

인터페이스 프록시는 클라이언트 프로세스에 있습니다. 인터페이스 스텁이 서버에 상주합니다. 각 쌍은 함께 인터페이스에 대한 모든 마샬링을 처리합니다. 각 인터페이스 프록시의 작업은 인수를 마샬링하고 반환 값을 마샬링하지 않고 해당 인터페이스에 대한 후속 호출에서 앞뒤로 전달되는 매개 변수를 출력하는 것입니다. 각 인터페이스 스텁의 작업은 함수 인수를 숨기지 않고 원래 개체에 전달한 다음 반환 값과 개체가 반환하는 매개 변수를 마샬링하는 것입니다.

프록시 및 스텁은 프로세스 간 통신에 시스템의 RPC 인프라를 활용하는 RPC(원격 프로시저 호출) 채널을 통해 통신합니다. RPC 채널은 인터페이스 프록시와 스텁이 모두 포인터를 보유하는 단일 인터페이스 IRpcChannelBuffer를 구현합니다. 프록시 및 스텁은 인터페이스를 호출하여 마샬링 패킷을 가져오고, 해당 패킷에 데이터를 보내고, 완료되면 패킷을 삭제합니다. 인터페이스 스텁에는 원래 개체에 대한 포인터도 있습니다.

지정된 인터페이스의 경우 프록시와 스텁은 모두 동일한 클래스의 인스턴스로 구현되며, 이는 ProxyStubClsid32 레이블 아래 시스템 레지스트리의 각 인터페이스에 대해 나열됩니다. 이 항목은 인터페이스의 IID를 프록시 및 스텁 개체의 CLSID 에 매핑합니다. COM에서 인터페이스를 마샬링해야 하는 경우 시스템 레지스트리에서 적절한 CLSID를 가져옵니다. 이 CLSID 로 식별된 서버는 인터페이스 프록시와 인터페이스 스텁을 모두 구현합니다.

대부분의 경우 이 CLSID 가 참조하는 클래스는 입력이 일부 인터페이스 설명 언어로 작성된 지정된 인터페이스의 함수 서명 및 의미 체계에 대한 설명인 도구에 의해 자동으로 생성됩니다. 이러한 언어를 사용하는 것이 좋으며 정확도를 위해 권장되지만 그렇게 할 필요는 없습니다. 프록시 및 스텁은 RPC 인프라에서 사용하는 COM 구성 요소일 뿐이며 올바른 외부 계약이 유지되는 한 원하는 방식으로 작성할 수 있습니다. 새 인터페이스를 디자인하는 프로그래머가 존재하는 모든 인터페이스 프록시 및 스텁이 마샬링된 데이터의 표현에 동의하도록 할 책임이 있습니다.

생성되면 인터페이스 프록시는 항상 개체 전체를 나타내는 더 큰 프록시로 집계됩니다. 또한 이 개체 프록시는 프록시 관리자라고 하는 COM 제네릭 프록시 개체를 집계합니다. 프록시 관리자는 IUnknownIMarshal이라는 두 가지 인터페이스를 구현합니다. 개체에 구현될 수 있는 다른 모든 인터페이스는 개별 인터페이스 프록시의 집계를 통해 개체 프록시에 노출됩니다. 개체 프록시에 대한 포인터가 있는 클라이언트는 실제 개체에 대한 포인터를 보유합니다.

클라이언트가 완전히 다른 개체에 구현된 동일한 인터페이스에 대한 호출을 구분할 수 있도록 클라이언트 프로세스에서 개체 전체를 나타내는 프록시가 필요합니다. 그러나 모든 인터페이스 스텁이 생성된 개체와만 통신하기 때문에 개체 자체가 있는 서버 프로세스에는 이러한 요구 사항이 없습니다. 다른 연결은 불가능합니다.

인터페이스 스텁은 인터페이스 프록시와 달리 일부 외부 클라이언트가 더 큰 전체의 일부로 표시될 필요가 없으므로 집계되지 않습니다. 연결되면 인터페이스 스텁에 수신하는 메서드 호출을 전달해야 하는 서버 개체에 대한 포인터가 제공됩니다. 스텁 관리자를 개념적으로 참조하는 것이 유용하지만, 지정된 개체의 원격 서비스를 제공하는 서버 쪽 RPC 인프라의 코드 및 상태를 의미하지만 코드와 상태가 특정하고 잘 지정된 형식을 취해야 한다는 직접적인 요구 사항은 없습니다.

클라이언트가 특정 개체의 인터페이스에 대한 포인터를 처음 요청할 때 COM은 서버 프로세스에서 IClassFactory 스텁을 로드하고 이를 사용하여 첫 번째 포인터를 클라이언트로 다시 마샬링합니다. 클라이언트 프로세스에서 COM은 클래스 팩터리 개체에 대한 제네릭 프록시를 로드하고 IMarshal 의 구현을 호출하여 첫 번째 포인터를 숨기지 않습니다. 그런 다음 COM은 첫 번째 인터페이스 프록시를 만들고 RPC 채널에 대한 포인터를 건네줍니다. 마지막으로 COM은 IClassFactory 포인터를 클라이언트에 반환합니다. 이 포인터를 사용하여 IClassFactory::CreateInstance를 호출하고 인터페이스에 대한 참조를 전달합니다.

서버 프로세스로 돌아가서 COM은 이제 요청된 인터페이스에 대한 스텁과 함께 개체의 새 instance 만듭니다. 이 스텁은 인터페이스 포인터를 클라이언트 프로세스로 다시 마샬링합니다. 여기서 다른 개체 프록시가 만들어지고, 이번에는 개체 자체에 대해 마샬링됩니다. 또한 생성된 는 요청된 인터페이스에 대한 프록시이며 클라이언트에 반환되는 포인터입니다. 개체의 다른 인터페이스에 대한 후속 호출을 통해 COM은 필요에 따라 적절한 인터페이스 스텁 및 프록시를 로드합니다.

새 인터페이스 프록시를 만들 때 COM은 모든 QueryInterface 호출을 위임하는 프록시 관리자의 IUnknown 구현에 대한 포인터를 제공합니다. 각 인터페이스 프록시는 자체 인터페이스인 IRpcProxyBuffer를 나타내는 인터페이스의 두 가지 인터페이스를 구현합니다. 인터페이스 프록시는 프록시 관리자에서 QueryInterface 를 호출하여 포인터를 가져올 수 있는 자체 인터페이스를 클라이언트에 직접 노출합니다. 그러나 COM만 RPC 채널에 프록시를 연결하고 연결을 끊는 데 사용되는 IRpcProxyBuffer를 호출할 수 있습니다. 클라이언트는 인터페이스 프록시를 쿼리하여 IRpcProxyBuffer 인터페이스에 대한 포인터를 가져올 수 없습니다.

서버 쪽에서 각 인터페이스 스텁은 IRpcStubBuffer를 구현합니다. 스텁 관리자 역할을 하는 서버 코드는 IRpcStubBuffer::Connect 를 호출하고 해당 개체의 IUnknown 포인터를 인터페이스 스텁에 전달합니다.

인터페이스 프록시는 메서드 호출을 받으면 IRpcChannelBuffer::GetBuffer 호출을 통해 RPC 채널에서 마샬링 패킷을 가져옵니다. 인수를 마샬링하는 프로세스는 데이터를 버퍼에 복사합니다. 마샬링이 완료되면 인터페이스 프록시는 IRpcChannelBuffer::SendReceive 를 호출하여 마샬링된 패킷을 해당 인터페이스 스텁으로 보냅니다. IRpcChannelBuffer::SendReceive가 반환되면 인수가 마샬링된 버퍼가 인터페이스 스텁에서 마샬링된 반환 값을 포함하는 새 버퍼로 대체됩니다. 인터페이스 프록시는 반환 값을 언마샬링하고, IRpcChannelBuffer::FreeBuffer 를 호출하여 버퍼를 해제한 다음, 반환 값을 메서드의 원래 호출자에게 반환합니다.

IRpcChannelBuffer::SendReceive의 구현으로, 실제로 서버 프로세스에 요청을 보내고 서버 프로세스를 식별하는 방법과 해당 프로세스 내에서 요청을 보내야 하는 개체를 알고 있습니다. 채널 구현은 요청을 해당 프로세스의 적절한 스텁 관리자로 전달하는 방법도 알고 있습니다. 인터페이스 스텁은 제공된 버퍼에서 인수를 분리하고, 서버 개체에서 표시된 메서드를 호출하고, 반환 값을 IRpcChannelBuffer::GetBuffer 호출에 의해 할당된 새 버퍼로 다시 마샬링합니다. 그런 다음 채널은 반환 데이터 패킷을 인터페이스 프록시로 다시 전송합니다. 이 패킷은 여전히 인터페이스 프록시로 반환되는 IRpcChannelBuffer::SendReceive의 중간에 있습니다.

인터페이스 프록시의 특정 instance 다음 조건이 충족되는 한 둘 이상의 인터페이스를 서비스하는 데 사용할 수 있습니다.

  • 영향을 받는 인터페이스의 IID는 시스템 레지스트리의 적절한 ProxyStubClsid 에 매핑되어야 합니다.
  • 인터페이스 프록시는 IUnknownIRpcProxyBuffer뿐만 아니라 한 지원되는 인터페이스에서 다른 인터페이스로의 QueryInterface 호출을 지원해야 합니다.
인터페이스 스텁의 단일 instance 둘 이상의 인터페이스를 서비스할 수도 있지만 해당 인터페이스 집합에 엄격한 단일 상속 관계가 있는 경우에만 가능합니다. 이 제한은 스텁이 메서드 호출을 어떤 인터페이스에서 구현되는 메서드를 미리 알고 있는 경우에만 여러 인터페이스로 전송할 수 있기 때문입니다.

프록시 및 스텁은 다양한 시간에 메모리를 할당하거나 해제해야 합니다. 예를 들어 인터페이스 프록시는 호출자에게 매개 변수를 반환할 메모리를 할당해야 합니다. 이러한 측면에서 인터페이스 프록시 및 인터페이스 스텁은 표준 작업 할당자를 사용해야 한다는 점에서 일반적인 COM 구성 요소일 뿐입니다. ( CoGetMalloc를 참조하세요.)

요구 사항

요구 사항
지원되는 최소 클라이언트 Windows 2000 Professional [데스크톱 앱 | UWP 앱]
지원되는 최소 서버 Windows 2000 Server [데스크톱 앱 | UWP 앱]
대상 플랫폼 Windows
헤더 objidl.h(ObjIdl.h 포함)

추가 정보

IStdMarshalInfo