다음을 통해 공유


COM에서 개체 만들기

스레드가 COM 라이브러리를 초기화한 후에는 스레드에서 COM 인터페이스를 사용하는 것이 안전합니다. COM 인터페이스를 사용하려면 프로그램에서 먼저 해당 인터페이스를 구현하는 개체의 인스턴스를 만듭니다.

일반적으로 COM 개체를 만드는 방법에는 두 가지가 있습니다.

  • 개체를 구현하는 모듈은 해당 개체의 인스턴스를 만들도록 특별히 설계된 함수를 제공할 수 있습니다.
  • 또는 COM은 CoCreateInstance라는 제네릭 생성 함수를 제공합니다.

예를 들어 COM 인터페이스란?에서 가상 Shape 개체를 사용합니다. 이 예제에서 Shape 개체는 IDrawable이라는 인터페이스를 구현합니다. Shape 개체를 구현하는 그래픽 라이브러리는 다음 서명이 있는 함수를 내보낼 수 있습니다.

// Not an actual Windows function. 

HRESULT CreateShape(IDrawable** ppShape);

이 함수를 사용하면 다음과 같이 새 Shape 개체를 만들 수 있습니다.

IDrawable *pShape;

HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

ppShape 매개 변수는 포인터-포인터-IDrawable 형식입니다. 이전에 이 패턴을 보지 못했다면 이중 간접 참조가 당황스러울 수 있습니다.

CreateShape 함수의 요구 사항을 고려해 보세요. 함수는 호출자에게 IDrawable 포인터를 다시 제공해야 합니다. 그러나 함수의 반환 값은 오류/성공 코드에 이미 사용되었습니다. 따라서 함수에 대한 인수를 통해 포인터를 반환해야 합니다. 호출자는 형식 IDrawable*의 변수를 함수에 전달하고 함수는 이 변수를 새 IDrawable 포인터로 덮어씁니다. C++에서는 함수가 매개 변수 값을 덮어쓰는 방법에는 참조로 전달 또는 주소로 전달의 두 가지가 있습니다. COM은 후자인 주소로 전달을 사용합니다. 또한 포인터의 주소는 포인터-포인터이므로 매개 변수 형식은 IDrawable**이어야 합니다.

다음은 진행 중인 작업을 시각화하는 데 도움이 되는 다이어그램입니다.

이중 포인터 간접 참조를 보여 주는 다이어그램

CreateShape 함수는 pShape의 주소(&pShape)를 사용하여 pShape에 새 포인터 값을 씁니다.

CoCreateInstance: 개체를 만드는 일반적인 방법

CoCreateInstance 함수는 개체를 만들기 위한 제네릭 메커니즘을 제공합니다. CoCreateInstance를 이해하려면 두 개의 COM 개체가 동일한 인터페이스를 구현할 수 있고 한 개체는 둘 이상의 인터페이스를 구현할 수 있다는 사실에 유의하세요. 따라서 개체를 만드는 제네릭 함수에는 두 가지 정보가 필요합니다.

  • 만들 개체
  • 개체에서 가져올 인터페이스

그러나 함수를 호출할 때 이 정보를 표시하려면 어떻게 해야 할까요? COM에서 개체 또는 인터페이스는 GUID(Globally Unique Identifier)라고 하는 128비트 번호를 할당하여 식별됩니다. GUID는 효과적으로 고유하게 만드는 방식으로 생성됩니다. GUID는 중앙 등록 기관 없이 고유 식별자를 만드는 방법과 관련해서 발생하는 문제에 대한 솔루션입니다. GUID를 UUID(Universally Unique Identifier)라고도 합니다. COM 이전에는 DCE/RPC(분산 컴퓨팅 환경/원격 프로시저 호출)에서 사용되었습니다. 새 GUID를 만들기 위한 몇 가지 알고리즘이 있습니다. 이러한 모든 알고리즘이 고유성을 엄격하게 보장하는 것은 아니지만 동일한 GUID 값을 실수로 두 번 만들 확률은 매우 낮으며 사실상 제로입니다. GUID를 사용하여 개체 및 인터페이스뿐만 아니라 모든 종류의 엔터티를 식별할 수 있습니다. 그러나 이러한 점이 이 모듈에서 걱정스러운 유일한 사용 측면입니다.

예를 들어 Shapes 라이브러리는 두 개의 GUID 상수를 선언할 수 있습니다.

extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable; 

(이러한 상수의 실제 128비트 숫자 값이 다른 위치에 정의되어 있다고 가정할 수 있습니다.) 상수 CLSID_ShapeShape 개체를 식별하지만, 상수 IID_IDrawableIDrawable 인터페이스를 식별합니다. 접두사 "CLSID"는 ‘클래스 식별자’를 의미하며 접두사 IID는 ‘인터페이스 식별자’를 의미합니다. 이것은 COM의 표준 명명 규칙입니다.

이러한 값을 고려하여 다음과 같이 새 Shape 인스턴스를 만듭니다.

IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
     reinterpret_cast<void**>(&pShape));

if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

CoCreateInstance 함수에는 5개의 매개 변수가 있습니다. 첫 번째 및 네 번째 매개 변수는 클래스 식별자 및 인터페이스 식별자입니다. 실제로 이러한 매개 변수는 함수에 "Shape 개체를 만들고 IDrawable 인터페이스에 대한 포인터를 제공합니다."라고 전달합니다.

두 번째 매개 변수를 NULL로 설정합니다. (이 매개 변수의 의미에 대한 자세한 내용은 COM 설명서의 집계 항목을 참조하세요.) 세 번째 매개 변수는 개체의 ‘실행 컨텍스트’를 지정하는 것이 주된 목적인 플래그 집합을 사용합니다. 실행 컨텍스트는 개체가 애플리케이션과 동일한 프로세스에서 실행되는지, 동일한 컴퓨터의 다른 프로세스에서 실행되는지 또는 원격 컴퓨터에서 실행되는지를 지정합니다. 다음 표에서는 이 매개 변수에 대한 가장 일반적인 값을 보여 줍니다.

플래그 설명
CLSCTX_INPROC_SERVER 동일한 프로세스입니다.
CLSCTX_LOCAL_SERVER 다른 프로세스, 동일한 컴퓨터
CLSCTX_REMOTE_SERVER 다른 컴퓨터
CLSCTX_ALL 개체에서 지원하는 가장 효율적인 옵션을 사용합니다. (가장 효율적인 것부터 덜 효율적인 것까지의 순서는 in-process, out-of-process 및 컴퓨터 간입니다.)

 

특정 구성 요소에 대한 설명서에서는 개체가 지원하는 실행 컨텍스트를 알려줄 수 있습니다. 그렇지 않은 경우 CLSCTX_ALL을 사용합니다. 개체가 지원하지 않는 실행 컨텍스트를 요청하는 경우 CoCreateInstance 함수는 REGDB_E_CLASSNOTREG 오류 코드를 반환합니다. 이 오류 코드는 CLSID가 사용자의 컴퓨터에 등록된 구성 요소와 일치하지 않다는 사실을 나타낼 수도 있습니다.

CoCreateInstance의 다섯 번째 매개 변수는 인터페이스에 대한 포인터를 받습니다. CoCreateInstance는 제네릭 메커니즘이므로 이 매개 변수에 강력한 형식을 지정할 수 없습니다. 대신 데이터 형식은 void**이고 호출자는 포인터의 주소를 void** 형식으로 강제 변환해야 합니다. 이것은 이전 예제에서 reinterpret_cast의 용도에 해당합니다.

CoCreateInstance의 반환 값을 확인하는 것이 중요합니다. 함수가 오류 코드를 반환하는 경우 COM 인터페이스 포인터가 유효하지 않으며 역참조를 시도하면 프로그램이 충돌할 수 있습니다.

내부적으로 CoCreateInstance 함수는 다양한 기술을 사용하여 개체를 만듭니다. 가장 간단한 경우 레지스트리에서 클래스 식별자를 조회합니다. 레지스트리 진입점은 개체를 구현하는 DLL 또는 EXE를 가리킵니다. CoCreateInstance는 COM+ 카탈로그 또는 SxS(Side-by-Side) 매니페스트의 정보를 사용할 수도 있습니다. 그렇지만 세부 정보는 호출자에게 투명하게 공개됩니다. CoCreateInstance의 내부 세부 정보에 대한 자세한 내용은 COM 클라이언트 및 서버를 참조하세요.

사용 중인 Shapes 예제는 살짝 부자연스러우므로 이제 사용자가 파일을 선택할 수 있도록 열기 대화 상자를 표시하는 실제 COM 예제를 살펴보겠습니다.

다음

예: 열기 대화 상자