포스트

COM 이란 무엇인가

COM(Component Object Model) 이란?

COM 은 상호작용이 가능한 binary software component 를 만들기 위한 시스템이며 아래의 특징을 가진다.

  • 플랫폼에 독립적인 시스템이다.
  • 분산된 시스템이다.
  • 객체 지향 시스템이다.

COM 은 마이크로소프트의 OLE(Object Linking and Embedding)1 와 ActiveX2 의 기반이 되는 기술이다.

COM 과 COM 기반 기술을 이해하기 위해서 COM 이 객체지향언어가 아닌 표준(Standard) 이라는 것을 이해하는 것이 중요하다. COM 은 어플리케이션의 구조가 어떤식으로 되어야한다 라고 지정하지 않는다. 언어, 구조, 구현에 대한 자세한 내용은 개발자에게 달려있다.

오히려 COM 은 COM objects(COM component 혹은 그냥 objects 라고도 부름)가 다른 objects 들과 상호작용할 수 있도록 object model 이나 프로그래밍적인 요구사항을 지정한다. 이 objects 들은 single process, other processes, 또는 remote computers 에도 있을 수 있다.

COM objects 들은 다른 프로그래밍 언어로 작성될 수도 있고, 구조적으로도 다른 부분이 있을수도 있다. 이런 점이 COM 이 binary standard(프로그램이 binary machine code 로 바뀐 뒤 적용되는 표준) 라고 불리는 이유이다.

COM 에 대해 프로그래밍 언어적으로 딱 하나 요구되는 것은 프로그래밍 언어 중 pointer 구조를 생성할 수 있고 pointer 를 통해 explicitly 혹은 implicitly 하게 function 을 호출할 수 있는 언어를 사용해 코드를 작성해야 한다는 것이다. C++ 나 Smalltalk 같은 객체지향 언어들은 COM objects 의 구현을 편하게 할 수 있도록 프로그래밍 메카니즘을 제공해준다. 반면 C, Java, VBScript 같은 언어들은 COM objects 를 만들거나 사용할 수 있다.

COM 은 COM objects 의 필수 특성을 정의한다. 보편적으로 software object 는 데이터들(set of data)과 그 데이터를 조작할 수 있는 function 들로 만들어진다. COM object 는 object 의 데이터에 접근하기위해 하나 이상의 관련 function 들을 통해야만 하는 부류이다. 이 관련 function 의 모음을 interfaces 라고 부르며, interface 의 function 들을 methods 라고 부른다. 또 COM 은 methods 에 접근할 때 interface 에 대한 pointer 를 통해서만 접근하게 하라고 요구한다.

COM 은 기본적인 binary object standard 를 지정하는 것 외에도 특정 기본 interfaces 를 정의해서 모든 COM 기반 기술에 공통적으로 사용되는 function 을 제공하고 있으며, 모든 component 에서 사용되는 몇가지 function 들을 제공한다. 또 COM 은 분산된 환경에서 objects 들이 어떻게 같이 동작할 수 있는지를 정의하며, 시스템과 component 의 무결성을 위한 보안 기능들도 추가되어있다.

COM Technical Overview

마이크로소프트의 COM 은 binary interoperability3 standard 을 정의하는데, 이는 런타임에 상호작용하는 reusable software libraries 를 만들기 위한 표준이다. 다시말해 COM libraries 들을 우리 어플리케이션에 컴파일할 필요없이 사용이 가능하다. COM은 Windows Media Player 와 Windows Server 같은 마이크로소프트 제품과 기술들의 기반이다.

COM 은 많은 OS 와 하드웨어 플랫폼들에 적용되는 binary standard 를 정의한다. 네트워크 컴퓨팅에서는 standard wire format 과 다른 하드웨어 플랫폼에서 동작하는 object 간의 상호작용 프로토콜을 정의한다. COM 은 구현에 사용된 언어에 독립적이다. 다시말해 C++ 나 .NET Framework 의 다양한 언어들을 사용해 COM libraries 를 개발할 수 있다.

