본문 바로가기

프로그래밍/C-CPP

[번역] COM 자동 초기화 자동 클린업

반응형

http://blogs.msmvps.com/gdicanio/2010/12/28/com-automatic-initialization-and-cleanup-and-text-to-speech/


COM 자동 초기화와 자동 클린업


CComPtr 인스턴스를 사용하는 COM 코드가 다음과 같다고 하자.


{

HRESULT hr = CoInitialize(NULL);

// 반환값 확인.


CComPtr<ISomeInterface> sp1;

CComPtr<IAnotherInterface> sp2;

// 인터페이스 포인터로 작업


CoUninitialize();


}


이 코드에는 미묘한 버그가 있다. 문제는 CoUninitialize 가 CComPtr 파괴자 전에 실행된다는 점이다. 옳바른 방법은 CoUninitialize 가 모든 COM 인터페이스 포인터가 (자신의 래핑된 CComPtr 파괴자에서) 릴리즈 된 이후에 와야한다.


그리고 여기엔 예외 안전성 문제도 있다. 코드블럭 중간에 어떤 예외가 던져진다(발생한다)면, CoUninitialize 함수는

불리지 않게 된다.


이 두가지 문제를 해결하기 위해, RAII 패턴을 따르는 C++ 클래스를 정의할 수 있다. 이 클래스의 생성자는 CoInitialize 를 호출하고, 초기화가 실패하면 예외를 던진다. 클래스의 파괴자는 CoUninitialize 를 호출한다. 따라서 모든 성공한 CoInitialize 호출은 (COM 프로그래밍 법칙이 요구하는 대로) 대응되는 CoUninitialize 을 갖게 된다.


나아가, 클래스 인스턴스가 스택에 생성되고, CComPtr (를 비롯한 COM 스마트 포인터들) 보다앞에 있다고 하면, oUninitialize 는 모든 CComPtr의 파괴자가 호출된 뒤에 마지막에 불리게 될 것이다.


{

// COM 자동 초기화와 자동 정리

CComAutoInit comInit;


CComPtr<ISomeInterface> sp1;

CComPtr<IAnotherInterface> sp2;


// 인터페이스 포인터로 작업


}


CComAutoInit 클래스의 완전한 코드는 원본 블로그포스트에 첨부되어 있다. (고 하는데 없더라.) 더불어 몇가지 부가적인 세부사항이 있다. 프라이빗 복사생성자와 =연산자가 정의되어 있어서, 이 클래스의 깊은복사를 막아 놓았다.


그리고, CComAutoInit 생성자의 익스플리싯 오버로드가 DWORD 인자를 받고, 이것은 CoInitializeEx 의 dwCoInit 인자로 쓰인다.


CComAuthInit 클래스를 어떻게 사용하는지를 보여주는 예제소스가 원본 블로그포스트에 첨부되어 있다. (고 하는데 없다.) 예제는 커맨드라인 인자로 주어진 단어를 "읽는" 예제 이다. (조금 더 복잡한 GUI MFC 버전은 MSDN Code Gallery 에서 찾을 수 있다.)



728x90