맨위로가기

컴포넌트 오브젝트 모델

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

컴포넌트 오브젝트 모델(COM)은 마이크로소프트에서 개발한 객체 지향 소프트웨어 컴포넌트 모델이다. 1988년 COM의 기반이 되는 아이디어가 처음 제시되었으며, 1990년대 초 OLE(Object Linking and Embedding) 프레임워크의 기반 기술로 사용되었다. COM은 윈도우 운영 체제에서 소프트웨어 개발 플랫폼으로 널리 사용되었으며, 액티브X, DCOM, COM+ 등의 기술로 확장되었다. COM은 인터페이스 정의 언어(IDL)를 사용하여 정의되며, 윈도우 레지스트리를 통해 컴포넌트를 관리한다. COM은 복잡성, 환경 초기화, 메시지 펌핑, 참조 카운팅, DLL 지옥 등의 문제로 비판을 받기도 했다. COM은 .NET Framework의 등장으로 점차 대체되었지만, DirectX와 같은 기술에서는 여전히 중요한 역할을 하고 있다.

더 읽어볼만한 페이지

  • 컴포넌트 기반 소프트웨어 공학 - 공통 객체 요구 매개자 구조
    공통 객체 요구 매개자 구조(CORBA)는 객체 관리 그룹(OMG)에서 분산 컴퓨팅 환경에서 객체 지향 기술을 통합하기 위해 제정한 표준 아키텍처로서, 객체 요청 브로커(ORB)를 통해 객체 간 통신을 제공하고 다양한 서비스를 지원한다.
  • 컴포넌트 기반 소프트웨어 공학 - 제어 반전
    제어 반전은 프로그램의 제어 흐름을 프레임워크나 컨테이너가 관리하도록 하는 프로그래밍 원칙으로, 코드 결합도를 낮추고 유연성을 높이지만, 복잡성을 증가시킬 수 있다는 비판도 존재한다.
  • 정보기술 용어 - 그리드 컴퓨팅
    그리드 컴퓨팅은 지리적으로 분산된 컴퓨터 자원을 연결하여 가상 슈퍼컴퓨터를 구축하는 기술이며, 유휴 자원을 활용하고 과학 연구 등 다양한 분야에 활용된다.
  • 정보기술 용어 - 컴퓨터 클러스터
    컴퓨터 클러스터는 여러 대의 상용 컴퓨터를 고속 네트워크로 연결하여 고성능 컴퓨팅 시스템을 구축하는 방식으로, 슈퍼컴퓨터를 포함한 다양한 분야에서 높은 가용성과 확장성을 제공하며, 클러스터 미들웨어를 통해 시스템 관리, 부하 분산, 통신 방식, 데이터 공유 등을 지원하고 노드 장애 관리를 위한 펜싱 기술을 활용한다.
  • 컴퓨터 프로그래밍 - 순서도
    순서도는 컴퓨터 알고리즘이나 프로세스를 시각적으로 표현하는 도구로, 흐름 공정 차트에서 기원하여 컴퓨터 프로그래밍 분야에서 알고리즘을 설명하는 데 사용되며, 다양한 종류와 소프트웨어 도구가 존재한다.
  • 컴퓨터 프로그래밍 - 의사코드
    의사코드는 컴퓨터 과학 및 수치 계산 분야에서 알고리즘을 설명하기 위해 사용되는 비표준적인 언어로, 자연어와 프로그래밍 언어의 요소를 혼합하여 알고리즘의 논리적 흐름을 이해하기 쉽게 하고 프로그래머가 실제 코드로 구현하기 전에 알고리즘을 설계하고 검토하는 데 유용하다.
컴포넌트 오브젝트 모델
일반 정보
이름컴포넌트 오브젝트 모델
원어명Component Object Model
약칭COM
개요
종류소프트웨어 컴포넌트 기술
개발마이크로소프트
최초 발표1993년
상태강제
최신 버전Living standard (2021년)
기술 정보
기반 표준MIDL, UUID
관련 표준대체: DDE
COM 기반: OLE, OLE 자동화, 브라우저 도우미 객체, ActiveX, COM+, DCOM, 윈도우 셸, DirectX, UMDF, 윈도우 런타임
도메인컴포넌트 인터페이스 처리
기타
웹사이트마이크로소프트 COM 공식 문서
시리즈시스템 서비스

2. 역사

1988년 앤서니 윌리엄스(Anthony Williams)는 〈오브젝트 설계: Unknown 다루기(Object Architecture: Dealing With the Unknown)〉 (또는 〈동적 확장이 가능한 클래스에서의 형식 안전성(Type Safety in a Dynamically Extensible Class)〉)라는 마이크로소프트 내부 문서를 발표했고, 1990년에는 〈상속: 상속은 무엇을 의미하며 어떻게 사용하는가(On Inheritance: What It Means and How To Use It)〉를 발표했다. 이 문서들은 COM의 기반이 되는 많은 아이디어들을 제공했다.

1990년대 초, 이러한 아이디어들을 바탕으로 마이크로소프트는 첫 오브젝트 기반 프레임워크인 OLE(Object Linking and Embedding)를 개발했다. OLE는 동적 데이터 교환(DDE)를 기반으로 구축되었으며, 복합 문서를 위해 설계되었다. 1991년 OLE는 워드엑셀을 통해 처음 소개되었고, 1992년 윈도우 3.1부터 운영 체제에 포함되었다. 예를 들어, 워드 문서에 포함된 스프레드시트를 엑셀에서 변경하면 워드 문서에도 자동 반영되었다.

1991년, 마이크로소프트는 비주얼 베이직 1.0을 통해 비주얼 베이직 확장(Visual Basic Extensions 또는 VBX)를 소개하였다.

1993년 마이크로소프트는 OLE 2와 그 기반이 되는 COM을 발표했다. OLE 1이 복합 문서에 초점을 맞춘 반면, COM과 OLE 2는 일반적인 소프트웨어 컴포넌트 개발에 초점을 맞추었다. 1994년에는 VBX 컨트롤을 대체하는 OLE 컨트롤(OCX)이 소개되었다. 이 시기에 마이크로소프트는 OLE 2를 "OLE"로 부르며, OLE가 더 이상 약어가 아닌 모든 회사의 컴포넌트 기술을 지칭하는 이름이라고 밝혔다.

1996년 초, 마이크로소프트는 인터넷 관련 OLE 기술 일부를 ActiveX로 이름을 변경하고, 마이크로소프트 오피스의 복합 문서 기술을 제외한 모든 OLE 기술을 ActiveX로 점차 변경했다. 1997년, 마이크로소프트는 CORBA에 대응하여 DCOM을 소개하였다.[6]

3. 관련 기술

COM은 윈도우에서 주요한 소프트웨어 개발 플랫폼이며, 수많은 기술 개발에 영향을 미쳤다. 주요 관련 기술은 다음과 같다.


  • COM+: 윈도우 2000과 함께 소개된 COM의 확장판이다. 분산 COM (DCOM)은 별개의 기술로 강조되지 않게 되었다. MTS를 통해 배치되었던 트랜잭션 COM 구성 요소들은 COM+의 추가된 계층에서 직접 처리된다.[1]

  • DCOM: COM을 확장하여 서로 다른 머신에서 실행되는 객체를 활성화할 수 있도록 했다.[1]

  • .NET Framework: COM 플랫폼을 상당 부분 대체했으며, 현재 마이크로소프트는 .NET에 집중하는 전략에 주력하고 있다.[31]

  • Windows 런타임 (WinRT): Windows 8에서 새로운 애플리케이션 개발 및 실행 기반으로 도입되었다. COM을 확장한 네이티브 기술이지만, .NET 언어 및 자바스크립트 등에서도 투명하게 이용 가능하다.[33]

  • Nano-COM: COM의 응용 프로그램 바이너리 인터페이스(ABI) 측면에 초점을 맞춘 COM의 하위 집합이다.

  • MSRPC: 윈도우 NT 서비스와 내부 구성 요소의 주요 프로세스 간 통신 메커니즘으로 사용되었다.[1]

3. 1. COM+

