Search
Duplicate
🪟

COM기술이란

간단소개
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Windows
C++
태그
컴파일
링킹
Windows
Scrap
8 more properties

목차

시작하며

안녕하세요 조신입니다. 오늘은 window 프로그래밍을 배우면서 사용하는 COM기술에 대해서 공부해 본 것들을 공유하고자 이 글을 작성합니다. 많은 부분이 ms공식 문서를 참조하였고 이 글을 작성하면서 추상적으로 배웠던 COM에 대해서 더 자세히 알 수 있게 됐습니다. 나중에 기회가 된다면 윈도우 프로그래밍으로 어떻게 COM객체를 만들어서 사용까지 하는지를 다뤄볼텐데 오늘은 COM기술이란 무엇인지와 그 내부에서 좀 중요하다고 생각되는 부분을 작성해봤습니다.
읽고 혹시나 궁금한점이나 피드백 언제나 환영합니다. 감사합니다.

COM

참고문서

COM의 특징.

COM이란 무엇인가?

Microsoft COM(구성 요소 개체 모델)은 런타임에 상호 작용하는 재사용 가능한 소프트웨어 라이브러리를 만들기 위한 이진 상호 운용성(binary interoperability standard) 표준을 정의합니다. COM 라이브러리를 응용 프로그램으로 컴파일하지 않고도 사용할 수 있습니다.
COM은 개체가 단일 프로세스 내에서처럼 쉽게 프로세스 및 컴퓨터 경계를 넘어 상호 작용할 수 있도록 하는 기술입니다. COM은 개체와 연결된 데이터를 조작하는 유일한 방법이 개체의 인터페이스 를 통하는 것임을 지정하여 이를 가능하게 합니다.
COM은 Windows Media Player 및 Windows Server와 같은 여러 Microsoft 제품 및 기술의 기반입니다.
COM이란 Microsoft의 OLE(복합 문서) 및 ActiveX(인터넷 지원 구성 요소) 기술의 기초 기술로 마이크로소프트가 만든 컴포넌트 모델이다.
컴포넌트 모듈의 형태와 컴포넌트를 사용하기 위한 방법을 표준화 한 것이다.
COM은 윈도 운영체제의 기본 모듈로 포함되며 OLE나 ActiveX의 근간이 됩니다.
OLE는 COM을 바탕으로 마이크로소프트가 만든 컴포넌트 기술이다. 이를 인터넷에서 동작하도록 수정한 것이 ActiveX입니다.
COM(따라서 모든 COM 기반 기술)을 이해하려면 개체 지향 언어가 아니라 표준이라는 것을 이해하는 것이 중요합니다.
COM은 애플리케이션을 구성하는 방법을 지정하지 않습니다. 언어, 구조 및 구현 세부 정보는 애플리케이션 개발자에게 맡기고, 대신 COM은 COM 개체(COM 구성 요소 또는 개체)가 다른 개체와 상호 작용할 수 있도록 하는 개체 모델 및 프로그래밍 요구 사항을 지정합니다.

이진 표준

여기서 말하는 개체는 다른 언어로 생성할 수 있고, 다른 프로세스에 있을수도 있습니다.
그래서 우리는 COM을 이진 표준(binary standard) 이라고 합니다. 프로그램이 이진 머신 코드로 변환된 후에 적용되는 표준입니다.
COM은 많은 운영 체제 및 하드웨어 플랫폼에 적용되는 이진 표준을 정의합니다. 네트워크 컴퓨팅의 경우 COM은 서로 다른 하드웨어 플랫폼에서 실행되는 개체 간의 상호 작용을 위한 표준 유선 형식 및 프로토콜을 정의합니다. COM은 구현 언어와 무관합니다. 즉, C++ 및 .NET Framework의 언어와 같은 다양한 프로그래밍 언어를 사용하여 COM 라이브러리를 만들 수 있습니다.

COM의 요구사항

COM에서 유일한 언어 요구 사항은 코드가 포인터 구조를 만들고 명시적 또는 암시적으로 포인터를 통해 함수를 호출할 수 있는 언어로 생성된다는 것입니다.
C++ 및 Smalltalk와 같은 개체 지향 언어는 COM 개체의 구현을 단순화하는 프로그래밍 메커니즘을 제공하지만 C, Java 및 VBScript와 같은 언어를 사용하여 COM 개체를 만들고 사용할 수 있습니다.

COM의 특징을 요약하면 다음과 같습니다.

