■ ActiveX와 COM의 이해
프로그래머라는 직업은 끊임없이 자기 개발과 새로운 기술에 대한 습득을 하여야 하는 직업일 것이다. 이처럼 프로그래머의 세계에서의 개념의 변화는 너무 자주 일어나는 것이다. 근래의 모든 프로그래밍의 추세는 인터넷이라는 거대한 네트워크 망에서 동작하는 여러 가지 기법들이 소개되고, 구현되고 있는 실정이다. 예전에는 자기 컴퓨터에서 현재의 네트워크까지 프로그래밍의 기법이 변화되면서 여러 가지 개념들이 생겨나고 없어졌다. 이번 장에서는 인터넷 프로그래밍 기법의 기본 개념이 되는 ActiveX와 COM에 대해서 알아보도록 하겠다. 인터넷을 사용하고 인터넷에서 동작하는 프로그래밍을 하기를 원한다면 본 장의 기본 개념에 대한 이해를 하여야만 할 것이다. 그럼 지금부터 인터넷 프로그래밍의 세계로 들어가 보도록 하자.
1.1 컴포넌트 프로그래밍
미래에는 컴포넌트 기술이 컴퓨터 환경을 지배한다는 말이 있다. 국내에서도 컴포넌트 기술의 중요성을 인식하고 국가적인 차원에서 이를 육성하고자 하는 여러 가지 방안들이 제시되고 있다. 그럼 컴포넌트라는 것이 무엇이기에 국가에서까지 나서서 이를 장려하고 있는 것일까? 지금부터 그 해답을 찾아보기로 하자.
1) OCX와 ActiveX
필자가 처음 비주얼 베이직을 접한 것이 버전 3.0부터 인 것으로 기억한다. 그때만 하여도 지금과 같은 복잡한 개념이나 기능은 거의 없었다. 다만 진보된 개념으로 소개되었던 것이 VBX(Visual Basic Extension)라는 것이다. 즉 당시 비주얼 베이직은 현재의 여러 가지 컨트롤들이 VBX라는 것으로 제작되었다. 그 당시만 하여도 Third Party의 다른 컨트롤들도 이런 VBX 기법으로 제작되어 사용되었었다. 그러나 버전 4.0이 나오면서 VBX의 개념이 OCX(OLE Control Extensions)라는 것으로 대체되었다. 예전의 VBX를 이용하여 제작된 컨트롤들이 OCX로 제작되면서 점차 VBX라는 것은 퇴색해 버렸다.
① VBX에서 OCX로
그러면 왜 VBX에서 OCX라는 새로운 개념으로 변하였을까? 그 답은 재 활용성의 극대화를 꾀하기 위해서이다. VBX와 OCX는 사용 범위의 차이가 가장 큰 차이점이다. VBX가 비주얼 베이직에 국한된 것이었던 것에 반해서 OCX는 윈도우 시스템 자원으로 사용이 가능하도록 OLE와 COM(Component Object Model)의 결합 형태로 작성되었다. 또한 VBX가 16비트를 기준으로 제작되었지만 OCX는 32비트를 기준으로 제작되었다. 이런 몇 가지 점들만 살펴보아도 VBX와 OCX의 차이점을 확실히 알 수 있을 것이다.
② OCX(OLE Control Extensions)란 무언인가?
앞서 이야기하였듯이 OCX는 기존의 16비트의 VBX 대신 32비트로 구성된다. 이 새로운 컨트롤 표준 방식은 기존에는 비주얼 베이직 프로그램에만 국한되어 있던 것을 윈도우 시스템 리소스로 서로 공유할 수 있도록 OLE 기능을 추가된 방식이다.
--------------------------------------------------------------------------------
[참고하세요]
OLE(Object Linking Embedding) : 대상이 되는 파일이나 프로그램을 연결하여 끼워 넣는 방법을 가리킨다. 워드 프로그램에서 다른 프로그램에 있는 도표나 그림들을 개체 삽입을 통해서 끼워 넣는 방식이 OLE의 한 예이다.
[그림 1-1] MS 워드에서의 개체 삽입
윈도우 3.1로부터 표준 기능으로 제공되었으며 현재는 기능이 대폭 강화된 OLE2가 사용되고 있다. OLE에는 크게 링크와 임베딩의 기술이 있다. 이중 링크는 원래 정보가 변경되면 그것을 사용한 문서에도 변경이 반영되는 것을 말하며, 임베드는 문서를 편집하는 경우 자동으로 데이터를 작성하는 프로그램이 실행되는 것을 말한다.
[그림 1-2] MS 워드에서의 Excel 그래프 삽입
--------------------------------------------------------------------------------
이처럼 OCX가 윈도우 시스템 리소스의 공유를 기반으로 서로의 공유가 가능함으로 비주얼 베이직에서 만든 컨트롤을 다른 프로그램에서도 동일하게 사용할 수 있다. 얼마나 놀라운 기술인가? 자기가 필요한 부분의 컨트롤을 직접 제작하고, 다른 프로그램에서 이 컨트롤을 사용하는 것을 상상만 하여도 즐거운 일일 것이다. 이는 또한 윈도우뿐만이 아니라 인터넷이라는 거대한 망을 통해서도 공통으로 사용할 수 있는 길을 만들을 주는 방식이다. 이것이 OCX가 만들어지게 된 가장 중요한 이유가 된다.
③ ActiveX란 무엇인가?
그러면 왜 VBX에서 OCX라는 새로운 개념으로 변하였을까? 지금까지 VBX에서 OCX까지 여러 가지 개념들에 대해서 알아보았다. 그러면 우리가 지금부터 알아야 하는 것은 무엇일까? 인터넷 프로그래밍의 가장 핵심이 되는 ActiveX라는 개념이다. '지금까지의 개념적인 설명도 어려운데 또 이상한 개념이 나오는구나'라고 생각할 수 있지만 ActiveX는 단지 OCX의 이름을 변경한 것에 불가한 것이다. 마이크로소프트에서 공식 발표한 ActiveX라는 것은 기존의 OCX와 별반 차이를 가지고 있지 않다. 다만 인터넷의 표준안에 해당하는 개념적인 의미에서 개명하면서 마이크로소프트의 목표를 우리들에게 알리는 하나가 된 것이다.
2) 컴포넌트 프로그래밍
컴포넌트의 사전적인 의미는 '구성요소'를 이야기한다. 그러면 컴포넌트 프로그래밍이란 무엇일까? 그 답은 아주 간단하다. 여러 가지 프로그래밍의 구성 요소들을 가지고 자기가 원하는 프로그램을 제작하는 방법을 이야기한다. 자동차를 보면 여러 가지 부품들이 모여서 하나의 자동차가 완성되듯이 프로그램의 여러 가지 부품의 역할을 하는 컴포넌트를 이용하여 하나의 프로그램을 제작하는 방법을 가리키는 것이다.
그러면 컴포넌트가 앞으로 프로그래밍에서 중요한 부분이 된다는 것이 이해가 되는가? 현재와 같은 기능이 상당히 많은 프로그램을 제작할 경우 기간과 비용의 여러 가지 문제가 산재해 있기 때문에 프로그래머가 처음부터 모든 것을 제작할 수 없는 실정이다. 이런 문제들을 해결하는 방법이 바로 컴포넌트를 이용하는 프로그래밍인 것이다.
컴포넌트는 서로간의 상호 교류가 가능한 장점을 지니고 있다. 각각 다른 컴포넌트간의 교류와 하나의 컴포넌트 안에 다른 컴포넌트를 포함할 수도 있으며 외부에 있는 다른 컴포넌트와의 교류가 가능하다. 그리고 기능이 변경될 경우에는 사용된 컴포넌트만 변경하면 구축되어져 있는 프로그램에 그 결과가 반영되는 여러 가지 장점을 가진 것이 컴포넌트를 이용한 프로그래밍의 장점인 것이다.
컴포넌트 프로그래밍에 대한 개념적인 이해를 더욱더 돕기 위해서 C++와 같은 객체지향 프로그래밍에 대한 기본 개념과 OOP(Object Oriented Programming)에 대한 전반적인 이해를 다른 참고자료에서 습득하기 바란다.
3) COM이란 무엇인가?
지금까지 우리는 ActiveX라는 개념을 이해하기 위해서 여러 가지 새로운 것들에 대해 알아보았다. 앞서 이야기했듯이 ActiveX는 OLE와 COM의 결합의 형태이다. 이제 우리는 ActiveX를 이해하는 마지막 단계로 COM에 대한 전반적인 개념을 알아보도록 하자. COM이라는 개념 자체로도 상당한 분량을 차지하지만 본 장에서는 비주얼 베이직을 이용한 ActiveX 프로그래밍에 기초가 되는 정도만 알아보도록 하겠다.
① COM(Component Object Model)의 발전
윈도우가 지금까지 사용되기까지에는 여러 가지 프로그래밍의 개념들이 도입이 이루어졌기 때문이다. 윈도우가 처음 만들어졌을 경우만 하여도 UNIX 시스템의 기본 개념인 멀티태스킹이나 다른 여러 가지 프로그래밍에 사용되는 파이프, 소켓, 공유 메모리 등의 개념을 가지지 못했다. 이런 취약점을 해결하기 위해서 마이크로소프트는 새로운 개념들을 제공하기 시작했다. 이에 멀티태스킹과 프로세스간의 통신을 위해 제안된 것들이 바로 DLL, RPC, DDE와 같은 개념이다. UNIX에 비해 부족했던 점들을 위해 따라가는 형식이었지만 초창기의 프로그래밍에 활용되었다.
● DLL(Dynamic Link Library) - 동적 라이브러리를 이용한 프로세스간의 공유를 구현하는 방법으로 UNIX에서 사용하는 공유 라이브러리와 공유 메모리와 같은 기능을 수행한다. 현재의 윈도우를 구성하는 파일들의 상당 부분을 차지하고 있으며 사용자가 직접 제작하여 사용할 수도 있다.
● RPC(Remote Process Communication) - 프로세스간의 원격 호출을 구현하는 방법으로 다른 운영체제에서도 사용되고 있다. 요즘의 분산환경 기술의 발전과 더불어 개념적인 향상을 이루고 있다.
● DDE(Dynamic Data Exchange) - 프로세스간의 데이터를 동적으로 처리를 구현하는 방법으로 기존의 제작되어있는 프로그램의 프로세스와 새로운 응용 프로그램간의 데이터의 교환에 주로 사용되었다.
DDE 프로그래밍을 해본 경험이 있는 사람들은 알 수 있지만 윈도우에서 제공하고 있는 DDE를 통해 데이터의 교환을 수행하면 속도와 데이터의 손실의 문제가 발생한다. 이런 단점이 발생하였기 때문에 COM(Component Object Model)의 방법이 제시되고 사용되었다. DDE와 같은 데이터의 공유가 아닌 COM의 공유개념으로 변화된 것이다. COM을 쉽게 이야기하면 기존의 DDE를 보안하기 위해 발생한 OLE의 통신방법의 모델이다.
② COM의 구조
COM의 일반적인 구조는 Win32 DLL 형식과 EXE 형식으로 구성된다. DLL과 EXE로 구성되기 때문에 특정언어에 국한되는 것이 아닌 언어 독립적이며, 바이너리 형태로 여러 가지 프로그램과 프로그래밍 툴에서 사용할 수 있다. COM의 실제 사용에서는 COM에 포함되어 있는 클래스 메서드를 실행시키기 위한 인터페이스의 사용이 가장 중요한 부분이 된다.
이런 COM은 윈도우 레지스트리에서 서버로 등록되어 외부 프로그램에서 클라이언트로 COM을 불러들여 사용할 수 있는 서버의 기능을 수행하는 것이다.
4) GUID의 고유성
COM이 서로 공유하여 사용할 수 있는 배경에는 고유의 식별자가 있기 때문이다. 이 식별자를 GUID(Globally Unique IDentifier)라고 하며, 128비트의 값으로 형식 라이브러리를 작성할 때 레지스트리의 멤버들을 식별하는데 사용된다. GUID에는 클래스 식별자(CLSID : Class Identifier), 인터페이스 식별자(IID : Interface Identifier)가 있다. 이중 클래스 식별자는 프로그램에서 개체를 구별하거나 생성시키는데 사용되며, 인터페이스 식별자는 해당 개체가 특정 인터페이스를 지원하는지의 여부를 알아내는 역할을 수행한다.
클래스 식별자가 어떻게 구성되는지 알아보기 위해서 윈도우 레지스트리 편집기를 실행하여 보자. 가장 위에 있는 목록인 HKEY_CLASSES_ROOT에서 CLSID항목으로 찾기를 수행하면 자기의 컴퓨터에 등록되어 있는 클래스 식별자를 확인할 수 있다. 그림에서 보듯이 클래스 식별자의 데이터부분에 상당히 복잡한 글자가 적혀있는 것을 확인할 수 있을 것이다.
[그림 1-3] 레지스트리 편집기에서 살펴본 클래스 식별자
클래스 식별자는 이처럼 직접 만들기에는 복잡한 숫자들의 조합으로 되어있다. 이는 비주얼 베이직에서 컴포넌트의 Public 멤버에 대해서 자동으로 생성되며 중복되는 값은 하나도 발생하지 않는다. 또한 프로그램의 제작 시 호환성 여부를 선택하지 않으면 비주얼 베이직에서 타입 라이브러리를 새롭게 제작할 때마다 동일한 프로젝트에 대해서도 새로운 클래스 식별자를 만드니 이를 주의하기 바란다.
5) COM 인터페이스 불변
COM을 제작하는데 주의하여야 하는 또 다른 사항은 인터페이스의 불변성이다. 일반적으로 버전이 올라감으로 새로운 인터페이스가 추가되어 기능의 향상을 이룰 수 있다. 하지만 이런 추가작업에 있어 비주얼 베이직에서 버전 호환성이 설정되어 있는 경우에 기존에 작성되어 있던 메서드나 속성이 변경되면 에러가 발생한다.
) COM 인터페이스
COM에 대한 개념적인 이해를 더하기 위해서 인터페이스에 대해서 알아보자. COM의 개체간 통신에는 기본적으로 두 가지의 인터페이스인 IUnknown과 IDispatch가 사용된다. 각각의 인터페이스는 다음의 역할을 수행한다.
① IUnknown 인터페이스
모든 COM개체는 IUnknown 인터페이스를 반드시 구현해야 한다. IUnknown 인터페이스는 세 가지 기본적인 메서드인 QueryInterface, AddRef, Release를 정의한다.
AddRef와 Release 메서드는 개체의 생성, 소멸을 관리하며 COM 개체 자신의 참조회수를 증가시키거나 감소시키는 기능을 가지고 있다. 참조 회수가 0으로 되면 그 개체는 소멸하게 되는 것이다.
QueryInterface는 특정 인터페이스에 관하여 그 개체에 질의를 던지는 역할을 하고 있다. 사용하고자 하는 컴포넌트의 인터페이스의 정보를 알아낼 수 있다. 이 메서드는 질의된 인터페이스에 대한 식별자를 인자로 받아서 그 인터페이스에 대한 간접포인터를 리턴 값으로 돌려주게 된다. 만약 요청된 인터페이스가 그 개체가 제공하지 않는 것이라면 에러가 발생한다.
② IDispatch 인터페이스
IDispatch 인터페이스는 자동화(Automation)을 지원하기 위해 IUnknown 인터페이스로부터 파생된 인터페이스이다. 메서드나 속성에 해당하는 디스패치 식별자를 알아내어 자동화 컴포넌트에서 제공하는 속성이나 메서드에 접근하는 등의 작업을 할 수 있다. 초기의 바인딩을 사용하여 개체에 접근하고자 할 때에는 IUnknown 인터페이스가 사용되며, 후기의 바인딩을 사용하여 개체에 접근하고자 할 때에는 IDispatch 인터페이스가 사용된다.
1.2 비주얼 베이직에서의 COM
1) 인터페이스 상속
OOP(Object Oriented Programming)의 모든 요소를 만족시키지 못하지만 비주얼 베이직에서도 인터페이스의 상속이 지원된다. 비주얼 베이직에 있는 클래스 모듈을 이용하여 인터페이스와 상속받을 인터페이스 클래스가 작성된다.
우선 표준 EXE로 프로젝트를 만든 다음 새로운 클래스 모듈을 추가하자.
● CComputer 클래스
--------------------------------------------------------------------------------
' --------------------------
' 추상 클래스 CComputer
' --------------------------
Public Sub Hdd()
' 실행 코드 없이 Hdd 메서드만 선언
End Sub
Public Sub Ram()
' 실행 코드 없이 Ram 메서드만 선언
End Sub
Public Sub Cdrom()
' 실행 코드 없이 Cdrom 메서드만 선언
End Sub
--------------------------------------------------------------------------------
CComputer 클래스를 상속받을 CMyComputer.cls(클래스 모듈)를 새롭게 추가하여 다음의 코드를 입력하자.
● CMyComputer 클래스
--------------------------------------------------------------------------------
' --------------------------
' CMyComputer 상속 클래스
' --------------------------
Implements CComputer ' CComputer 클래스를 상속
' Private에 주의
Private Sub CComputer_Ram()
MsgBox "램은 256MB 입니다."
End Sub
Private Sub CComputer_Hdd()
MsgBox "하드디스크는 9GB 입니다."
End Sub
Private Sub CComputer_Cdrom()
MsgBox "시디롬의 배속은 48X 입니다."
End Sub
--------------------------------------------------------------------------------
● MyComputer 폼
앞에서 추가한 두 가지의 클래스를 활용하는 간단한 프로그램을 만들어보자. 우선 추가되어 있는 폼에 다음과 같이 3가지이 버튼을 추가하여 각각의 이름을 cmdCdrom, cmdHdd, cmdRam으로 변경하자. 간단한 폼 디자인이 완료되면 다음의 코드를 정확하게 입력하도록 하자.
[그림 1-5] MyComputer 폼 디자인
--------------------------------------------------------------------------------
Dim Com As New CComputer
Dim myCom As New CMyComputer
Private Sub cmdCdrom_Click()
Com.Cdrom
End Sub
Private Sub cmdHdd_Click()
Com.Hdd
End Sub
Private Sub cmdRam_Click()
Com.Ram
End Sub
Private Sub Form_Load()
Set Com = myCom
End Sub
--------------------------------------------------------------------------------
우선 앞서 정의한 클래스들을 참조하는 변수를 소스의 첫 부분에서 선언한다. CComputer 클래스를 Com 변수에, CMyComputer 클래스를 myCom 변수로 선언한다.
--------------------------------------------------------------------------------
Dim Com As New CComputer
Dim myCom As New CMyComputer
--------------------------------------------------------------------------------
이렇게 선언된 클래스는 앞서 CMyComputer 클래스에서도 알아보았듯이 CComputer가 하나의 인터페이스를 제공하고, CMyComputer는 CComputer를 상속받아서 해당하는 메서드에 기능을 부과하였다. 위의 예는 상속이 이루어지는 과정을 알기 위한 구현이므로 선조 클래스는 추상 클래스로 정의되고 실제 상속받은 클래스에서 구현작업이 이루어진다. 그렇기 때문에 상속받은 클래스를 기존의 선조 클래스를 참조하는 변수에 할당해야 정상적인 메서드의 실행이 가능하다. 이 부분이 폼이 로드될 때 이루어지는 다음의 부분이다.
--------------------------------------------------------------------------------
Private Sub Form_Load()
Set Com = myCom
End Sub
--------------------------------------------------------------------------------
이렇게 Com 변수에 새로운 객체가 할당되면 추상 클래스에서 정의된 메서드들을 각각의 버튼을 클릭할 때마다 적합한 메서드의 호출을 하면 상속받은 클래스의 메서드에서 정의한 결과값이 출력된다.
--------------------------------------------------------------------------------
Private Sub cmdCdrom_Click()
Com.Cdrom
End Sub
--------------------------------------------------------------------------------
프로그램의 실행 결과는 다음의 그림과 같다. 각각의 버튼마다 앞서 정의한 다른 메시지 박스가 나타나는 것을 확인할 수 있을 것이다.
[그림 1-6] MyComputer 실행결과