코딩캣: 코딩하는 고양이.
COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (7)
API/COM
2020. 10. 4. 14:13

COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가?

본 게시물은 ‘codeproject.com’에 게시된 글 ‘Introduction to COM - What It Is and How to Use It.’을 번역한 것입니다.

원 게시물은 https://www.codeproject.com/Articles/633/Introduction-to-COM-What-It-Is-and-How-to-Use-It에 게재되어 있습니다. 최대한 원문에 적힌 의도를 반영하고자 하였으나, 우리말로 읽었을 때 보다 자연스럽게 하고자 부득이 어순과 어휘를 조정한 부분도 있음을 양해 바랍니다.

또한 본 게시물에서 언급하고 있는 예제 소스 코드는 Visual C++ 6.0을 기준으로 작성되어 있기 때문에 후속 버전의 Visual Studio(또는 Visual Studio .NET)에서 자동 생성되는 COM 코드와는 다소 차이가 있음을 감안하고 읽으시기 바랍니다.

  1. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (1)
  2. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (2)
  3. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (3)
  4. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (4)
  5. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (5)
  6. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (6)
  7. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (7)
  8. COM의 소개(파트 1) – COM이 무엇이며, 어떻게 사용하는가? (8) [完]

 

함께 해 봅시다 – 예제 코드

아래 두 예제를 통해 본 글에서 다루었던 COM 개념들을 시연해보겠습니다.

 

단일 인터페이스를 가지고 COM 객체를 사용하기

첫 번째 예제는 하나의 인터페이스를 노출하고 있는 COM 객체를 어떻게 사용하는지를 보여주고 있습니다. 이 예제는 여러분이 앞으로 마주치게 될 소스 코드 중 가장 간단한 것입니다. 이 코드는 현재 바탕화면으로 지정된 그림파일의 이름을 얻기 위하여 쉘에 부속된 액티브 데스크톱 coclass를 사용합니다. 이 코드가 작동되기 위해서 여러분은 윈도우 운영체제에 액티브 데스크톱 기능이 설치되어 있어야 합니다.

이 예제에는 다음과 같은 단계가 포함됩니다.

1. COM 라이브러리를 초기화하기

2. 액티브 데스크톱과 상호작용하기 위해 사용되는 COM 객체를 생성하고, IActiveDesktop 인터페이스에 대한 포인터를 얻기

3. COM 객체에 있는 GetWallpaper 메소드를 호출하기

4. GetWallpaper 호출이 성공하면 바탕화면으로 지정된 그림파일의 이름을 얻기

5. 인터페이스를 포인터에 대해 Release 호출하기

6. COM 라이브러리를 정리하고 사용 해제하기

WCHAR wszWallpaper[MAX_PATH];
CString strPath;
HRESULT hr;
IActiveDesktop * pIAD;

// 1. COM 라이브러리를 초기화하기(윈도우 운영체제로 하여금 DLL 적재하게 하기)
// 일반적으로 여러분은 이 작업을 InitInstance나 기타 초기 호출 코드에서 할 것입니다.
// MFC에서는 AfxOleInit()을 대신 사용합니다.
CoInitialize(NULL);

// 2. 쉘이 제공하는 액티브 데스크톱 coclass를 사용하여 COM 객체를 생성합니다.
// 4번째 파라미터는 우리가 어떤 인터페이스를 원하는지를 지정하는 옵션입니다.
hr = CoCreateInstance(CLSID_ActiveDesktop,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_IActiveDesktop,
    (void **)&pIAD);

if (SUCCEEDED(hr)) {
    // 3. COM 객체 생성되었다면, GetWallpaper를 호출합니다.
    hr = pIAD->GetWallpaper(wszWallpaper, MAX_PATH, 0);
    if (SUCCEEDED(hr)) {
    // 4. GetWallpaper 호출이 성공하였다면 파일 이름을 출력합니다
    // 유니코드 문자열을 출력하기 위해 wcout을 사용할 것입니다.
    // wcout은 cout과 동일하나 유니코드 버전입니다.
    std::wcout << L"Wallpaper path is \n" << wszWallpaper << std::endl << std::endl;
} else {
    std::cout << "GetWallpaper() failed." << std::endl << std::endl;
}
    // 인터페이스 포인터에 대해 사용 해제하기
    pIAD->Release();
} else {
    std::cout << "CoCreateInstance failed." << std::endl << std::endl;
}

