DirectX 9.0 의 소개 DirectX SDK 의 사용법 C 또는 C++ 에 의한 DirectX 프로그래밍 COM 의 사용법 COM 개체란   [목차열람] [주소복사] [슬롯비우기]
COM 개체란
 
Microsoft DirectX 9.0

COM 개체와는


구성 요소 개체 모델 (COM) 개체는, 기본적으로, 1 개 또는 복수의 태스크를 실행하기 위해서 애플리케이션으로 사용되는 블랙 박스와 같은 것이다. 동적 링크 라이브러리 (DLL)로서 처리 하는 것이 가장 일반적이다. 종래의 DLL 같이, COM 개체가 지원 하고 있는 모든 처리는, 개체에 의해 공개되고 있는 메서드를 애플리케이션으로부터 호출하는 것에 의해 실행할 수 있다. 애플리케이션이 COM 개체와 교환하는 방법은, C++ 개체와 교환하는 방법과 비슷하다. 다만, 이러한 사이에는 몇개의 현저한 차이점이 있다.

이 문서에는, 다음의 항목이 포함되어 있다.

개체와 인터페이스

개체와 인터페이스의 차이를 이해하는 것은 중요한 것이다. 개체는, 일상적으로, 그 주가 되는 인터페이스의 이름이라고 부르기도 한다. 그러나, 엄밀하게는, 이 2 개의 용어는 의미가 다르다.

  인터페이스를 공개하는 개체는, 반드시, 그 인터페이스 정의에 포함되는 모든 메서드를 지원 해야 한다. 바꾸어 말하면, 메서드를 호출할 때에, 그것이 존재할지 어떨지를 걱정할 필요는 없다. 다만, 각 메서드의 처리 방법은 개체에 따라서 다른 경우가 있다. 예를 들어, 최종적인 결과는 같아도, 개체에 의해, 사용하는 알고리즘이 다른 경우가 있다. 또, 메서드의 모든 기능이 지원 되고 있다고 하는 보증은 없다. 개체가 일반적인 인터페이스를 공개 할 때 그 인터페이스에 속하는 메서드군의 서브 세트를 지원 하는 것만으로 좋은 경우가 있다. 이 때, 지원되지 않은 메서드도 정상적으로 호출할 수가 있지만, E_NOTIMPL 가 반환된다. 개체의 문서를 참조해, 각 개체에서의 인터페이스의 처리 상태를 확인하는 것을 권한다.

COM 표준에서는, 공개 끝난 인터페이스 정의는 변경할 수 없게 되어 있다. 예를 들어, 기존의 인터페이스에 새로운 메서드를 추가할 수 없다. 인터페이스를 변경하는 것이 아니라, 새로운 인터페이스를 생성 할 필요가 있다. 인터페이스에 반드시 포함하지 않으면 안 되는 메서드등의 제약은 없지만, 새로운 세대의 인터페이스에는, 그 바탕으로 되어 있는 인터페이스의 모든 메서드와 추가되는 새로운 메서드를 포함하는 것이 일반적이다.

1 개의 인터페이스에 복수의 세대가 존재하는 일도 드물지 않다. 보통, 어느 세대라도 본질적으로 전체적으로는 같은 태스크를 실행하지만, 세부가 차이가 난다. 많은 경우, 개체는 모든 세대의 인터페이스를 공개한다. 이것에 의해, 낡은 애플리케이션에서는, 개체의 낡은 인터페이스를 계속해 사용해, 새로운 애플리케이션에서는, 새로운 인터페이스의 기능을 이용할 수가 있다. 보통, 1 살의 패밀리에 속하는 인터페이스에는 모두 같은 이름이 사용되어 거기에 세대를 나타내는 정수가 부가된다. 예를 들어, 초대의 인터페이스의 이름이 IMyInterface 이었다고 하면 다음의 2 세대의 이름은 IMyInterface2IMyInterface3 가 된다. DirectX 에서는, 보통, 각 세대의 인터페이스의 이름에 DirectX 의 버전 번호를 사용하고 있다.

GUID