COM+는 윈도우 2000과 함께 소개된 COM의 중요한 확장판이다. 마이크로소프트는 분산 COM (DCOM)을 별개의 기술로 강조하지 않게 되었다. 이전에는 MTS 애플리케이션 인터페이스를 통해 배치되었던 트랜잭션 COM 구성 요소들은 이제 COM+의 추가된 계층에서 직접 처리된다. COM+ 구성 요소는 현재 컴포넌트 서비스 애플리케이션 인터페이스를 통해 추가된다.[1]

COM+의 이점 중 하나는 컴포넌트 팜(farm)에서 실행될 수 있다는 것이다. 제대로 작성된 컴포넌트는 한 번 메모리에 로드되면 초기화 루틴을 다시 호출하는 것만으로 재사용할 수 있다. 이전에는 DCOM에서만 가능했던 컴포넌트 분산(다른 시스템에서 호출)도 가능하다.[1]

마이크로소프트는 개발자에게 분산 트랜잭션, 리소스 풀링, 연결이 끊어진 애플리케이션, 이벤트 게시 및 구독, 더 나은 메모리 및 프로세서(스레드) 관리를 지원하고, Windows를 다른 엔터프라이즈 수준 운영 체제의 대안으로 만들기 위해 Windows NT 4에서 MTS를 도입했다.[1]

Windows 2000에서 COM+로 이름이 변경된 이 기능 집합은 MTS에서 제공하는 일련의 외부 도구와 달리 운영 체제에 통합되었다. COM+를 사용하는 컴포넌트는 COM+의 추가 계층, 특히 가로채기에 대한 운영 체제 지원을 통해 더 직접적으로 처리되었다. MTS의 첫 번째 릴리스에서는 가로채기가 부착되었다. MTS 컴포넌트를 설치하면 컴포넌트가 직접 호출되는 것이 아니라 MTS 소프트웨어를 호출하도록 Windows 레지스트리가 수정되었다.[1]

Windows 2000에는 COM+ 컴포넌트를 구성하기 위한 구성 요소 서비스 제어판 업데이트가 포함되었다.[1]

COM+와 마이크로소프트 비주얼 스튜디오는 클라이언트 측 프록시를 쉽게 생성할 수 있는 도구를 제공했으므로, 개발자는 DCOM을 사용하여 원격 호출을 쉽게 수행할 수 있었다. COM+는 또한 '''COM+ 이벤트'''라는 구독자/게시자 이벤트 메커니즘을 도입했으며, '''큐잉된 컴포넌트'''라는 컴포넌트를 사용하여 MSMQ(애플리케이션 간 비동기 메시징을 제공하는 기술)를 활용하는 새로운 방법을 제공했다. COM+ 이벤트는 COM+ 프로그래밍 모델을 확장하여 게시자 또는 구독자와 이벤트 시스템 간의 늦은 바인딩(늦은 바인딩 참조) 이벤트 또는 메서드 호출을 지원한다.[1]

3. 2. DCOM

DCOM은 COM을 확장하여 윈도우 데스크톱에서 별도의 애플리케이션으로 통신하는 단일 사용자 지원에서, 서로 다른 보안 컨텍스트 및 네트워크를 통해 다른 머신에서 실행되는 객체를 활성화할 수 있도록 했다.[1] 이와 함께 객체를 생성, 활성화 및 호출할 권한이 있는 사용자를 구성하고, 호출하는 사용자를 식별하며, 호출 보안을 위한 암호화를 지정하는 데 필요한 기능이 추가되었다.[1]

엔터프라이즈급 운영 체제 (OS)의 대안으로 윈도우의 입지를 확립할 뿐만 아니라, 분산 트랜잭션을 지원하고 메모리와 프로세서(스레드) 관리를 개선하기 위해 마이크로소프트는 Windows NT 4.0 Service Pack 4에서 Microsoft Transaction Server (MTS)를 도입했다.[2]

3. 3. .NET Framework

COM 플랫폼은 .NET Framework에 의해 상당 부분 대체되었으며, 현재 마이크로소프트는 .NET에 집중하는 전략에 주력하고 있다.[31] .NET은 COM을 대체하는 마이크로소프트의 컴포넌트 기술로, 컴포넌트 생성의 많은 세부 사항을 숨겨 개발을 용이하게 한다.

COM은 Visual Basic 및 ASP로 구현된 프론트엔드 코드와 연결하기 위해 널리 사용되었으나, .NET에 비해 비판을 받기도 한다. .NET은 Windows Forms와 Web Form 모두에 대해 Just-In-Time 컴파일 방식과 함께 Visual Basic과 유사한 래피드 개발 툴을 제공하므로, 백엔드 코드는 C#, Visual Basic .NET, C++/CLI를 포함한 모든 .NET 언어로 구현할 수 있다.

그럼에도 불구하고 COM은 여전히 다양한 기술에서 중요한 소프트웨어 기반으로 남아있다. 예를 들어 멀티미디어 API로 널리 보급된 DirectX의 API는 COM을 기반으로 한다.[31] 2015년에 Windows 10과 함께 출시된 DirectX 12 (Direct3D 12) 역시 COM 기반이며, C++를 1급 언어로 사용하고 있다. 2018년 현재 마이크로소프트는 COM 지원을 중단하거나 COM 자체를 폐지할 계획은 가지고 있지 않다.

.NET은 일반적으로 사용되는 COM 컨트롤에 대한 래퍼를 제공한다. `System.EnterpriseServices` 네임스페이스를 통해 COM+를 활용할 수 있으며, COM+가 제공하는 여러 서비스가 .NET에서 중복되었다. 예를 들어, `System.Transactions` 네임스페이스는 COM+에 의존하지 않고 트랜잭션 관리를 제공하는 `TransactionScope` 클래스를 제공한다. 큐 구성 요소는 Windows Communication Foundation (WCF)과 MSMQ 전송으로 대체될 수 있다.

.NET은 COM에 대한 제한적인 상호 운용성을 지원한다. .NET은 런타임 호출 가능 래퍼 (RCW)를 구현하여 COM 객체를 사용할 수 있다.[7] COM 클라이언트는 COM 호출 가능 래퍼 (CCW)를 통해 특정 제약 조건에 따라 .NET 객체를 사용할 수 있다.[8] COM과 .NET 모두에서 상대 객체가 네이티브 객체처럼 보인다. COM Interop을 참조하라.

.NET Remoting은 객체가 프로세스 또는 머신 경계를 넘어 레퍼런스 및 값을 투명하게 마샬링할 수 있도록 하여 COM이 가진 여러 원격 실행의 단점을 해결한다.

3. 4. Windows Runtime (WinRT)

'''Windows 런타임'''('''WinRT''')은 COM 기반 API이지만, 향상된 COM 변형이다. COM과 유사한 기반으로 인해 WinRT는 여러 프로그래밍 컨텍스트에서 인터페이싱을 지원하지만, 비관리형 네이티브 API이다. API 정의는 ".winmd" 파일에 저장되며, ECMA 335 메타데이터 형식으로 인코딩된다. 이는 .NET이 몇 가지 수정 사항과 함께 사용하는 동일한 CLI 메타데이터 형식이다. 이 메타데이터 형식은 .NET 애플리케이션에서 WinRT를 호출할 때 P/Invoke보다 훨씬 낮은 오버헤드를 허용한다.

Windows 8 및 Windows RT에서 새로운 애플리케이션의 개발 및 실행 기반으로 '''Windows 런타임'''(WinRT)이 도입되었다. WinRT는 COM을 확장한 네이티브 기술이지만, Windows 메타데이터(WinMD) 및 언어 프로젝션(language projection)이라고 불리는 기술을 통해 .NET 언어 및 자바스크립트 등에서도 투명하게 이용 가능하다.[33]

3. 5. Nano-COM

Nano-COM은 독립적으로 컴파일된 모듈/컴포넌트 간의 함수 및 메서드 호출을 가능하게 하는 COM의 응용 프로그램 바이너리 인터페이스(ABI) 측면에 초점을 맞춘 COM의 하위 집합이다. Nano-COM은 이식 가능한 C++ 헤더 파일로 표현할 수 있다. Nano-COM은 원자적 타입, 구조체, 배열 및 함수 호출 규칙에 초점을 맞춘 일반적인 ABI와 달리, 기본 명령어 아키텍처 및 OS의 네이티브 ABI를 확장하여 타입이 지정된 객체 참조를 지원한다.