COM specification(사양) 은 cross-platform software reuse 를 위한 기본 개념들을 아래와 같이 제공한다.

  • component 간의 functions 호출을 위한 binary standard
  • interface 내부 functions 의 strongly-typed groupings 에 대한 규정
  • polymorphism, feature discovery, object lifetime tracking 을 제공하는 기본 인터페이스
  • component 들과, component 들의 interfaces 를 고유 식별하는 메커니즘
  • component loader - deployment 에서 component instance 들을 생성해준다

아래와 같이 COM 이 가지고있는 다양한 파츠들을 같이 사용해 reusable components 들로 이루어진 어플리케이션을 만들수 있다.

  • COM specification 에 따른 런타임 환경을 제공하는 host system
  • feature contracts4 를 정의하는 interface, interface 를 구현하는 component
  • 시스템에 components 를 제공하는 servers, components 가 제공하는 기능을 사용하는 clients
  • local host, remote host 에서 components 가 deploy 된 위치를 기록하는 registry
  • local host, remote host 에서 components 의 위치를 찾아내고, servers 를 clients 에 연결하는 Service Control Manager
  • host 의 파일 시스템 안 파일 내용을 탐색하는 방법을 정의하는 structured storage protocol5

다양한 hosts 와 platforms(소프트웨어가 실행되는 HW + OS 조합 - ex. Windows 플랫폼, Linux 플랫폼) 전반에 걸쳐 코드의 재사용을 가능하게 만드는 것이 COM 의 핵심이다. 재사용 가능한 interface 구현체를 component, component object, COM object 라고 부른다. 이 component 는 하나 이상의 interface 를 구현한다.

개발자는 자신의 library 가 구현하는 interface 를 디자인해서 custom COM library 를 만들 수 있다. 이렇게 만들어진 custom COM library 의 사용자는 library 의 deployment(SW, library 를 사용가능하게 시스템에 설치, 구성하는것) 나 자세한 구현에 대해 알 필요 없이 기능을 찾아서 사용할 수 있다.

Objects and Interfaces

COM object 의 기능은 interface(member function = method 의 모음) 를 통해서 드러난다. COM interface 는 component 의 예상 동작과 역할을 정의하는데, 이는 strongly-typed contract 에 맞게 작성된 관련된 작업(method)들의 모음으로서 작성한다.

잠깐 정리하기(COM interface, COM object, COM component)