구성 요소 간의 함수 호출에 대한 이진 표준입니다.
인터페이스에 대한 강력한 유형의 기능 그룹화를 위한 규정.
다형성, 기능 검색 및 개체 수명 추적을 제공하는 기본 인터페이스입니다.
구성 요소와 해당 인터페이스를 고유하게 식별하는 메커니즘입니다.
배포에서 구성 요소 인스턴스를 생성하는 구성 요소 로더입니다.

COM의 구성요소

분류

host system(호스트 시스템) : COM 사양을 준수하는 런타임 환경을 제공
Interfaces and components(인터페이스와 구성요소) : 기능 계약을 정의 (인터페이스) 인터페이스를 구현(컴포넌트)
Servers and client : 서버 : 시스템에 컴포넌트를 제공, 클라이언트 : 컴포넌트가 제공하는 기능을 사용
registry : 컴포넌트가 로컬 및 원격 호스트에서 배포되는 위치를 추적 tracks where components are deployed on local and remote hosts.
Service Control Manager : 로컬 및 원격 호스트에서 컴포넌트를 찾고 서버를 클라이언트에 연결하는 기능을한다.
structured storage protocol : 호스트의 파일 시스템에 있는 파일 내용을 탐색하는 방법을 정의합니다.
여기서 우리는 인터페이스와 컴포넌트에 대해서만 다뤄보도록하겠습니다.
나머지는 또 쓸일이 있을 때 찾아봐야겠어요. 공식 문서에 잘 써있으니 천천히 읽어가시길 추천드립니다.

COM 컴포넌트

모듈 형태COM 컴포넌트는 메소드와 프로퍼티를 갖는 객체이다. 이것은 실행 파일이나 DLL의 형태가 된다. 실행 파일의 형태를 가지면 아웃프로세스(Out-Process) 컴포넌트라고 하여 DLL 형태를 가지면 인프로세스(In-Process)라고 한다. 아웃프로세스는 느리지만 안정성이 좋고, 인프로세스는 빠르지만 안정성이 떨어진다. 그 이유는 아웃프로세스는 별도의 프로세스로 실행되어 사용시 주소 변환이 수반되기 때문에 속도는 느리지만, 문제가 생겨도 영향을 받지 않기 때문이다. 인프로세스의 경우 그 반대가 된다.하나의 모듈 안에 둘 이상의 컴포넌트가 존재해도 무방하다.
인터페이스COM 컴포넌트의 메소드와 프로퍼티는 인터페이스로 구성된다. 즉 멤버함수로만 구성된다. 프로퍼티는 변수 처럼사용하지만 실제로 함수를 이용해 구현된다. 모든 COM 컴포넌트는 IUnkonwon이라는 최상위 인터페이스로 부터 상속된다. 이 인터페이스는 3개의 멤버 함수(AddRef, Release, QueryInterface)가 존재 한다. 따라서 모든 COM 컴포넌트는 이 3개의 함수를 기본적으로 갖고 있다. 인터페이스 또한 구분을 위한 128비트의 ID를 갖는다. IID라고 부른다.
1.
AddRef : 컴포넌트에 대한 레퍼런스가 생길 때마다 사용자 프로그램에서는 그 컴포넌트의 AddRef 메소드를 호출하여 레퍼런스 카운트를 하나 증가시킨다.
2.
Release : 더 이상 그 컴포넌트를 사용할 일이 없어지면 Release 메소드를 호출. Release 메소드에서는 내부적으로 유지하는 레퍼런스 카운트가 0이 되면 자신을 메모리에서 제거한다.
3.
QueryInterface : 컴포넌트에게 갖고 있는 인터페이스를 달라고 요청하는데 사용된다. 첫 번째 인자로 원하는 IID, 두 번째 인자로 그 인터페이스에 대한 포인터를 받을 변수의 주소를 지정해야 한다(포인터의 포인터). 즉, 컴포넌트에서 자신이 사용하고자 하는 인터페이스를 받아오는데 사용된다.예를 들어 GetMemorySize라는 메소드를 갖는 ISystemInfo라는 인터페이스를 구현한다고 하면, 모든 인터페이스는 앞에 I를 붙여 표시하는 것이 일반적이다. 당연히 IUnknown으로부터 계승이 되어야 한다.

COM 인터페이스