Nano-COM 헤더 파일은 최소한 세 가지 유형을 정의하거나 이름을 지정한다.

  • GUID 인터페이스 유형을 식별한다.
  • HRESULT S_OK, E_FAIL, E_OUTOFMEMORY와 같은 메서드 결과 코드
  • IUnknown 객체 참조의 기본 유형; 새로운 인터페이스 유형 획득을 위한 `dynamic_cast` 스타일 및 `shared_ptr`와 같은 참조 카운팅을 지원하는 추상 가상 함수


Nano-COM의 많은 용례는 호출 대상에서 할당된 메모리 버퍼를 결과로 처리하기 위해 두 가지 함수를 정의한다.

  • Alloc 호출 대상에서 호출자가 반환받는 원시 버퍼(객체가 아님)를 할당하기 위해 메서드 구현에서 호출된다.
  • Free 더 이상 사용하지 않을 때 호출자가 호출 대상에서 할당된 버퍼를 해제하기 위해 메서드 호출자가 호출한다.


Direct3D와 같은 Nano-COM의 일부 구현에서는 할당자 함수를 피하고 호출자가 할당한 버퍼만 사용하도록 제한한다.

Nano-COM은 클래스, 아파트, 마샬링, 등록 등의 개념이 없다. 대신 객체 참조는 단순히 함수 경계를 넘어 전달되며 표준 언어 구문(예: C++ `new` 연산자)을 통해 할당된다.

Nano-COM의 기반은 Mozilla에서 파이어폭스(XPCOM)를 부트스트랩하는 데 사용되었으며, 현재 DirectX/Direct3D/DirectML의 기본 ABI 기술로 사용되고 있다.

3. 6. MSRPC

'''MSRPC'''는 윈도우 NT 서비스와 내부 구성 요소의 주요 프로세스 간 통신 메커니즘으로 사용되므로 기반으로 선택하기에 적합했다.[1] COM IDL은 객체 지향 확장을 포함하는 기능이 풍부한 DCE/RPC IDL을 기반으로 한다.[1]

4. 기술 세부 사항

COM 프로그래머는 COM 컴포넌트를 사용하여 소프트웨어를 개발한다. 각 COM 컴포넌트는 전역 고유 식별자(GUID) 형식의 클래스 ID(CLSID)로 식별된다. COM 컴포넌트의 기능은 하나 이상의 인터페이스를 통해 제공되며, 각 인터페이스는 GUID 형식의 인터페이스 ID(IID)로 식별된다.

COM 인터페이스는 C, C++, 비주얼 베이직 등 다양한 프로그래밍 언어 및 윈도우 플랫폼의 스크립트 언어와 바인딩된다. 컴포넌트에 대한 접근은 인터페이스의 메서드를 통해 이루어지며, 이를 통해 프로세스 간(inter-process) 또는 컴퓨터 간(inter-computer) 프로그래밍(후자는 DCOM 사용)이 가능하다.

1987년에 소개된 동적 데이터 교환(DDE)은 윈도우에서 최초의 프로세스 간 통신 기술 중 하나로,[4][5] 애플리케이션 간 메시지 송수신을 가능하게 했다.

COM 설계를 담당했던 앤토니 윌리엄스는 1988년 ''객체 아키텍처: 미지 대처 – 또는 – 동적으로 확장 가능한 클래스 라이브러리에서의 타입 안전성''과 1990년 ''상속에 관하여: 그것이 의미하는 바와 사용법''이라는 소프트웨어 컴포넌트 개념 관련 논문을 마이크로소프트 내에 배포했다.

객체 연결 및 포함(OLE)은 마이크로소프트의 최초 객체 기반 프레임워크로, DDE를 기반으로 복합 문서를 위해 설계되었다. 1991년 워드엑셀과 함께 소개되었으며, 1992년 윈도우 3.1부터 포함되었다.

1991년, 마이크로소프트는 비주얼 베이직 확장(VBX) 기술을 비주얼 베이직 1.0과 함께 도입했다. VBX는 동적 링크 라이브러리(DLL) 형태로 패키지화된 확장 기능으로, 객체를 양식에 배치하고 속성과 메서드를 통해 조작할 수 있게 했다.

1992년, 윈도우 3.1과 함께 마이크로소프트는 COM을 갖춘 OLE 2를 출시했다. COM의 애플리케이션 이진 인터페이스(ABI)는 1992년 출시된 MAPI ABI와 동일했으며, MSRPC를 기반으로 오픈 그룹DCE/RPC를 기반으로 했다. COM은 DDE를 대체하기 위해 만들어졌다.

1994년, COM 기반 OLE 사용자 지정 컨트롤(OCX) 기술이 VBX의 후속으로 도입되었다. 마이크로소프트는 OLE 2를 "OLE"로 명명했다.

1996년 초, 마이크로소프트는 OCX를 웹 브라우저 기능 확장으로 사용했다. 마이크로소프트는 인터넷 관련 OLE 일부를 액티브X로 변경했지만, 마이크로소프트 오피스의 복합 문서 기술은 예외였다.

1996년 후반, 마이크로소프트는 DCOM을 통해 COM을 네트워크로 확장했다.[6]

COM은 객체 지향적 프로그램 개발 및 배치를 위한 인터페이스 및 런타임 프레임워크이다. 전역 고유 식별자(GUID)를 사용하여 실행 중 타입을 개별 식별 및 지정하며, 각 COM 타입에는 실행 시 식별을 위한 GUID가 할당된다.[35]

COM은 타입 라이브러리를 통해 컴파일 및 실행 시간에 타입 정보를 제공하여 객체 간 상호 동작을 지원하는 동적 프레임워크이다.

COM에서 클래스는 '''코클래스'''(coclass)라고 불리며, 언어 독립적인 클래스 정의 수단이다. 코클래스는 하나 이상의 인터페이스를 구현하며, C++, Visual Basic 등 COM을 지원하는 프로그래밍 언어로 구현할 수 있다.[35] 각 코클래스는 클래스 ID (CLSID) 또는 ProgID로 식별된다. 클래스 ID는 GUID를 사용하며, ProgID는 "프로그램명.컴포넌트.버전" 형태의 문자열이다. ProgID는 필수가 아니며, 버전 지정이 없는 경우 컴퓨터마다 다른 CLSID를 가질 수 있다.[35]

COM은 구현과 인터페이스를 분리하여 다형성을 실현한다. 즉, 하나의 인터페이스에 대해 여러 구현을 제공하고, 응용 프로그램이 이를 선택하여 동일하게 조작할 수 있게 한다.[36]

윈도에서 COM 클래스, 인터페이스, 타입 라이브러리들은 GUID로써 레지스트리에 저장된다. COM 라이브러리는 레지스트리를 사용하여 COM 오브젝트들의 로컬 라이브러리를 찾거나 원격 서비스의 네트워크 위치를 찾는다.[37]

COM 객체는 객체 수명 관리를 위해 참조 카운팅을 사용한다. 객체의 참조 카운트는 `IUnknown` 인터페이스의 `AddRef` 및 `Release` 메서드를 통해 클라이언트에서 제어하며, 참조 카운트가 0이 되면 자체 메모리를 해제한다.[40]

COM 객체는 클래스 팩토리를 통해 생성되며, 이는 객체 생성에 대한 표준화된 방식을 제공한다.[35] 각 COM 객체는 고유한 클래스 ID (GUID)를 가지며, 자신의 클래스 팩토리를 통해 인스턴스화된다. 클래스 팩토리는 `IClassFactory` 인터페이스를 구현하는 COM 객체로, 다른 객체들을 생성하는 역할을 담당한다.

COM 컴포넌트는 타입 라이브러리를 사용하여 자기 자신에 대한 정보를 기록한다. 타입 라이브러리는 컴포넌트의 CLSID, 구현 인터페이스의 IID 및 각 인터페이스에 선언된 메서드 정보 등을 포함하며, 비주얼 베이직비주얼 스튜디오 같은 RAD 툴들을 통해 COM 컴포넌트를 사용하는 프로그래머들을 돕는 데 사용된다.

