QueryInterface: 개체에서 탐색

개체의 인터페이스에 대한 초기 포인터가 있으면 COM에는 개체가 다른 특정 인터페이스를 지원하는지 여부를 확인하는 매우 간단한 메커니즘이 있으며, 그렇다면 포인터를 가져올 수 있습니다. (개체의 인터페이스에 대한 초기 포인터를 가져오는 방법에 대한 자세한 내용은 개체에 대한 포인터 가져오기를 참조하세요.) 이 메커니즘은 IUnknown 인터페이스의 QueryInterface 메서드입니다. 개체가 요청된 인터페이스를 지원하는 경우 메서드는 해당 인터페이스에 대한 포인터를 반환해야 합니다. 이렇게 하면 개체가 지원하는 인터페이스를 자유롭게 탐색할 수 있습니다. QueryInterface 는 협상이 성공하면 "지정된 계약을 지원합니까?" 요청을 해당 계약의 고성능 사용과 구분합니다.

클라이언트가 처음에 개체에 대한 액세스 권한을 얻게 되면 해당 클라이언트는 최소한 개체를 사용하여 개체를 사용할 때 개체에 알리고 QueryInterface를 호출하여 개체의 수명을 제어할 수 있는 IUnknown 인터페이스 포인터(가장 기본적인 인터페이스)를 받게 됩니다. 클라이언트는 관리되는 각 개체에 일부 작업을 수행하도록 요청하도록 프로그래밍되지만 IUnknown 인터페이스에는 해당 작업에 대한 함수가 없습니다. 대신 이러한 작업은 다른 인터페이스를 통해 표현됩니다. 따라서 클라이언트는 해당 인터페이스에 대한 개체와 협상하도록 프로그래밍됩니다. 특히 클라이언트는 QueryInterface 를 호출하여 클라이언트가 원하는 작업을 호출할 수 있는 인터페이스에 대한 개체를 요청합니다.

개체는 QueryInterface를 구현하므로 요청을 수락하거나 거부할 수 있습니다. 개체가 클라이언트의 요청을 수락하면 QueryInterface 는 요청된 인터페이스에 대한 새 포인터를 클라이언트에 반환합니다. 해당 인터페이스 포인터를 통해 클라이언트는 해당 인터페이스의 메서드에 액세스할 수 있습니다. 반면에 개체가 클라이언트의 요청을 거부하는 경우 QueryInterface 는 null 포인터(오류)를 반환하며 클라이언트에 원하는 함수를 호출할 포인터가 없습니다. 이 경우 클라이언트는 해당 가능성을 정상적으로 처리해야 합니다. 예를 들어 클라이언트에 개체의 인터페이스 A에 대한 포인터가 있고 인터페이스 B 및 C를 요청한다고 가정합니다. 또한 개체가 인터페이스 B를 지원하지만 인터페이스 C는 지원하지 않는다고 가정해 보겠습니다. 그 결과 개체는 B에 대한 포인터를 반환하고 C가 지원되지 않는다고 보고합니다.

핵심은 개체가 QueryInterface에 대한 호출을 거부하는 경우 클라이언트가 요청된 인터페이스를 통해 표현된 작업을 수행하도록 개체에 요청할 수 없다는 것입니다. 클라이언트에는 해당 인터페이스에서 메서드를 호출하는 인터페이스 포인터가 있어야 합니다. 개체가 요청된 포인터 제공을 거부하는 경우 클라이언트는 해당 개체로 의도한 대로 수행하지 않거나 덜 강력한 다른 인터페이스로 대체하려고 시도하여 수행하지 않도록 준비해야 합니다. COM 기능의 이 기능은 해당 함수를 호출할 때까지 함수가 작동하는지 여부를 알 수 없는 다른 개체 지향 시스템과 비교하여 잘 작동하며, 그 후에도 오류 처리가 불확실합니다. QueryInterface 는 메서드를 호출하기 전에 개체가 인터페이스를 지원하는지 여부를 알 수 있는 안정적이고 일관된 방법을 제공합니다.

또한 QueryInterface 메서드는 개체가 지정된 계약을 지원하지 않음을 나타내는 강력하고 신뢰할 수 있는 방법을 제공합니다. 즉, QueryInterface 호출에서 "이전" 개체가 "새" 인터페이스(예: 이전 개체가 배송된 후 발명된 인터페이스)를 지원하는지 여부를 묻는 경우 이전 개체는 충돌을 일으키지 않고 안정적으로 "아니요"라고 대답합니다. 이를 지원하는 기술은 IID가 할당되는 알고리즘입니다. 이는 작은 점처럼 보일 수 있지만 시스템의 전체 아키텍처에 매우 중요하며, 새로운 기능에 대한 레거시 요소를 조회하는 기능은 놀랍게도 대부분의 다른 개체 아키텍처에 없는 기능입니다.

IUnknown 사용 및 구현