COM은 개체가 단일 프로세스 내에서처럼 쉽게 프로세스 및 컴퓨터 경계를 넘어 상호 작용할 수 있도록 하는 기술입니다. COM은 개체와 연결된 데이터를 조작하는 유일한 방법이 개체의 인터페이스 를 통하는 것임을 지정하여 이를 가능하게 합니다.
일반적으로 소프트웨어 개체는 데이터 집합과 데이터를 조작하는 기능으로 구성됩니다. 
COM 객체(COM object)는 멤버 함수의 모음인 인터페이스를 통해 기능을 보여줍니다.
COM 인터페이스는 구성 요소의 예상 동작 및 책임을 정의하며, 작은 관련 작업 집합을 제공하는 강력한 형식의 계약을 지정합니다.
COM 구성 요소 간의 모든 통신은 인터페이스를 통해 발생하며 구성 요소에서 제공하는 모든 서비스는 해당 인터페이스를 통해 노출됩니다.
호출자는 인터페이스 멤버 함수에만 액세스할 수 있습니다. 내부 상태는 인터페이스에 노출되지 않는 한 호출자가 사용할 수 없습니다.
즉 COM에서는 인터페이스의 메서드에 액세스할 수 있는 유일한 방법은 인터페이스에 대한 포인터를 통해서만 가능해야 합니다.

인터페이스 식별자.

인터페이스는 강력한 타입이라고 MS 공식문서에서 이야기한다. (Interfaces are strongly typed.)
모든 인터페이스에는 고유한 IID라는 인터페이스 식별자가 존재해서 이름으로 인한 충돌의 가능성을 제거합니다. IID는 UUID와 동일한 GUID입니다. (이 부분은 나중에 또 다루겠습니다.)
새 인터페이스를 만들 때 해당 인터페이스에 대한 새 식별자를 만들어야 합니다. 호출자가 인터페이스를 사용하는 경우 고유 식별자를 사용해야 합니다. 이 명시적 식별은 런타임 오류가 발생하는 명명 충돌을 제거하여 견고성을 향상하는 효과가 있습니다.

인터페이스 정의 (IDL)

새 인터페이스를 정의할 때 IDL(인터페이스 정의 언어)을 사용하여 인터페이스 정의를 만들 수 있습니다. 이 인터페이스 정의에서 Microsoft IDL 컴파일러는 인터페이스를 사용하여 애플리케이션에서 사용할 헤더 파일과 원격 프로시저 호출을 처리하는 소스 코드를 생성합니다.
Microsoft에서 제공하는 IDL은 RPC(원격 프로시저 호출) 기반 분산 컴퓨팅에 대한 업계 표준인 DCE IDL에 대한 간단한 확장을 기반으로 합니다. IDL은 인터페이스 디자이너의 편의를 위한 도구이며 COM 상호 운용성의 중심이 아닙니다. IDL을 사용하면 각 프로그래밍 환경에 대해 헤더 파일을 수동으로 만들 필요가 없습니다.

인터페이스 빌드 및 파생 특징

모든 COM 인터페이스는 IUnknown 인터페이스에서 직접 또는 간접적으로 파생되어야 합니다.
해당 제약 조건 내에서 사용자 지정 인터페이스는 비동기 메서드를 포함하여 거의 모든 메서드 또는 매개 변수를 지원할 수 있습니다.
클라이언트가 런타임에 개체의 메서드에 대한 정보에 액세스할 수 있도록 사용자 지정 인터페이스에 대한 형식 라이브러리를 생성할 수도 있습니다.
COM 인터페이스를 빌드하려면 C/C++ 컴파일러와 Midl.exe 컴파일러를 포함하는 개발 환경이 필요합니다.

인터페이스 제작 단계 및 사용방법

COM 인터페이스를 만드는 단계는 다음과 같습니다.
인터페이스에 대한 마샬링 지원을 제공할 방법을 결정합니다. 형식 라이브러리 기반 마샬링을 사용하거나 프록시/스텁 DLL을 사용합니다. 심지어 인프로시저 인터페이스는 아파트 경계를 넘어 사용되는 경우 마샬링되어야 합니다. 필요한 것은 아니지만 모든 COM 인터페이스에 마샬링 지원을 빌드하는 것이 좋습니다. 자세한 내용은 인터페이스 마샬링을 참조하세요.
IDL(인터페이스 정의) 파일의 인터페이스 또는 인터페이스에 대해 설명합니다. 또한 ACF(애플리케이션 구성 파일)에서 인터페이스의 특정 로컬 측면을 지정할 수 있습니다. 형식 라이브러리 기반 마샬링을 사용하는 경우 형식 정보를 생성하려는 인터페이스를 참조하는 라이브러리 문을 추가합니다.
MIDL 컴파일러를 사용하여 형식 라이브러리 파일 및 헤더 파일 또는 C 언어 프록시/스텁 파일, 인터페이스 식별자 파일, DLL 데이터 파일 및 헤더 파일을 생성합니다. 자세한 내용은 MIDL 컴파일 을 참조하세요.
선택한 마샬링 방법에 따라 DEF(모듈 정의) 파일을 작성하고, MIDL에서 생성된 모든 파일을 컴파일 및 단일 프록시 DLL에 연결하고, 시스템 레지스트리에 인터페이스를 등록하거나, 형식 라이브러리를 등록합니다. 자세한 내용은 형식 라이브러리 로드 및 등록 , 프록시 DLL 빌드 및 등록을 참조하세요. 저는 DLL을 레지스트리에 등록하는 방법으로 실습을 해봤으나 나중에 다뤄보도록 하겠습니다.