COM 프로그래머는 COM 환경 시작 및 종료, COM 오브젝트 인스턴스화 및 참조 횟수 관리, 버전 정보 쿼리, 개선된 버전 오브젝트 활용 또는 기능 축소 동작을 코딩해야 한다.[13] COM은 언어 독립적인 바이너리 표준이므로, 바이너리 인터페이스에 접근 가능한 모든 프로그래밍 환경에서 객체를 사용할 수 있다.

COM 클라이언트 소프트웨어는 COM 하위 시스템 활성화, COM 객체 인스턴스화, 참조 횟수 계산, 지원 인터페이스 쿼리를 수행한다.

COM은 "언어 독립적인"(language-agnostic) 또는 "언어 비의존적"(language-independent)인 바이너리 표준이며, 타입 라이브러리(바이너리로 정의된 데이터형과 인터페이스를 해석하는 기능)를 구현할 수 있다면 어떤 프로그래밍 언어로도 개발할 수 있다.

COM 객체는 동일 프로세스 내(인 프로세스), 프로세스 경계 넘어(아웃 오브 프로세스), 네트워크 통해 원격(DCOM)으로 투명하게 생성 및 사용될 수 있다. 아웃 오브 프로세스 및 원격 객체는 프로세스 또는 네트워크 경계 넘어 메서드 호출 및 반환 값을 직렬화하기 위해 마샬링을 사용한다. 이 마샬링은 로컬 인 프로세스 객체처럼 객체에 접근하는 클라이언트에게는 보이지 않는다.[1]

COM 오브젝트 인스턴스화 및 참조는 프로세스 내, 컴퓨터 내 프로세스 경계 넘어, DCOM 기술 이용해 네트워크 통해 원격으로 이루어질 수 있다. 프로세스 경계 넘거나 원격 사용 오브젝트들은 마샬링 사용하여 메서드 호출 보내고 결과 받는다. 마샬링은 투명하게 동작하여 오브젝트 및 해당 오브젝트 사용 코드에서는 보이지 않는다.[2]

COM은 '''아파트먼트''' 모델을 사용하여 스레딩을 처리한다. 아파트먼트는 하나 이상의 COM 컴포넌트를 포함할 수 있는 논리적 컨테이너이다. COM에는 단일 스레드 아파트먼트 (STA), 멀티 스레드 아파트먼트 (MTA), 스레드 중립 아파트먼트 (NA)의 세 가지 유형이 있다. 각 아파트먼트는 스레드 동기화 메커니즘을 나타내며, 객체와 스레드는 하나의 아파트먼트에 속한다.

아파트 유형스레딩 모델설명
단일 스레드 아파트먼트 (STA)[22]아파트단일 스레드가 객체의 메서드를 실행한다. 외부 스레드에서 호출된 메서드는 마샬링되어 시스템에 의해 자동으로 대기열에 추가된다. COM 런타임은 각 메서드 호출이 완료된 후 다음 호출이 실행되도록 동기화를 제공한다.
멀티 스레드 아파트먼트 (MTA)[23]자유COM 런타임은 동기화를 제공하지 않으며, 여러 스레드가 객체 메서드를 동시에 호출할 수 있다. 객체는 동시 접근 문제를 방지하기 위해 자체적으로 동기화를 처리해야 한다. STA 스레드에서 MTA 객체에 대한 호출도 마샬링된다.
동적으로 결정되는 아파트둘 다서버는 호출 스레드의 아파트먼트 유형에 맞춰 객체 생성 시 STA 또는 MTA를 자동 선택한다.[24] 이는 MTA 서버에 STA 스레드가 접근할 때 마샬링 오버헤드를 피하는 데 유용하다.
스레드 중립 아파트먼트 (NA)중립할당된 스레드가 없는 특수한 아파트먼트. STA 또는 MTA 스레드가 동일 프로세스 내 NA 객체를 호출하면, 호출 스레드는 일시적으로 해당 아파트먼트를 떠나 스레드 전환 없이 NA에서 직접 코드를 실행한다.[25] 따라서 NA는 아파트먼트 간 메서드 호출을 효율적으로 하기 위한 최적화로 볼 수 있다.


4. 1. 인터페이스

COM 컴포넌트는 하나 이상의 인터페이스를 통해 기능을 제공하며, 모든 인터페이스는 `IUnknown` 인터페이스를 상속한다. `IUnknown` 인터페이스는 세 가지 메서드를 제공한다.[34]

  • `AddRef()`, `Release()`: 참조 카운팅을 구현하여 인터페이스의 수명을 관리한다.
  • `QueryInterface()`: 인터페이스 ID (IID)를 사용하여 컴포넌트로부터 원하는 인터페이스를 얻는다. C++의 `dynamic_cast<>` 또는 D, 자바, C#의 캐스트와 유사한 역할을 수행한다.


COM 컴포넌트의 인터페이스는 반사적, 대칭적, 추이적 특성을 가져야 한다.[34]

  • 반사적 특성: `QueryInterface()`를 호출하여 인터페이스를 얻을 때 항상 동일한 인스턴스에서 인터페이스를 반환해야 한다.
  • 대칭적 특성: 인터페이스 B를 인터페이스 A의 `QueryInterface()`를 통해 얻었다면, 인터페이스 A 역시 인터페이스 B로부터 얻을 수 있어야 한다.
  • 추이적 특성: 인터페이스 B를 인터페이스 A로부터 얻을 수 있고, 인터페이스 C를 인터페이스 B로부터 얻을 수 있다면, 인터페이스 C는 인터페이스 A로부터 얻을 수 있어야 한다.


인터페이스는 가상 메소드 테이블에 대한 포인터로 구성된다. 가상 함수 테이블은 인터페이스가 정의하는 함수 선언을 실제로 구현하는 함수들에 대한 함수 포인터 목록을 포함하며, 인터페이스에 선언된 함수의 순서와 동일한 순서대로 저장한다. 이러한 함수 포인터 구조체를 전달하는 기법은 OLE 1.0이 자신의 시스템 라이브러리와 통신하기 위해 사용한 방법과 매우 유사하다.[34]

COM은 컴포넌트 간 통신을 위해 다양한 표준 인터페이스를 정의한다. 예를 들어, `IStream` 인터페이스는 데이터 스트림을 나타내는 컴포넌트(예: 파일을 읽고 쓰는 FileStream 컴포넌트)에서 사용되며, 스트림 읽기 및 쓰기를 위한 `Read`와 `Write` 메서드를 갖는다. 또 다른 표준 인터페이스인 `IOleObject`는 컨테이너에 연결되거나 포함되는 컴포넌트에서 사용되며, 컴포넌트의 테두리 사각형 크기 결정, 'Open', 'Save' 같은 동작 지원 여부 확인 등의 기능을 제공한다.[34]

각 COM 인터페이스는 인터페이스 ID (IID)라는 GUID로 식별된다. 사용자 지정 인터페이스는 `IUnknown`에서 파생되며, 가상 메서드 테이블에 대한 포인터를 통해 초기 바인딩된 접근을 제공한다. 후기 바인딩된 접근은 `IDispatch`를 구현하여 제공되며, 사용자 지정 인터페이스보다 더 광범위한 프로그래밍 컨텍스트에서 접근을 허용한다.[34]

4. 2. 클래스 (Coclass)

COM에서 클래스는 코클래스(coclass)라고 불리며, 하나 이상의 인터페이스를 구체적으로 구현한 것이다. 코클래스는 COM 컴포넌트 개발을 지원하는 모든 언어(예를 들어 C++나 비주얼 베이직 등)로 작성할 수 있다.[35]

코클래스는 GUID인 클래스 ID (CLSID)와 사람이 읽을 수 있는 프로그램 식별자인 ProgID로 식별된다. 코클래스는 이러한 식별자 중 하나를 통해 생성된다.[35]