글로벌 일의 식별자 (GUID)는, COM 프로그래밍 모델의 주요한 부분이다. GUID 를 가장 간단하게 설명 하면, GUID 는 128 비트의 구조체이다. 다만, GUID 를 생성 할 때는, 그 밖에 같은 GUID 가 존재하지 않는 것이 보증되지 않으면 안 된다. COM 에서는, 다음의 2 개의 목적이기 때문에, GUID 를 넓게 사용한다.

  보통, 문서로 개체나 인터페이스를 부를 때는, 알기 쉽게 IDirect3D9 등의 설명적인 이름이 사용된다. 문서에서는, 문맥에 의해 무엇을 나타내고 있는지를 알므로, 혼동 될 걱정은 거의 없다. 다만, 엄밀하게 말하면, 같은 설명적 이름을 가지는 개체 또는 인터페이스가 그 밖에 존재하지 않는다고 하는 보증은 없다. 특정의 개체 또는 인터페이스를 틀림없이 나타낼 수가 있는 유일한 방법은, GUID 에 의하는 것이다.

GUID 는 구조체이지만, 등가인 캐릭터 라인으로서 표현되는 일도 있다. GUID 의 캐릭터 라인 형식으로서 일반적인 것은, 32 진수의 정수에 의한 8-4-4-4-12 형식이다. 즉,"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} " 가 되어,x 는 16 진수의 정수에 대응한다. 예를 들어,IDirect3D9 인터페이스의 IID 를 캐릭터 라인 형식에서 나타내면 다음과 같이 된다.

{1DD9E8DA-1C77-4D40-B0CF-98FEFDFF9512}

실제의 GUID 는 사용하기 어렵고, 오입력하기 쉽기 때문에, 보통은, GUID 와 함께 등가인 이름도 준비된다. CoCreateInstance 등의 함수를 호출할 때에, 실제의 구조체 대신에 이 이름을 사용할 수 있다. 관습적인 명명 규칙으로서 인터페이스 및 개체의 설명적인 이름의 선두에는, 각각 IID_ 및 CLSID_ 를 붙일 수 있다. 예를 들어,IDirect3D9 인터페이스의 IID 의 이름은 IID_IDirect3D8 가 된다.

HRESULT 값

모든 COM 메서드는,HRESULT 로 불리는 32 비트의 정수를 돌려준다. 대부분의 메서드에서는,HRESULT 는 기본적으로 1 개의 구조체를 형성해, 다음의 2 개의 독립한 정보를 포함하고 있다.

일부의 메서드는, Winerror.h 에 표준 세트로서 정의되고 있는 값만을 HRESULT 값으로 돌려준다. 다만, 메서드는, 보다 전문적인 정보를 나타내는 커스텀 HRESULT 값도 돌려줄 수가 있다. 보통, 이러한 값은, 메서드의 레퍼런스 페이지에 기재되어 있다.

  메서드의 레퍼런스 페이지의 리스트에 기재되어 있는 HRESULT 값은, 돌려주어질 가능성이 있는 값의 서브 세트 뿐인 경우가 많다. 보통, 이 리스트에는, 메서드 고유의 값과 메서드 고유의 의미를 가지는 표준의 값만이 기재되어 있다. 문서에 명시적으로 기재되지 않아도, 메서드로부터는, 다양한 표준의 HRESULT 값이 돌려주어질 가능성이 있다.

HRESULT 값은 에러 정보를 돌려주기 위해서(때문에) 사용되는 경우가 많지만, 이것들을 에러 코드라고 봐서는 안 된다. HRESULT 값에는, 값상세 정보를 포함한 비트와 정부를 나타내는 비트가 독립해 저장 되고 있기 (위해)때문에, 정부를 나타내는 코드를 몇개에서도 포함할 수가 있다. 관습에 의해, 성공 코드에는 S_ 라고 하는 접두어를 붙일 수 있어 실패를 나타내는 코드에는 E_ 라고 하는 접두어를 붙일 수 있다. 예를 들어, 가장 일반적으로 사용되는 코드에 S_OK 및 E_FAIL 가 있다. 각각, 단지 성공 또는 실패를 나타내고 있다.

COM 메서드가 정부를 나타내는 다양한 코드를 돌려준다고 하는 것은,HRESULT 값의 테스트 방법으로 주의가 필요한 것을 의미한다. 예를 들어, 문서에 기재되어 있는 반환값을 사용해, 성공의 경우는 S_OK 가 돌려주어져 실패의 경우는 E_FAIL 가 반환된다고 하는 가설에 근거해 테스트를 실시했다고 한다. 그러나, 메서드로부터는, 이외의 실패 또는 성공을 나타내는 코드가 돌려주어질 가능성도 있다. 다음 코드는, 단순한 테스트를 이용했을 경우의 위험성을 나타내고 있다. hr 는, 메서드에 의해 돌려주어진 HRESULT 값이다.