위에서 설명한대로 COM interface 는 strongly-typed contract 를 준수하며 특정 역할에 관련된 메서드를 정의하고, COM object 는 이러한 interface 를 실제로 구현한다. COM component 는 필요한 여러 기능의 COM object 들을 포함하며, COM 의 기본 원칙을 따르고 interoperability(상호 운용성)을 가지기 때문에 다른 소프트웨어에서 사용할 수 있는 독립적인 모듈(보통 파일 단위) 또는 라이브러리(여러 모듈 포함가능)이다.
일반적으로 COM component 는 DLL, EXE 같은 형태로 존재하며, 다양한 프로그래밍 언어(C++, C#, VB 등)로 개발될 수 있다.

이러한 구조의 간단한 예시를 들어보자. 만약 파일시스템에서 json 파일을 읽어온 후 데이터를 XML 형식으로 변환하여 다시 저장하는 COM component 를 만들고 싶다.
이러한 경우, 파일 조작에 관련된 interface 와 데이터 처리에 관련된 interface 를 각각 작성할 수 있다. 각 interface 는 object 로서 실제 기능이 구현되고, 구현된 object 들을 포함하는 component 가 만들어지는 것이다.

COM component

COM component 간의 모든 상호작용은 interface 를 통해 이루어지며, component 에서 제공하는 모든 기능들은 해당 기능이 정의된 interface 를 통해서 나온것이다. 사용자는 interface 의 member function(=method) 만 사용할 수 있으며, 더 자세한 내부 내용의 조작은 interface 에서 제공하지 않는 이상 불가능하다.

interface 는 strongly typed 되어있다. 모든 interface 는 각자 자신의 unique identifier(고유 식별자) 인 IID(Interface Identifier) 를 가지고있어서 사람들이 직접 이름을 지을 때 발생할 수 있는 충돌을 방지한다. IIDGUID(Globally Unique Identifier), UUID(Universally Unique Identifier)6 라고도 불린다. 실제로 우리가 새로운 interface 를 만들 때 새로운 identifier 도 같이 만들어야한다. 사용자가 interface 를 사용시에 반드시 unique identifier 를 사용해야 한다. 이런식으로 명시적인 식별자를 사용하면 runtime 에 발생할 수 있는 에러인 naming conflicts 를 방지하여 강건성(robustness)을 향상시킬 수 있다.

새로운 interface 를 만들 때, IDL(interface definition language) 을 사용하여 interface definition(interface 를 정의하는 코드) 을 작성할 수 있다. 작성된 interface definition 를 보고 Microsoft IDL compilerheader file(interface 를 사용하는 application 들을 위한 파일) 과 remote procedure calls7 를 다루기 위한 소스코드를 만들어낸다.

이 과정에 대한 간단한 예시를 ChatGPT 로 만들어보았다.

1. 새로운 인터페이스 정의 (IDL):
새로운 기능을 제공하는 인터페이스를 IDL로 정의한다.

1
2
3
interface MyInterface {
    HRESULT DoSomething([in] int param1, [in, out] BSTR param2, [out, retval] int* result);
};

2. IDL 컴파일러 실행:
IDL 파일을 Microsoft IDL 컴파일러에 제공하여 헤더 파일과 소스 코드를 생성한다.

1
midl MyInterface.idl

3. 헤더 파일 및 소스 코드 사용 (C++ 응용 프로그램):
응용 프로그래머는 생성된 MyInterface.h 헤더 파일을 사용하여 새로운 인터페이스를 C++ 언어로 구현한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "MyInterface.h"

int main() {
    // 서버에 연결하는 코드 등을 작성

    // MyInterface 인터페이스 사용
    MyInterfacePtr pMyInterface;
    HRESULT hr = pMyInterface.CreateInstance(__uuidof(MyInterface));

    if (SUCCEEDED(hr)) {
        // 원격 서버에 대한 호출
        int result;
        BSTR param2 = L"Hello";
        pMyInterface->DoSomething(42, &param2, &result);

        // 결과 처리 등을 작성
    }

    // 서버 연결 해제 등을 작성

    return 0;
}

응용 프로그램은 MyInterface 인터페이스를 사용하여 원격 서버의 DoSomething 함수를 호출하고, 결과를 처리한다. 일반적으로 RPC 에서 서버는 계속해서 구동되어 있고, 클라이언트는 필요할 때 원하는 RPC 호출을 수행한다.

마이크로소프트에서 제공하는 IDL 은 DCE IDL 의 간단한 확장형이고, 여기서 DCE IDL 은 RPC 기반 분산 컴퓨팅(DCE; Distributed Computing Environment) 의 산업 표준을 뜻한다. IDL 은 interface 를 간편하게 디자인하기위한 도구일 뿐, COM interoperability 에는 중요한 역할을 하지 않는다. IDL 을 사용하면 각각의 프로그래밍 환경(C, C++ 등. C# 에는 헤더 파일 개념이 없고 클래스, 인터페이스, 다른 코드들이 들어간 소스 코드 파일로 구성된다.)에 맞춰서 일일이 header files 를 만들어낼 필요없이 IDL 컴파일러로 생성이 가능하다. 자세한 내용은 도큐먼트(Defining COM Interfaces) 를 참조하자.

COM interfaces 에서도 드물게 상속(Inheritance)이 사용된다. COM 에서의 interface 상속은 오직 base interface 와 관련된 contract(interface 가 제공하는 method 의 집합) 를 재사용하기 위해서만 사용된다. COM 은 selective inheritance(선택적 상속)8 을 지원하지 않는다. 따라서 한 인터페이스가 다른 인터페이스를 상속받는다면, 다른 인터페이스에 정의된 모든 메서드들을 포함하게 된다. 또한 COM 에서 base interface 의 메서드들을 상속받기 위해서 오직 single inheritance 만 사용한다.(multiple inheritance 는 불가)


참조


  1. 마이크로소프트에서 개발한 윈도우의 각종 응용 프로그램 사이에서 서로 데이터를 공유할 수 있는 기능.
    - 위키백과 

  2. 마이크로소프트에서 개발한 객체지향적 소프트웨어 구성요소 개발에 사용되는 기술이다. COM 과 OLE 를 결합한 기술로 WWW 에서 다운로드한 컨텐츠들을 이용하는데 사용된다.
    - 위키백과 

  3. binary interoperability(≒ compatibility). 어떤 컴퓨터 시스템(machine)에서 만든 소프트웨어의 executable code(대부분 CPU를 조작하는 machine code: 2진 컴퓨터가 지배적인 현대 시장에서 machine code 는 컴퓨터가 프로그램을 실제로 읽고 해석하기 위한 2진 표현법이다) 를 바꾸거나 recompile 하지 않고도 다른 시스템에서 실행할 수 있는 능력을 말한다. 예를들어 레노버의 Thinkpad 노트북과 삼성 데스크탑이 binary compatibility 를 가진다면, 서로 다른 브랜드의 processors, motherboards, memory, graphics hardware, disk drives 를 가진다 해도 똑같이 실행할 수 있다.
    - 위키백과, computerworld.com 

  4. 소프트웨어 개발에서 특정 기능이나 서비스에 대한 규격이나 인터페이스. 특정 기능이나 서비스가 어떻게 동작해야 하는지, 어떤 메서드나 속성을 제공해야 하는지 등을 정의한다. 예를 들어, 여러 component 가 데이터베이스에 접근하는데 사용되는 feature contract 로서 데이터 CRUD 메서드, 연결 설정 메서드 등이 포함될 수 있다.
    - ChatGPT(틀릴수도있음) 

  5. 파일 시스템이나 데이터 저장 공간에 구조적으로 데이터를 저장하고 접근하기 위한 규약이나 프로토콜. 데이터를 계층 구조 또는 특정 형식으로 저장하여 효율적으로 관리하고 검색할 수 있게 하는 방법이다. 일반적으로 파일의 메타데이터, 구조, 및 데이터 간의 상호 작용을 정의하며, 복잡한 데이터 구조를 효과적으로 저장하고 검색할 수 있도록 지원한다. 여러 응용 프로그램이 동일한 데이터에 접근하고 조작할 수 있도록 하며, 특히 데이터베이스나 문서 저장소와 같은 시스템에서 활용될 수 있다.
    - ChatGPT(틀릴수도있음) 

  6. Open Software Foundation (OSF) Distributed Computing Environment (DCE) 에서 정의함 

  7. RPC 라고 불리며, 별도의 원격 제어를 위한 코딩 없이 컴퓨터 네트워크를 통해 다른 주소 공간(다른 컴퓨터)에서 프로시저(함수, 메서드 등)를 실행할 수 있게하는 프로세스 간 통신 기술이다. 보통 rpc 요청을 받는 서버가 띄워져있고, 클라이언트로부터 call 을 받으면 프로시저를 실행한다. 

  8. 특정 interface 를 상속받을 때 원하는 method 만 선택적으로 상속할 수 있는 기능. TypeScript 에서도 사용 가능하다. 간단하게 계산기 인터페이스의 선택적 상속을 구현한다고 하면 interface IAdvancedCalculator extends Partial<ICalculator> 이런식으로 코드를 작성한다. 

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.