개별 코클래스는 클래스 ID (CLSID)나 ProgID로 식별된다.

  • 클래스 ID는 GUID를 사용한 표현이다. 일반적으로 각 코클래스에 대해 클래스 ID를 하나 할당한다. 다만, 호환성을 위해 구 버전의 클래스 ID에 신 버전의 코클래스 구현을 등록하여 결과적으로 복수 클래스 ID가 동일한 코클래스를 가리키는 경우도 있다.
  • ProgID는 문자열 표현이다. `InternetExplorer.Application`이나 `Msxml2.DOMDocument.6.0` 등 "프로그램명.컴포넌트.버전" (버전은 필수 아님)이라는 규칙이다[35]。ProgID는 필수 사항은 아니며, 코클래스에 따라 ProgID를 가지지 않는 경우도 있다.


ProgID로 객체를 생성·취득할 때에는, ProgID에서 클래스 ID로 변환할 필요가 있다. 이 변환은 고유하지 않으며, 특히 버전 지정이 없는 ProgID에서는, 설치된 컴포넌트의 버전에 따라 컴퓨터마다 다른 CLSID가 될 가능성이 있다.

이 처리는 프로그래밍 언어나 라이브러리에 의해 구현되는 경우도 있다. VBScript 등 객체 생성 시 ProgID로의 지정만 가능한 프로그래밍 언어도 있다.

4. 3. 인터페이스 정의 언어 (IDL)와 타입 라이브러리

인터페이스 정의 언어(IDL)는 COM 컴포넌트의 타입들을 설명하는 메타데이터를 포함하는 텍스트 파일이다. COM 컴포넌트 개발 시, IDL을 사용하여 타입을 정의하는 것으로 시작하는 것이 일반적이다. 개발자는 IDL 파일을 통해 특정 프로그래밍 언어에 종속되지 않고 객체 지향적인 클래스, 인터페이스, 구조체, 열거형 등 사용자 정의 타입들을 정의할 수 있다.

IDL 파일은 MIDL 컴파일러에 의해 타입 라이브러리(.TLB 파일)로 컴파일된다. 이 타입 라이브러리에 저장된 바이너리 메타데이터는 VB, VC++, 델파이 등 다양한 프로그래밍 언어에서 처리된다. 각 언어 컴파일러는 자신의 언어에 맞는 형식(VB의 경우 VB 클래스, VC++의 경우 클래스, 구조체, 매크로, typedef 등)을 생성하며, 이러한 형식들은 .TLB 파일(궁극적으로는 원래 정의된 IDL 파일)에 정의된 coclass를 나타낸다.

IDL은 프로그래밍 언어에 독립적인 구문으로, 인터페이스 및 coclass를 정의하기 위한 추가 구문이 있는 C++와 유사하다. 또한, 식별자 및 매개변수 간의 관계와 같은 메타데이터를 정의하기 위해 선언 앞에 대괄호로 묶인 속성을 지원한다.

MIDL 컴파일러는 C/C++과 함께 사용하기 위해 선언된 인터페이스의 vtbl과 일치하는 `struct` 정의와 인터페이스의 GUID 선언을 포함하는 C 파일을 사용하여 헤더 파일을 생성한다. 프록시 모듈에 대한 C++ 소스 코드는 MIDL 컴파일러에 의해 생성될 수도 있다. 이 프록시는 COM 호출을 원격 프로시저 호출로 변환하기 위한 메서드 스텁을 포함하여 프로세스 외부 통신을 위해 DCOM을 활성화한다.

MIDL은 다른 도구에서 다른 컨텍스트에서 액세스를 지원하는 데 사용할 수 있는 바이너리 타입 라이브러리(TLB)를 생성할 수 있다.

COM 컴포넌트에 관한 정보 기술 수단으로, MIDL(마이크로소프트 인터페이스 정의 언어, IDL도 참조)과 타입 라이브러리가 있다. MIDL은 텍스트 파일로 주로 개발 시에 사용된다. 타입 라이브러리는 타입에 관한 언어 독립적인 정보를 제공하는 바이너리 파일이며, 개발 시뿐만 아니라 실행 시에도 참조된다.[1]

IDL 파일에서는 객체 지향적인 클래스나 인터페이스, 구조체, 열거형 등의 사용자 정의 타입을 프로그래밍 언어에 의존하지 않고 기술할 수 있다. 이 IDL에서는 C/C++와 비슷한 키워드와, 거기에 추가하여 인터페이스를 정의하는 "interface", 코클래스를 정의하는 "coclass", 그것들의 집합을 나타내는 "library"라는 2개의 키워드를 사용한다. 또한 각 선언 앞에 대괄호`[]`로 묶어 속성을 지정할 수 있으며, 인터페이스에 GUID (IID)를 지정하거나, 배열 인자와 그 길이를 나타내는 인자와의 관계를 지시할 수 있다.[1]

MIDL 컴파일러는 IDL 파일로부터 다양한 프로그래밍 언어에 맞게 컴파일한다. C/C++용으로는 인터페이스 등이 선언된 헤더 파일과 GUID를 정의한 C 소스 파일, 또한 COM의 메서드 호출을 RPC용으로 변환하는 "프록시"와 그것을 원래대로 되돌리는 "스텁"의 소스 파일도 생성된다. MIDL은 타입 라이브러리(.TLB 파일)도 만든다. 타입 라이브러리에 포함된 바이너리 메타 데이터는 컴파일러나 실행 환경(Visual Basic이나 델파이, .NET의 CLR 등)에서 이용된다. 그 결과 타입 라이브러리 파일에서 정의된 코클래스를 그 언어와 환경에 가져와 사용할 수 있게 된다.[1]

4. 4. 객체 프레임워크로서의 COM

COM은 프로그램을 객체 지향적으로 개발하고 배치하기 위한 인터페이스이자 런타임 프레임워크이다. 실행 중에 타입들을 개별적으로 식별하고 지정하기 위해 전역 고유 식별자(GUID)를 사용하며, 각 COM 타입에는 실행 시 식별될 수 있도록 GUID가 할당된다.[35]

COM은 타입 라이브러리를 통해 컴파일 및 실행 시간에 타입 정보를 제공하여 객체 간 상호 동작을 지원하는 동적 프레임워크로서의 기능을 수행한다. 예를 들어, IDL에서 다음과 같이 `MyObject`라는 COM 클래스를 선언할 수 있다.



coclass MyObject

{

[default] interface IMyObject;

[default, source] dispinterface _IMyObjectEvents;

};



이는 개념적으로 다음과 같은 C++ 클래스 정의와 동일하다.



class CSomeObject : public ISomeInterface

{

...

...

...

};



여기서 `ISomeInterface`는 C++ 가상 클래스이다.

타입 라이브러리는 각 언어 컴파일러가 COM 클래스를 이해하고 바이너리 실행 코드를 생성하는 데 필요한 정보를 제공한다. COM 코클래스가 구현되면, `CoCreateInstance()` API를 사용하여 인스턴스화할 수 있다.



CoCreateInstance

(

CLSID_MyObject,

NULL,

CLSCTX_INPROC_SERVER,

IID_IMyObject,

(void**)&m_pIMyObject

);



이는 개념적으로 다음 C++ 코드와 동일하다.



ISomeInterface* pISomeInterface = NULL;

pISomeInterface = new CSomeObject();



COM에서 클래스는 '''코클래스'''(coclass)라고 불리며, 이는 언어에 독립적인 클래스 정의 수단이다. 코클래스는 하나 이상의 인터페이스를 구현하며, C++, Visual Basic 등 COM을 지원하는 프로그래밍 언어로 구현할 수 있다.[35]

각 코클래스는 클래스 ID (CLSID) 또는 ProgID로 식별된다. 클래스 ID는 GUID를 사용하며, ProgID는 "프로그램명.컴포넌트.버전" 형태의 문자열이다. ProgID는 필수가 아니며, 버전 지정이 없는 경우 컴퓨터마다 다른 CLSID를 가질 수 있다.[35]

COM은 구현과 인터페이스를 분리하여 다형성을 실현한다. 즉, 하나의 인터페이스에 대해 여러 구현을 제공하고, 응용 프로그램이 이를 선택하여 동일하게 조작할 수 있게 한다.[36]

4. 5. 레지스트리

윈도에서 COM 클래스, 인터페이스, 타입 라이브러리들은 GUID로써 레지스트리에 저장된다. COM 라이브러리는 레지스트리를 사용하여 COM 오브젝트들의 로컬 라이브러리를 찾거나 원격 서비스의 네트워크 위치를 찾는다.[37]

