티스토리 뷰

프로그래밍/MFC

MFC COM

에어버스 2016. 7. 24. 12:56

COM (Common Object Model)

특정 프로그래밍 언어에 종속되지 않는 개체를 만드는 방법

- 매서드를 가진다. (C++ 멤버함수와 비슷)
메서드 : 
인터페이스에 그룹화되어 인터페이스 포인터를 통해 호출된다.

- 인터페이스 : 관련된 메서드의 그룹을 의미적으로 결합하기 위해 존재한다.
MS에서 제공하는 인터페이스를 표준 인터페이스라 하고 사용자가 만든 사용자 정의 인터페이스라 한다.

모든 COM 개체는 IUnknown 인터페이스를 구현구현하고, 3개의 메서드를 가진다. (모든 COM 개체는 이를 갖고 있어야만 한다)
QueryInterface : 포인터를 다른 인터페이스에 전달한다.
AddRef : 개체의 참조 카운트를 증가 시긴다.
Release : 개체의 참조 카운트를 감소 시킨다.

한 인터페이스에 대한 포인터가 주어지면 클라이언트는 그 포인터를 통해 인터페이스에 있는 모든 메서드는 물론 IUnkown의 메서드를 호출할 수 있다.

만약, 어떤 COM개체가 Add, Subtract 라는 메서드를 가진 IMath 인터페이스를 정의하면 실제로 이 인터페이스는 Add, Subtract 뿐만 아니라 QueryInterface, AddRef, Release 5개의 메서드를 갖게된다.

이런 인터페이스는 이름이 아닌 인터페이스 식별자 또는 IID라는 128bit 고유의 값으로 지정된다.

MS C++ 은 IID를 생성 위해 uuidgen 명령 유틸리티와 guidgen 이라는 GUI 유틸리티를 제공한다.

COM API 함수인 CoCreateGuid()를 통해 만들수도 있다.

 

COM 클래스 역시 128bit 값으로 구분하고 이 값을 CLSID 라고 한다.

모든 클라이언트는 이 CLSID를 알아야 개체의 인스턴스를 생성할 수 있다.

1
2
3
4
5
IMath* pMath;
CoCreateInstance(CLSID_Object, NULL, CLSCTX_SERVER, IID_IMath, (void**)&pMath);
...
int sum;
pMath->Add(22&sum);
cs

IID_IMath : IMath 의 IID 값
인터페이스 포인터를 가지면, -> 연산자로 메서드를 호출한다.

C++ 은 개체를 new로 만들고 delete 로 삭제하며 관리하듯. COM은 AddRef() 가 호출되면 참조 횟수가 증가하고 Release()가 호출되면 감소한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
ULONG __stdcall CComClass::AddRef()
{
   retrun ++m_lRef;
}
 
ULONG __stdcall CComClass::Release()
{
   if(--m_lRef == 0) {
      delete this;
      return 0;
   }
   return m_lRef;
}
cs

 AddRef() 는 클라이언트에서 호출하는것이 아니라 개체 내에서 호출되고, Release()는 클라이언트에서 호출해야 한다.

COM 서버

COM이 활성화 요청에 반응하여 개체를 생성하는 것이라면 각 개체의 실행파일이 어디에 있는지 알아야 한다. COM개체를 구현하는 실행파일을 COM 서버라고 한다. 레지스트리의 HKEY_CLASSES_ROOT/CLSID 섹션에는 실행파일을 관련짓는 정보가 들어있다. 예로 MathSvr.exe 라는 서버가 Math 개체를 구현하고 클라이언트가 Math의 CLSID를 사용해 CoCreateInstance()를 호출하면 COM은 레지스트에서 CLSID를 찾아 MathSvr.exe의 경로를 찾아 EXE파일을 실행한다. 그러면 EXE는 COM에게 클래스 공장을 넘겨주고 COM은 클래스 공장의 CreateInstance() 메서드를 호출해 Math 개체의 인스턴스를 생성한다.

COM 서버는 in-process (DLL) 과 out-of-process (DCOM) 2개 방식이 있다.

COM은 메서드의 매개 변수를 정돈(Marchal)하고 값을 반환한다.

샬링(Marshaling) 은 호출 수신자의 주소 공간에 호출자의 스택 프레임을 다시 생성하는 것이 필수적이다.
프록시와 스터브가 대부분의 마샬링과 원격화를 수행한다. 클라이언트가 다른 프로세스에서 실행중인 개체의 인터페이스 포인터를 받으면 COM은 클라이언트 프로세스 공간에 인터페이스 프록시를 만들고 서버 공간에는 인터페이스 스터브를 만든다. 클라이언트가 가진 인터페이스 포인터는 사실 프록시에 대한 인터페이스 포인터인 것이다. 프록시 인터페이스는 실제 개체와 똑같은 인터페이스와 메서드를 구현한다. 클라이언트가 개체의 메서드를 호출하면 이 호출은 프록시로 전달되고 프록시는 어떤 형식의 프로세스 간 통신(IPC)를 사용해 호출을 스터브로 전달한다. 스터브는 메서드 매개 변수를 읽어 내어 개체를 호출하고 반환값을 정돈하여 프록시에게 다시 보낸다.

- 프록시와 스터브

개체가 표준 인터페이스만 사용한다면 COM이 프록시와 스터브를 제공한다.
개체가 사용자 정의 인터페이스를 사용한다면 개체 구현자가 프록시/스터브 DLL의 형태로 프록시와 스터브를 제공해야 한다. 이때 사용하는 언어가 IDL(인터페이스 정의 언어) 파일을 컴파일하여 프록시/스터브 DLL에 필요한 소스 코드를 만드는 MIDL컴파일러 도구를 제공한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31