DirectX11 2D 롤플레잉 게임 만들기 6 COM 아키텍쳐에 대하여

COM은 실제 개발시 큰 의미가 없는 지식일 수 있다. 하지만 이것을 알고 있고 없고에는 차이가 있으며 이 차이가 개발자의 역량 차이를 만든다.

COM이란?

Component Object Model, Windows 상에서 돌아가고 있는 프로세스들이(애플리케이션이나 백그라운드 프로세스, 시스템 모듈 등) Windows가 제공하는 기능들을 실시간으로 공유 하는 체계이다.

라이브러리(DLL)를 통해 프로세스들이 각자 독립적으로 Windows의 기능을 이용하는 방법과는 차이가 있다.

특히 DirectX는 대표적인 COM 모듈로서 Windows 안에 자리 잡혀 있다, 우리가 만드는 게임 프로그램은 이 모듈과 소통하고자 하는 것.

이런 공용 모듈인 COM 모듈에 실시간으로 접근하기 위해선 이에 접근할 수 있는 인터페이스 객체들을 만들어 써야 한다

이전 포스팅에서 보여준 사각형을 그리는 DirectX의 스타터 코드를 보면 이 애플리케이션의 중심이 되는 메인 객체(DemoApp)에서 DirectX를 사용하기 위한 기본 자료형인 ID2D1Factory나 랜더 타겟이란걸(ID2D1HwndRenderTarget) 만들어 쓰는 코드가 보인다.

이때 자료형의 이름 앞에 모두 알파벳 I 가 붙는 게 보인다(ID2D 같이)이는 이런 자료형은 프로그래밍적으로 인터페이스 역할을 한다는 뜻이다.

C++은 Java나 C#과 달리 인터페이스(interface)라는 자료형이 정확히 명시되어있지 않다. 대신 상속 가능한 빈함수나 함수 포인터만 가지고 있는 클래스를 만들어 쓰면 된다. 이를 추상 클래스라고 부르기도 한다.

인터페이스란, 데이터와 메서드를 모두를 가진 일반적인 클래스의 객체와 달리, 오직 비어있는 함수 목록들(또는 메서드 목록들, 인자형, 리턴형 등)만 가지고 있는 껍데기 같은 자료형이다.

이 인터페이스를 상속받은 하위 클래스들은 이 비어있는 함수 목록을 채워서 그걸 사용하도록 유도된다. 한 인터페이스를 상속받은 모든 클래스들은 같은 이름의 함수들이 있게 되는 일종의 틀인 것.

위에 보이는 인터페이스들의 내부 함수들은, 실제 DirectX COM 모듈이 제공하는 기능과 직접 연결되어 우리 프로세스가 그것을 쓸수있게 만들어준다. 이것이 COM 인터페이스인 것.

참고 아래 화면에 보이는 팩토리나, 랜더 타겟은 우리가 DirectX를 사용하기 위한 기본 중의 기본 오브젝트들이었다.

여기서 보이는 ID2D1Factory 인터페이스 자료형은, 함수 포인터를 가지고 있는 구조체로 만들어져 있다. (클래스나 구조체나 그놈이 그놈이다) 이런 식으로 다른 언어와 형식을 맞춰서 소통하는 것.

팩토리를 이용해 CreateHwndRenderTarget 함수로 랜더타겟을 만들어주는 부분

팩토리라는 단어도 COM 체계에서 많이 사용하는 용어이다 특정 COM을 위한 인터페이스를 만들어주는 첫번째 생성 함수들이 보통 팩토리라고 불리기 때문.

다시 말하지만 우리가 팩토리 함수로 요청해서 만들어지는 COM오브젝트는 우리 프로세스 안에있는 라이브러리가 아니라 Windows의 COM 영역에 있다. 우리는 인터페이스를 받아서 그것과 소통만 하는 것

잊혀져가고 있는 기술? 내부적으로는 쓰이고 있다

예전에 익스플로러라는 브라우저의 ActiveX라는 기능이, 이 윈도우의 COM 시스템 모델을 배경으로 쓰고 있었다.

익스플로러를 만든 마이크로소프트 입장에서는 익스플로러가 단순히 웹브라우저 수준을 벗어나,

인터넷을 사용하는 금융거래 프로그램이나 게임 등으로 그 기능이 확장될 수 있기를 바랬고 그 바람이 ActiveX라는 형태로 만들어진 것.

익스플로러 개발진이 단독으로 이 모든 것들을 만들어 낼 수 없었기에 생긴 일이다,