if(hr == E_FAIL)
{
    //Handle the failure
}

else
{
    //Handle the success
}

메서드가 실패를 나타내기 위해서(때문에) 돌려주는 값이 E_FAIL 뿐인 한, 이 테스트는 올바르게 기능한다. 그러나, 메서드로부터, E_NOTIMPL 나 E_INVALIDARG 등의 에러값이 돌려주어질 가능성도 있다. 이러한 값은 성공으로서 해석되어 애플리케이션으로 에러가 발생하는 원인이 된다.

메서드의 호출의 결과에 관한 상세한 정보가 필요한 경우는, 관계가 있는 각 HRESULT 값을 테스트할 필요가 있다. 그러나, 필요한 정보가, 성공인가 실패인가만의 경우도 있다. HRESULT 값이 성공을 나타내고 있는지 실패를 나타내고 있는지를 테스트하는 강력한 방법으로서 Winerror.h 에 정의되고 있는 다음의 매크로의 어느 쪽인가에 HRESULT 값을 건네줄 수가 있다.

FAILED 매크로를 사용하면 전술의 코드를 다음과 같이 수정할 수 있다.

if(FAILED(hr))
{
   //Handle the failure
}

else
{
   //Handle the success
}

이 코드는, E_NOTIMPL 나 E_INVALIDARG 를 실패로서 올바르게 처리한다.

대부분의 COM 메서드는 구조화 된 HRESULT 값을 돌려주지만, 일부의 소수의 메서드에서는 HRESULT 를 사용해 단순한 1 개의 정수를 돌려준다. 이러한 메서드는, 비명시적으로 항상 성공한다. 이런 종류의 HRESULTSUCCEEDED 매크로에 건네주면 매크로로부터는 반드시 TRUE 가 반환된다. 일반적으로 사용되는 예로서IUnknown::Release 메서드가 있다. 이 메서드는, 개체의 참조 카운트를 1 개씩 감소 해, 현재의 참조 카운트를 돌려준다. 참조 카운트의 설명에 대해서는, 「COM 개체의 수명의 관리」를 참조할것.

포인터의 주소

COM 메서드의 레퍼런스 페이지를 참조 하면, 다음과 같은 표기가 발견된다.

HRESULT CreateDevice(..., IDirect3DDevice9 **ppReturnedDeviceInterface);

COM 에서는, C 나 C++ 에서도 사용되는 보통의 포인터 외에, 이제 1 개별의 레벨의 간접적 호출이 사용되는 일이 있다. 이 제 2 의 레벨의 간접적 호출은, 형태의 선언의 뒤에 계속되는 "**" 으로 나타나 보통, 변수명에는 "pp" 라고 하는 접두어가 붙는다. 전술의 예의 ppReturnedDeviceInterface 파라미터는, 일반적으로,IDirect3DDevice9 인터페이스의 포인터 주소라고 부른다.

C++ 와 달리, COM 개체의 메서드에 직접 액세스 할 것은 없다. 그 대신해, 메서드를 공개하고 있는 인터페이스의 포인터를 얻어올 필요가 있다. 메서드를 호출할 때는, C++ 의 메서드의 포인터를 호출하면 귀로 동일한 구문을 사용한다. 예를 들어,IMyInterface::DoSomething 메서드를 호출하려면 , 다음과 같은 구문을 사용한다.


IMyInterface *pMyIface;
...
pMyIface->DoSomething(...);

간접적 호출에 제 2 의 레벨이 필요한 것은, 인터페이스 포인터를 직접 생성 하지 않기 때문이다. 전술의 CreateDevice 메서드와 같은, 다양한 메서드의 1 개를 호출해야 한다. 이러한 메서드를 사용해 인터페이스 포인터를 얻어오려면, 목적의 인터페이스의 포인터를 변수로서 선언해, 그 변수의 주소를 메서드에 건네준다. 즉, 포인터의 주소를 메서드에 건네준다. 메서드가 돌아왔을 때, 변수는 요구된 인터페이스를 가리키고 있다. 이 포인터를 사용하면 그 인터페이스의 임의의 메서드를 호출할 수가 있다. 인터페이스 포인터의 사용법에 관한 더 자세한 정보는, 「COM 인터페이스의 사용법」을 참조할것.



© 2002 Microsoft Corporation. All rights reserved.
↑TOP