초기에는 형식 라이브러리 메타데이터를 시스템 레지스트리에 저장해야 했다. COM 클라이언트는 객체 생성을 위해 레지스트리 정보를 사용했다.

윈도우 XP에서 등록이 필요 없는(RegFree) COM이 도입되어 형식 라이브러리 메타데이터를 어셈블리 매니페스트로 실행 파일의 리소스 또는 구성 요소와 함께 설치되는 별도의 파일로 저장할 수 있게 되었다.[15] 이를 통해 동일한 컴퓨터에 동일한 구성 요소의 여러 버전을 다른 디렉터리에 설치할 수 있으며, XCOPY 배포가 가능하게 되었다.[16] 그러나 이 기술은 EXE COM 서버에 대한 지원이 제한적이며,[17] MDAC, MSXML, DirectX 또는 Internet Explorer와 같은 시스템 전체 구성 요소에는 사용할 수 없다.

응용 프로그램 로드 중에 윈도 로더는 매니페스트를 검색한다.[18] 매니페스트가 있으면 로더는 매니페스트의 정보를 활성화 컨텍스트에 추가한다.[16] COM 클래스 팩토리가 클래스를 인스턴스화하려고 할 때, CLSID에 대한 구현을 찾을 수 있는지 확인하기 위해 활성화 컨텍스트를 먼저 확인한다. 조회에 실패하는 경우에만 레지스트리를 검색한다.[16]

윈도우 XP 이후에는, "격리된 응용 프로그램과 Side-by-Side 어셈블리"라고 불리는 구조를 사용하여, 레지스트리가 아닌 매니페스트 파일을 사용하여 컴포넌트 종속성을 해결하는 것도 가능하다. 이 구조를 사용함으로써, COM 컴포넌트를 시스템 전체에서 공유하지 않고, 애플리케이션별로 개인 어셈블리로 배포 및 운용하는 것도 가능하게 된다.

4. 6. 참조 카운팅

COM 객체는 객체 수명 관리를 위해 참조 카운팅을 사용한다. 객체의 참조 카운트는 `IUnknown` 인터페이스의 `AddRef` 및 `Release` 메서드를 통해 클라이언트에서 제어한다. COM 객체는 참조 카운트가 0이 되면 자체 메모리를 해제해야 한다.[40]

이를 구현하기 위해, COM 객체는 일반적으로 참조 카운트를 위한 정수 값을 갖는다. 객체의 인터페이스에서 `AddRef()`가 호출되면 이 정수 값이 증가한다. `Release()`가 호출되면 이 정수 값은 감소한다. `AddRef()`와 `Release()`는 COM 객체의 클라이언트가 해당 객체의 수명에 관여할 수 있는 유일한 수단이다. 내부 정수 값은 COM 객체의 개인 멤버이며, 직접 접근할 수 없다.

`AddRef()`의 목적은, COM 객체에 대한 새로운 참조가 생겨 해당 참조가 유효한 동안 생존을 유지해야 한다는 것을 COM 객체에 나타내는 것이다. `Release()`의 목적은, 클라이언트(또는 클라이언트 코드의 일부)가 더 이상 객체를 필요로 하지 않게 되었고, 만약 참조 카운트가 0에 도달하면 객체가 스스로를 파기할 것이라는 것을 나타내는 것이다.

일부 프로그래밍 환경(예: Visual Basic)은 객체 사용을 단순화하기 위해 자동 참조 카운팅을 제공한다. C 언어로 COM을 이용하는 경우, 명시적인 참조 카운트 조작이 필요하다. C++에서는 직접 관리하거나, 참조 카운트를 전부 관리해주는 스마트 포인터(ATL::CComPtr 등)를 이용하는 것을 선택할 수 있다.

다음은 COM 객체에서 적절한 참조 카운트 제어를 위한 `AddRef()`와 `Release()` 호출에 대한 일반적인 가이드라인이다.

  • (반환 값 또는 out 매개변수로) 인터페이스의 참조를 반환하는 함수(객체 메서드와 전역 함수 모두)는, 반환하기 전에 해당 객체의 참조 카운트를 증가시켜야 한다. 따라서 함수나 메서드 내부에서, `AddRef()`가 (반환하는) 인터페이스의 참조에 대해 호출된다. `IUnknown` 인터페이스의 `QueryInterface()` 메서드가 이 예시이다. 따라서, 반환된 인터페이스의 참조는 이미 증가되었으며, 반환된 인터페이스의 참조에 `AddRef`를 다시 호출할 필요가 없다는 것을 개발자는 이해해야 한다.
  • 인터페이스의 포인터가 덮어쓰여지거나 스코프에서 벗어나기 전에 인터페이스의 참조에서 `Release()`를 호출해야 한다.
  • 인터페이스의 참조 포인터에서 복사본을 만드는 경우, 해당 포인터로 `AddRef()`를 호출해야 한다. 결국 이 경우에는, 해당 객체의 또 다른 참조를 실제로 생성하는 것이다.
  • 인터페이스를 참조하는 것만으로 내부 리소스를 할당해야 할 필요가 있으므로 인터페이스마다 참조를 카운트하도록 객체가 구현되었을 수 있으므로, 참조한 특정 인터페이스에 대해 `AddRef()`와 `Release()`를 호출해야 한다.


원격 객체의 경우 모든 참조 카운트 호출이 네트워크를 통해 전송되지는 않는다. 프록시는 원격 객체에 대한 참조를 하나만 유지하고, 자체 로컬 참조 카운트를 관리한다.

C++ 개발자를 위한 COM 개발을 단순화하기 위해, 마이크로소프트는 ATL (액티브 템플릿 라이브러리)를 도입했다. ATL은 비교적 높은 수준의 COM 개발 패러다임을 제공한다. 또한 스마트 포인터 유형을 제공하여 COM 클라이언트 애플리케이션 개발자가 참조 카운팅을 직접 유지 관리할 필요가 없도록 한다. COM을 인식하는 다른 라이브러리 및 언어에는 MFC, VC 컴파일러 COM 지원,[12] VBScript, Visual Basic, ECMAScript (JavaScript) 및 Borland Delphi가 있다.

4. 7. 인스턴스화

COM 객체는 클래스 팩토리를 통해 생성되며, 이는 객체 생성에 대한 표준화된 방식을 제공한다.[35] 각 COM 객체는 고유한 클래스 ID (GUID)를 가지며, 자신의 클래스 팩토리를 통해 인스턴스화된다. 클래스 팩토리는 `IClassFactory` 인터페이스를 구현하는 COM 객체로, 다른 객체들을 생성하는 역할을 담당한다.

클래스 팩토리는 일반적으로 COM 객체를 포함하는 바이너리 실행 파일(서버 코드) 내에 존재한다. 개발자는 클래스 팩토리를 직접 작성하거나 코드 생성 프로그램을 통해 생성할 수 있다. 클래스 팩토리를 사용하면 싱글턴과 같은 디자인 패턴을 쉽게 구현할 수 있어, 객체 생성에 대한 유연성을 높일 수 있다.

클라이언트 애플리케이션은 `CoGetClassObject()` API 함수를 사용하여 COM 서버에서 클래스 팩토리를 얻을 수 있다. DLL 기반 서버는 `DllGetClassObject()` 전역 함수를 익스포트해야 하며, EXE 기반 서버는 `CoRegisterClassObject()` API를 통해 실행 중에 클래스 팩토리를 등록한다.

클래스 팩토리를 사용하여 객체를 생성하는 일반적인 과정은 다음과 같다.

# `CoGetClassObject()` API를 사용하여 원하는 객체의 클래스 팩토리를 얻는다. 이때 생성하려는 객체의 클래스 ID가 필요하다.

# 반환된 클래스 팩토리 객체의 `CreateInstance()` 메서드를 사용하여 COM 객체의 인스턴스를 생성한다.

# 클래스 팩토리 객체도 COM 객체이므로, 더 이상 필요하지 않으면 `Release()` 메서드를 호출하여 해제해야 한다.