각각 이런 서비스를 해주는 업체들이 프로그램들을 만들어 이를 익스플로러와 연동해주길 바랬던 것.

하지만 이러기 위해선 그 각각의 업체들이 만든 게임 모듈이나 금융 서비스 모듈이 다운로드되어 각 사용자의 컴퓨터에 설치돼야 했고 이것들이 또 익스플로러와 상호 작용도 해야 했다.

사용자 컴퓨터에 설치돼서 관련 서비스는 이 모듈들이 했고, 단지 결과를 출력하는 화면과 사용자로부터 입력을 받는 페이지만 브라우저 위에 떠있었던 것.

이는 엄청난 보안상의 부담을 가져왔다. 지금 깔리는 게 금융결제 서비스인지, 해킹 프로그램인지, 바이러스인지 제대로 파악하지 못한 상태에서 사용자들이 이것들을 멋모르고 깔기 일수였고 이를 막기 위해 허구헌날 익스플로러 화면 위에는

“이게 보안상 위험할 수 있습니다 그래도 설치하시겠습니까?”

라는 노란색 경고 문구가 떠있었다. 그리고 그렇게 익스플로는 역사의 뒤안길로 사라진다.

ActiveX가 사라지면서 윈도우의 COM 객체 모듈은 그 존재감을 잃었다(반파되었다) 만약 누군가가 COM을 공부한다고 하면

“그거 이미 사장 기술인데 왜 해? 다른 신기술 많잖아”라는 말을 듣게 될 것이다.

하지만 ActiveX가 사라졌다 뿐이지 COM 시스템 모델 자체는 아직도 윈도우를 구성하는 매우 중요한 요소중 하나이다.

DirectX만 COM 인터페이스 통신을 하는 게 아니라는 소리.

COM 모델의 장점 호환성

COM이 가진 가장 큰 장점은 이것이 다른 언어로 만든 프로그램과 소통할 수 있게끔 해주는데도 있다.

자바 모듈을 쓰는 C++ 프로그램이라던지, C로 만든 서비스를 원격 PC에서 파이썬, 자바 스크립트들이 사용한다든지 말이다. 그것도 소스코드들의 머지를 통한 소통이 아니라 이미 만들어져서 돌고 있는 바이너리간의 소통이기에 매우 의미 있다.

기본적으로 다른 언어에서 컴파일된 바이너리들은 그 형식이 매우 상이하기 때문에 절대로 합쳐질 수 없다.

그리고 윈도우 시스템 자체를 이해하기 위해서도 반드시 알아둬야 하는 부분이기도 하다.

팩토리 함수(AddRef)와 레퍼런스 카운트, 릴리즈(Release)

레퍼런스 카운트의 개념은 우리가 COM을 알아야 하는 이유이다.

우리가 COM 인터페이스를 받아오기 위해 IUnknown이라는 모든 COM에 있는 기본 인터페이스를 사용한다. (그래서 COM은 최소 두 개의 인터페이스가 있는 것, IUnknow과 모듈의 인터페이스)

그리고 이 COM 오브젝트를 사용하고 나면 지워줘야 할 것이다.

그런데 이 COM오브젝트를 다른 게임이나 워드 프로그램, 엑셀 등이 같이 사용하고 있다고 가정해보자. (달력 만들어주는 COM 같은 건 양쪽에서 모두 사용할 수 있지 않겠는가) 우리가 이 COM오브젝트를 지우면 엑셀 쪽에서 오류가 날것이다.

그래서 각각의 COM오브젝트는 레퍼런스 카운트라는 걸 가지고 있다.

현재 몇 개의 애플리케이션이 자길 쓰고 있는지 카운팅 해두고 있는 것.

그래서 COM 오브젝트를 사용하기 위해 팩토리 함수를 사용하면 내부적으로 AddRef(레퍼런스 카운트 증가함수)가 호출된다.

만약 우리 게임 프로그램이 COM 오브젝트를 다 쓰고 이제 그만 써도 된다고 알리면 이 카운트가 하나 감소된다.

카운트가 0이 되면 이 COM오브젝트는 지워진다.

그래서 DirectX를 사용하는 게임 프로그램은 Release라는 단어가 담긴 해제 함수를 많이 사용한다.

사용하던 모듈을 당장 지워야 하는지 말아야 하는지는 나도 모르니까

“이거 이제 난 필요 없어 카운트 0 되었으면 지우든가”라는 메시지가 담겨 있는 것.

이런 레퍼런스 카운트와 릴리즈라는 개념은 DirectX 전반에 걸쳐 자리 잡혀 있는 개념이다.

Leave a Comment