상속

상속은 COM 인터페이스에서 드물게 사용됩니다. COM은 기본 인터페이스와 연결된 계약을 다시 사용하는 인터페이스 상속만 지원합니다. COM은 선택적 상속을 지원하지 않습니다. 따라서 한 인터페이스가 다른 인터페이스에서 상속되는 경우 기본 인터페이스가 정의하는 모든 함수가 포함됩니다. 또한 인터페이스는 여러 상속 대신 단일 상속만 사용하여 기본 인터페이스에서 함수를 가져옵니다.

인터페이스의 작동 및 설명

COM은 Visual C++ 프로그래밍에서 일반적으로 사용되는 것과는 다른 의미에서 인터페이스 라는 단어를 사용합니다. 
COM 인터페이스의 인스턴스는 단독으로 만들 수 없습니다. 대신 인터페이스를 구현하는 클래스의 인스턴스를 만듭니다. C++에서 COM 인터페이스는 추상 기본 클래스 로 모델링됩니다. 즉, 인터페이스는 순수 가상 멤버 함수만 포함하는 C++ 클래스입니다. C++ 라이브러리는 하나 이상의 인터페이스에서 멤버 함수 서명을 상속하고, 각 멤버 함수를 재정의하고, 각 함수에 대한 구현을 제공하여 COM 개체를 구현합니다.
C++ 인터페이스는 클래스가 지원하고 개체의 클라이언트가 개체와 상호 작용하기 위해 호출할 수 있는 모든 기능을 나타냅니다. COM 인터페이스는 COM 클래스가 구현하는 관련 기능의 미리 정의된 그룹을 참조하지만 특정 인터페이스가 반드시 해당 클래스가 지원하는 모든 기능을 나타내는 것은 아닙니다.
인터페이스를 구현 하는 개체를 참조한다는 것은 개체 가 인터페이스의 각 메서드를 구현하는 코드를 사용하고 해당 기능에 대한 COM 바이너리 호환 포인터를 COM 라이브러리에 제공한다는 의미입니다. 그런 다음 COM은 클라이언트가 해당 기능을 구현하는 프로세스 내부에 있든 외부에 있든 인터페이스에 대한 포인터를 요청하는 모든 클라이언트가 해당 기능을 사용할 수 있도록 합니다.

인터페이스 구현

함수 포인터의 개념을 지원하는 프로그래밍 언어를 사용하여 COM 인터페이스를 구현할 수 있습니다. 예를 들어 C에서 인터페이스는 인터페이스의 각 메서드에 대해 하나씩 함수 포인터 테이블에 대한 포인터를 포함하는 구조체입니다.
인터페이스를 구현할 때 클래스는 인터페이스의 모든 함수에 대한 구현을 제공해야 합니다. 클래스가 인터페이스 함수에서 수행할 작업이 없는 경우 구현은 단일 반환 문일 수 있습니다.

인터페이스 정의와 구현