// COM 라이브러리의 사용을 해제합니다. 
// MFC 개발의 경우 MFC자 알아서 하기 때문에 이 과정이 필요 없습니다.
CoUninitialize()

위 예제 코드에서 필자는 유니코드 문자열인 wszWallpaper를 출력하기 위하여 std::wcout을 사용하였습니다.

 

다중 인터페이스를 갖는 COM 객체 사용하기

두 번째 예제는 하나의 인터페이스를 노출하고 있는 COM 객체에 대해 QueryInterface를 어떻게 사용하는지를 보여주고 있습니다. 이 예제에서는 앞서 우리가 확인한 바탕화면 그림파일의 경로를 가지고 바로가기 아이콘을 만들기 위하여 쉘에 포함된 Shell Link coclass를 사용합니다.

이 예제는 다음과 같은 단계를 포함합니다.

1. COM 라이브러리를 초기화하기

2. 바로가기 아이콘을 만드는 COM 객체를 생성하고 IShellLink 인터페이스 포인터를 얻기

3. IShellLink 인터페이스의 SetPath 메소드 호출하기

4. COM 객체에 대해 QueryInterface를 호출하여 IPersistFile 인터페이스 포인터를 얻기

5. IPersistFileSave 메소드를 호출하기

6. 모든 인터페이스 포인터에 대해 Release하기

7. COM 라이브러리를 사용 해제하기

CString sWallpaper = wszWallpaper; // 바탕화면 경로를 ANSI 문자열로 변환
IShellLink * pISL;
IPersistFile * pIPF;

// 1. COM 라이브러리를 초기화하기(윈도우 운영체제로 하여금 DLL 적재하게 하기)
// 일반적으로 여러분은 이 작업을 InitInstance나 기타 초기 호출 코드에서 할 것입니다.
// MFC에서는 AfxOleInit()을 대신 사용합니다.
CoInitialize(NULL);

// 2. COM 객체를 사용하기 위하여 쉘에서 제공하는 Shell Link coclass를 사용합니다.
// 4번째 파라미터로 우리가 필요로 하는 인터페이스 포인터가 IShellLink임을 알려줍니다.
hr = CoCreateInstance(CLSID_ShellLink,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_IShellLink,
    (void **)&pISL);

if (SUCCEEDED(hr)) {
    // 3. 바탕화면 그림파일의 경로를 바로가기 대상으로 지정합니다.
    hr = pISL->SetPath(sWallpaper);
    
    if (SUCCEEDED(hr)) {
        // 4. 두 번째 인터페이스인 IPersistFile에 대한 포인터를 얻습니다.
        hr = pISL->QueryInterface(IID_IPersistFile, (void **)&pIPF);
        
        if (SUCCEEDED(hr)) {
        // 5. 바로가기 파일을 저장합니다. 첫 번째 파라미터는 유니코드 문자열입니다.
        hr = pIPF->Save(L”C:\\wallpaper.lnk”, FALSE);
        
        if (SUCCEEDED(hr)) {
            // 저장 성공한 경우 처리할 내용
        } else {
            // 저장 실패한 경우 처리할 내용
        }
        
        // 6. IPersistFile 인터페이스에 대한 포인터를 참조 해제합니다.
        pIPF->Release();
    } else {
        // QueryInterface 실패한 경우 처리할 내용
    }
    
    // 6. IShellLink 인터페이스에 대한 포인터를 참조 해제합니다.
    pISL->Release();
} else {
    // SetPath 실패한 경우 처리할 내용
}
'API/COM' 카테고리의 다른 글
더 보기...
태그 : 
댓글