더 높은 수준의 인스턴스화 방법도 가능하다. 예를 들어, `CoCreateInstance()` API를 사용하면 클래스 팩토리를 얻는 과정을 건너뛰고 바로 COM 객체를 생성할 수 있다. 비주얼 베이직과 같은 언어에서는 `CreateObject()` 함수나 `new` 키워드를 사용하여 객체 생성을 추상화할 수 있다. 이러한 방법들은 내부적으로 `CoGetClassObject()` API와 `IClassFactory::CreateInstance()` 메서드를 호출하여 객체를 생성한다.

4. 8. 리플렉션

COM 컴포넌트는 타입 라이브러리를 사용하여 자기 자신에 대한 정보를 기록할 수 있다. 타입 라이브러리는 컴포넌트의 CLSID, 컴포넌트가 구현하는 인터페이스의 IID 및 각 인터페이스에 선언된 메서드 정보 등을 포함한다. 타입 라이브러리는 일반적으로 비주얼 베이직비주얼 스튜디오 같은 RAD 툴들을 통해 COM 컴포넌트를 사용하는 프로그래머들을 돕는 데 사용된다.

4. 9. 프로그래밍

COM 프로그래머는 COM 환경을 시작하고 종료하며, COM 오브젝트를 인스턴스화하고 참조 횟수를 관리하며, 버전 정보를 얻기 위해 오브젝트에 쿼리하고, 개선된 버전의 오브젝트를 활용하거나 최신 버전을 사용할 수 없을 때 기능을 축소하여 동작하도록 코딩해야 한다.[13]

COM은 언어에 독립적인 바이너리 표준이므로, 바이너리 인터페이스에 접근 가능한 모든 프로그래밍 환경에서 객체를 사용할 수 있다.

COM 클라이언트 소프트웨어는 COM 하위 시스템을 활성화하고, COM 객체를 인스턴스화하고, 참조 횟수를 계산하고, 지원되는 인터페이스에 대해 객체를 쿼리한다.

마이크로소프트 비주얼 C++ 컴파일러는 "C++ 특성"이라고 불리는 C++ 언어 확장 기능을 지원한다.[14] 이는 COM 개발을 단순화하고 C++로 COM 서버를 구현할 때 필요한 상용구 코드를 최소화한다.

COM은 "언어에 독립적인"(language-agnostic) 또는 "언어 비의존적"(language-independent)인 바이너리 표준이며, 타입 라이브러리(바이너리로 정의된 데이터형과 인터페이스를 해석하는 기능)를 구현할 수 있다면 어떤 프로그래밍 언어로도 개발할 수 있다.

런타임 라이브러리(엄밀히 말하면 프로그래머)는 COM 환경에 진입하여 COM 객체를 인스턴스화하고 참조를 계산하며, 버전 정보를 통해 객체를 질의하고, 새로운 버전의 객체를 활용하거나, 새로운 버전을 사용할 수 없을 경우에는 이전 버전에서도 동작하도록 결함 허용을 코딩해야 한다.

4. 10. 애플리케이션과 네트워크에서의 투명성

COM 객체는 동일한 프로세스 내(인 프로세스), 프로세스 경계를 넘어(아웃 오브 프로세스), 또는 네트워크를 통해 원격으로(DCOM) 투명하게 생성되고 사용될 수 있다. 아웃 오브 프로세스 및 원격 객체는 프로세스 또는 네트워크 경계를 넘어 메서드 호출 및 반환 값을 직렬화하기 위해 마샬링을 사용한다. 이 마샬링은 로컬 인 프로세스 객체처럼 객체에 접근하는 클라이언트에게는 보이지 않는다.[1]

COM 오브젝트를 인스턴스화하고 참조하는 작업은 하나의 프로세스 안에서, 하나의 컴퓨터 안에서 프로세스의 경계를 넘어, 또는 DCOM 기술을 사용하여 네트워크를 통해 원격으로 이루어질 수 있다. 프로세스의 경계를 넘거나 원격으로 사용되는 오브젝트들은 마샬링을 사용하여 메서드 호출을 보내고 결과를 받을 수 있다. 마샬링은 투명하게 동작하기 때문에 오브젝트 및 해당 오브젝트를 사용하는 코드에서는 보이지 않는다.[2]

4. 11. COM 스레딩 (아파트먼트 모델)

COM은 '''아파트먼트''' 모델을 사용하여 스레딩을 처리한다. 아파트먼트는 하나 이상의 COM 컴포넌트를 포함할 수 있는 논리적 컨테이너이다. COM에는 단일 스레드 아파트먼트 (STA), 멀티 스레드 아파트먼트 (MTA), 스레드 중립 아파트먼트 (NA)의 세 가지 유형이 있다. 각 아파트먼트는 스레드 동기화 메커니즘을 나타내며, 객체와 스레드는 하나의 아파트먼트에 속한다.

아파트 유형스레딩 모델설명
단일 스레드 아파트먼트 (STA)[22]아파트단일 스레드가 객체의 메서드를 실행한다. 외부 스레드에서 호출된 메서드는 마샬링되어 시스템에 의해 자동으로 대기열에 추가된다. COM 런타임은 각 메서드 호출이 완료된 후 다음 호출이 실행되도록 동기화를 제공한다.
멀티 스레드 아파트먼트 (MTA)[23]자유COM 런타임은 동기화를 제공하지 않으며, 여러 스레드가 객체 메서드를 동시에 호출할 수 있다. 객체는 동시 접근 문제를 방지하기 위해 자체적으로 동기화를 처리해야 한다. STA 스레드에서 MTA 객체에 대한 호출도 마샬링된다.
동적으로 결정되는 아파트둘 다서버는 호출 스레드의 아파트먼트 유형에 맞춰 객체 생성 시 STA 또는 MTA를 자동 선택한다.[24] 이는 MTA 서버에 STA 스레드가 접근할 때 마샬링 오버헤드를 피하는 데 유용하다.
스레드 중립 아파트먼트 (NA)중립할당된 스레드가 없는 특수한 아파트먼트. STA 또는 MTA 스레드가 동일 프로세스 내 NA 객체를 호출하면, 호출 스레드는 일시적으로 해당 아파트먼트를 떠나 스레드 전환 없이 NA에서 직접 코드를 실행한다.[25] 따라서 NA는 아파트먼트 간 메서드 호출을 효율적으로 하기 위한 최적화로 볼 수 있다.



같은 아파트먼트에 속한 스레드와 객체는 동일한 스레드 접근 규칙을 따른다. 따라서 같은 아파트먼트 내 메서드 호출은 COM의 도움 없이 직접 수행된다. 아파트먼트 간 메서드 호출은 마샬링을 통해 수행되며, 여기에는 '''프락시'''와 '''스텁'''이 사용된다. 스레드 중립 아파트먼트(NA)의 경우, 객체의 모든 메서드들이 재진입 가능해야 한다.[44][45]

5. COM에 대한 비판

COM은 구현이 복잡하여 프로그래머들이 "플러밍(plumbing)" 문제 등으로 어려움을 겪을 수 있다.

5. 1. 복잡성

COM은 특히 .NET과 같은 더 현대적인 컴포넌트 기술에 비해 상대적으로 복잡하다.[7]

5. 2. 환경 초기화

COM을 사용하려면 프로그래머가 `CoInitialize` 또는 `CoInitializeEx`와 `CoUninitialize` 메서드를 호출해야 한다.[1] OLE 클립보드나 드래그 앤 드랍 기능을 사용하는 코드는 `OleInitialize`와 `OleUninitialize` 메서드도 호출해야 한다.[1] 시스템의 일부 스레드는 COM을 모르는 라이브러리에서 만들어질 수 있으므로, 프로그래머는 자신이 만든 스레드 외의 스레드에서 COM 라이브러리를 사용할 때 주의해야 한다.[1]

5. 3. 메시지 펌핑

COM은 초기화될 때 스레드나 프로세스 간의 메시지 라우팅을 위해 숨겨진 윈도를 생성한다. 이 윈도는 자체 윈도 메시지 큐를 가지며, 큐의 데이터는 정기적으로 확인 및 사용된다. STA(Single-Threaded Apartment)가 초기화되면 아파트 간 및 프로세스 간 메시지 라우팅에 사용되는 숨겨진 창이 생성된다. 이 창은 메시지 큐를 정기적으로 "펌핑"해야 하며, 이러한 구조를 "메시지 펌프"라고 부른다.