COM은 인터페이스 정의와 구현을 근본적으로 구분합니다.
인터페이스 는 실제로 사용법이 정의되어 있지만 구현이 정의되어 있지 않은 관련 함수 프로토타입 그룹으로 구성된 계약입니다. 이러한 함수 프로토타입은 C++ 프로그래밍의 순수 가상 기본 클래스와 동일합니다. 인터페이스 정의는 메소드 라고 하는 인터페이스의 멤버 함수, 리턴 유형, 매개변수의 수와 유형, 수행해야 하는 작업을 지정합니다. 인터페이스와 관련된 구현이 없습니다.
인터페이스 구현 은 인터페이스 정의에 지정된 작업을 수행하기 위해 프로그래머가 제공하는 코드입니다 . 프로그래머가 개체 기반 응용 프로그램에서 사용할 수 있는 많은 인터페이스 구현이 COM 라이브러리에 포함되어 있습니다. 그러나 프로그래머는 이러한 구현을 무시하고 직접 작성할 수 있습니다. 인터페이스 구현은 해당 개체의 인스턴스가 생성될 때 개체와 연결되어야 하며 구현은 개체가 제공하는 서비스를 제공합니다.
예시
예를 들어 IStack이라는 가상의 인터페이스는 Push 및 Pop이라는 두 가지 메서드를 정의하여 Pop 메서드에 대한 연속적인 호출이 이전에 Push 메서드에 전달된 값을 역순으로 반환하도록 지정할 수 있습니다.
이 인터페이스 정의는 코드에서 함수가 구현되는 방법을 지정하지 않습니다. 인터페이스를 구현할 때 한 프로그래머는 스택을 배열로 구현하고 해당 배열에 액세스하는 방식으로 Push 및 Pop 메서드를 구현하는 반면 다른 프로그래머는 연결 목록을 사용하여 그에 따라 메서드를 구현할 수 있습니다.
Push 및 Pop 메서드의 특정 구현에 관계없이 IStack 인터페이스에 대한 포인터의 메모리 내 표현 및 이에 따른 클라이언트의 사용은 인터페이스 정의에 의해 완전히 결정됩니다.
단순 개체는 단일 인터페이스만 지원합니다.
포함 가능한 개체와 같은 더 복잡한 개체는 일반적으로 여러 인터페이스를 지원합니다. 클라이언트는 인터페이스 중 하나에 대한 포인터를 통해서만 COM 개체에 액세스할 수 있으며, 이를 통해 클라이언트는 해당 인터페이스를 구성하는 모든 메서드를 호출할 수 있습니다. 이러한 메서드는 클라이언트가 개체의 데이터를 사용하는 방법을 결정합니다.
인터페이스는 개체와 해당 클라이언트 간의 계약을 정의합니다. 계약은 각 인터페이스와 연결되어야 하는 메서드와 입력 및 출력 측면에서 각 메서드의 동작이 무엇이어야 하는지를 지정합니다.
계약은 일반적으로 인터페이스에서 메서드를 구현하는 방법을 정의하지 않습니다. 계약의 또 다른 중요한 측면은 개체가 인터페이스를 지원하는 경우 어떤 방식으로든 해당 인터페이스의 모든 메서드를 지원해야 한다는 것입니다. 구현의 모든 메서드가 무언가를 수행할 필요는 없습니다. 개체가 메서드가 암시하는 기능을 지원하지 않는 경우 해당 구현은 간단한 반환이거나 의미 있는 오류 메시지의 반환일 수 있지만 메서드는 반드시 존재해야 합니다.

인터페이스 식별(DLL)

COM 클래스는 클래스를 파일 시스템의 특정 배포와 연결하는 고유한 CLSID(128비트 클래스 ID)를 사용하여 식별됩니다. 이 ID는 Windows DLL 또는 EXE입니다. CLSID는 GUID입니다. 즉, 다른 클래스에 동일한 CLSID가 없습니다. 고유 클래스 식별자를 사용하면 클래스 간의 이름 충돌을 방지할 수 있습니다.

COM의 의의

호스트와 플랫폼에서 코드 재사용을 활성화하는 것은 COM의 핵심입니다. 재사용 가능한 인터페이스 구현은 구성 요소 , 구성 요소 개체 또는 COM 개체 로 명명 됩니다. 구성 요소는 하나 이상의 COM 인터페이스를 구현합니다.
라이브러리가 구현하는 인터페이스를 디자인하여 사용자 지정 COM 라이브러리를 정의합니다. 라이브러리의 소비자는 라이브러리의 배포 및 구현 세부 정보에 대한 지식 없이도 해당 기능을 검색하고 사용할 수 있습니다.
COM은 기본 바이너리 오브젝트 표준을 지정하는 것, 모든 COM 기반 기술에 공통적인 기능을 제공하는 기본 인터페이스를 정의하고 모든 구성 요소에 필요한 소수의 기능을 제공했습니다. 또한 분산환경에서도 개체의 작동방식을 정의했고, 보안기능까지 함께 제공하였다.
거의 대부분의 구성요소의 베이스는 COM이다.
꼭 CLR이 있어야만 상요할 수 있는건 아니다.

COM의 특징

구성요소가 갖추어야 할 표준 제시
여러 버전의 구성요소를 투명한 방식으로 관리
언어 독립적 기반 제공
원격 구성요소에 대한 투명한 접근 지원

구성요소 인터페이스 제공

구성요소 사용자에게는 인터페이스가 가장 중요(인터페이스를 잘 만들어야한다.)
인터페이스는 property가 없고 메서드만 존재한다.
프로터티와 메서드의 차이 -나중에 또 다뤄보겠습니다.