초기 버전의 윈도에서는 이 메시지 펌핑이 제대로 처리되지 않으면 시스템 전체가 멈추는 데드락 현상이 발생할 수 있었다. 특히 일부 윈도 API는 내부적으로 COM을 초기화하므로, COM 구현 세부 사항이 외부로 "누출"되어 문제가 더 복잡해졌다.[1]

5. 4. 참조 카운팅

COM 참조 카운팅은 두 개 이상의 오브젝트가 순환 참조하는 문제를 일으킬 수 있다. 애플리케이션을 디자인할 때 이 사항을 반드시 고려하여 오브젝트가 고아(orphaned)가 되지 않도록 해야 한다. COM "이벤트 싱크(event sink)" 모델을 사용하는 오브젝트의 참조 카운트는 항상 0보다 크게 된다. 왜냐하면 이벤트를 발생시키는 오브젝트는 해당 이벤트를 처리하는 오브젝트에 대한 참조가 필요하게 되는데, 이는 오브젝트의 참조가 결코 0이 되지 않도록 하기 때문이다.[1]

참조 사이클은 일반적으로 대역외 종료(out-of-band termination) 또는 신분 나누기(split identities)를 사용하면 깨진다. 대역외 종료 기법에서 오브젝트는 호출될 경우 갖고 있는 다른 오브젝트에 대해 모든 참조를 버리는(drop) 메서드를 노출하는데, 이 메서드가 호출되면 사이클은 깨진다. 신분 나누기 기법에서는 하나의 구현이 서로 다른 두 개의 COM 오브젝트(identities)를 노출하여, COM 오브젝트 사이에 약한 참조를 만든다. 이는 참조 사이클을 방해한다.[1]

5. 5. DLL 지옥

COM 컴포넌트는 윈도 레지스트리에 위치 정보를 저장하기 때문에, 특정 컴포넌트에 대하여 하나의 버전만을 설치하여 사용할 수 있다. 따라서 두 개 이상의 애플리케이션에서 특정 컴포넌트의 서로 다른 버전을 필요로 할 때 DLL 지옥 문제가 발생할 수 있다.

윈도우 XP는 "'''레지스트레이션-프리 COM(Registration-free COM)'''"[46]이라는 새로운 COM 오브젝트 등록 방식을 도입했다. 이 기능은 애플리케이션이 COM 오브젝트를 설치할 때 COM 등록에 필요한 정보를 전역 레지스트리가 아닌 자신의 디렉터리에 저장하여 사용할 수 있도록 한다. 이 기능은 해당 COM 컴포넌트를 단일 애플리케이션에서 사용할 경우에만 적용 가능하다. 레지스트레이션-프리 COM을 사용하면 대부분 DLL 지옥을 피할 수 있다. 다만 최소 윈도우 XP 이상의 운영체제가 필요하며, EXE COM 서버 및 MDAC, MSXML, 다이렉트X, 인터넷 익스플로러 등의 시스템 전역 컴포넌트에는 사용할 수 없다.

내부 프로세스 COM 컴포넌트는 DLL 파일로 구현되며, 등록은 CLSID당 하나의 버전만 허용하므로, 어떤 상황에서는 "DLL 지옥" 현상의 영향을 받을 수 있다. 무등록 COM 기능은 내부 프로세스 컴포넌트에 대해 이 문제를 해결한다. 무등록 COM은 외부 프로세스 서버에는 사용할 수 없다.

참조

[1] 웹사이트 Documentation Archive https://developer.ap[...]
[2] 웹사이트 Plug-ins and Microsoft's COM https://developer.ap[...] Apple Inc. 2010-10-05
[3] 웹사이트 Binary compatibility across Visual C++ versions https://archive.toda[...] Microsoft forum
[4] 웹사이트 About Network DDE - Windows applications https://docs.microso[...] 2018-05-30
[5] 웹사이트 Code Execution Technique Takes Advantage of Dynamic Data Exchange https://securingtomo[...] 2017-10-27
[6] 간행물 draft-brown-dcom-v1-spec-03 - Distributed Component Object Model Protocol -- DCOM/1.0 https://datatracker.[...] 2019-08-29
[7] 웹사이트 Runtime Callable Wrapper http://msdn.microsof[...] 2023-04-19
[8] 웹사이트 COM Callable Wrapper http://msdn.microsof[...] 2021-09-15
[9] 웹사이트 Competing components make for prickly panelists https://www.infoworl[...] 2020-07-16
[10] 웹사이트 win32com Documentation Index http://docs.activest[...]
[11] 웹사이트 Python and COM http://www.boddie.or[...]
[12] 웹사이트 Compiler COM Support http://msdn.microsof[...] Microsoft 2021-08-03
[13] 웹사이트 C++ Attributes Reference http://msdn.microsof[...] Microsoft MSDN
[14] 웹사이트 C++ Attributes: Make COM Programming a Breeze with New Feature in Visual Studio .NET http://msdn.microsof[...] MSDN Magazine
[15] 웹사이트 Assembly Manifests http://msdn.microsof[...] MSDN 2009-11-05
[16] 웹사이트 Simplify App Deployment with ClickOnce and Registration-Free COM http://msdn.microsof[...] MSDN Magazine 2008-04-22
[17] 웹사이트 How to use an out-of-process COM server without its tlb file https://stackoverflo[...] 2011-04-16
[18] 웹사이트 Concepts of Isolated Applications and Side-by-side Assemblies https://msdn.microso[...] MSDN 2016-02-05
[19] 웹사이트 Registration-free COM https://blogs.msdn.m[...] 2016-04-29
[20] 웹사이트 DllGetClassObject entry point (COM) https://msdn.microso[...]
[21] 웹사이트 Processes, Threads, and Apartments http://msdn.microsof[...] Microsoft MSDN
[22] 웹사이트 Single-Threaded Apartments http://msdn.microsof[...] Microsoft MSDN
[23] 웹사이트 Multithreaded Apartments http://msdn.microsof[...] Microsoft MSDN
[24] 웹사이트 Understanding and Using COM Threading Models http://msdn.microsof[...] Microsoft MSDN
[25] 웹사이트 Understanding COM Apartments http://www.codeguru.[...] Codeguru
[26] 웹사이트 Component Object Model (COM) - Windows applications https://docs.microso[...] Microsoft Docs
[27] 웹사이트 The Component Object Model - Windows applications https://docs.microso[...] Microsoft Docs
[28] 웹사이트 '[MC-COMQC]: Component Object Model Plus (COM+) Queued Components Protocol' https://docs.microso[...] Microsoft Docs
[29] 웹사이트 The Mono Runtime https://www.mono-pro[...] Mono
[30] 웹사이트 COM Interop https://www.mono-pro[...] Mono
[31] 문서
[32] 문서
[33] 웹사이트 Windows 8時代のアプリ開発とWinRT - @IT https://atmarkit.itm[...]
[34] 웹사이트 IOleObject (oleidl.h) - Win32 apps https://docs.microso[...] Microsoft Docs
[35] 웹사이트 Key (COM) https://msdn.microso[...] 2016-06-12
[36] 문서 例えば、DAOでは呼び出し先コンポーネントがSQL Server用実装であるか、Oracle DB用実装であるかを意識することなく、クライアントアプリケーションを記述できる。
[37] 웹사이트 ActiveXコントロール、ActiveXサーバ、およびタイプライブラリを登録する方法 - National Instruments http://digital.ni.co[...]
[38] 웹사이트 DirectX に関してよく寄せられる質問 https://msdn.microso[...]
[39] 웹사이트 The Versioning Theory for RPC and COM (Windows) https://msdn.microso[...]
[40] 웹사이트 参照カウント https://msdn.microso[...]
[41] 웹사이트 http://msdn.microsof[...]
[42] 웹사이트 http://msdn2.microso[...]
[43] 웹인용 보관된 사본 https://web.archive.[...] 2006-05-17
[44] 문서 The Thread Neutral Apartment allows different threads, none of which is necessarily dedicated to calling methods on the object, to make such calls.
[45] 문서 The only proviso is that all methods on the object must be serially reentrant.
[46] 문서 등록이 필요없는 COM



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com