COM은?
-.컴포넌트 객체 모델 (Component Object Model)의 약자이다. COM은 컴파일과 링크가 되어 있는 바이너리코드로 객체지향 프로그래밍이 가능하게 해주는 윈도우의 기능 중에 하나이다.
-."인터페이스라는 미리 정의된 루틴들을 통해 객체들 사이의 상호작용을 가능하게 해주는 객체기반의 바이너리 표준"라고 MS에서 정의 해 놓았다. 이 말은 객체(Application도 포함)들 사이에 인터페이스가 있는데, 이 인터페이스를 통해 객체간의 공유가 가능하다. 분산환경(Corba, COM) 프로그래밍에는 각각 인터페이스를 정의 하는 표준적인 룰과 그를 응용한 룰(타입 라이브러리 등)이 있다.
-.인터페이스가 상속과 다형성 등의 할 수 있으므로 바이너리 코드기반으로 객체지향 프로그래밍이 가능하다.
-.COM 객체는 위에서 말했듯이 바이너리코드 이다. 이것을 프로세스 단위로 실행 시켜 주어야 한다. 그 프로세스 단위 안에 COM 객체는 1개 이상 있을 수 있다. 또 그 프로세스는 DLL (in-process), EXE (out-of-process) 형태로 만들어질 수 있다.
-.이상 위의 내용을 정리하면 "COM은 인터페이스라는 약속을 정해놓고 특정 프로세스단위 내에 존재하는 클래스를 지금 개발자가 만들고 있는 Application의 인스턴스로 갖다 쓰자." 라고 이해 하자. 추가로 "그 인터페이스를 상속 받아서 다른 COM Class도 만들 수 있다." 라고 이해 하자.
-. 위의 내용을 그림으로 그린 것이 [그림1] 이다.
[그림1] COM의 기본구조. |
[그림1] 같이 COM객체는 COM 서버 내에 존재해야 하고, 각각의 COM 객체는 1개 이상의 인터페이스를 통해 Client Application 에게 COM객체 자신의 기능을 노출시킨다. Client Application은 노출된 인터페이스의 GUID (= IID)를 가지고 해당 COM 객체에 접근할 수 있는 것이다. COM 객체 자체가 어떤 일을 하고 그에 따른 함수를 노출하기만 하면(인터페이스를 통해서 ) Client Application 에서는 COM 객체가 어떻게 구현되어있는지 알지 않아도 COM 객체의 기능을 사용할 수 있다. 그렇다면 인터페이스를 이해할 필요가 있을 것이다. 아래에 인터페이스의 기본원리와 어떤 규칙을 따르는지 알아보자.
Interface는?
-.인터페이스는 COM 객체를 외부에서 사용할 수 있도록 하는 매개체 역활을 한다.
-.인터페이스는 함수들의 선언으로만 구성되어있고 COM 객체에서 인터페이스의 함수를 구현해 준다.
-.인터페이스를 서로를 식별하기 위해 GUID 타입의 128bit의 유일한 값을 가진다.
-.인터페이스는 언어 독립적으로 제작가능하고 인터페이스 내의 함수들은 포인터를 통해서 접근할 수 있다.
COM 서버의 형태는?
-. 위에서 COM객체는 COM 서버 내에 존재해야 한다고 설명했는데, COM 서버의 형태에 따란 Client Application에 바인딩이 달리 된다. [그림2]는 이것을 설명하는 그림이다.
[그림2-1 ] In-Process 의 형태 |
-. [그림2-1]의 In-Process는 COM 서버가 *.DLL로 제작되어있을 경우 이다. DLL로 되어있는 COM 객체에 Client Application이 접근하면 Client Application의 프로세스내에 COM 서버의 인스턴스가 바인딩 된다. 주로 ActiveX 컨트롤이 이런 형태이다. 익스플로어에서 COM서버내의 COM 객체를 호출할 때 익스플로어 프로세스내에 바인딩 되는 것이다. 참고로 ActiveX 컨트롤의 OCX 파일은 구조적으로 DLL과 동일하다.
[그림2-2] Out-Of-Process 의 형태 |
-. [그림2-2]의 Out-of-process는 COM 서버가 *.EXE로 제작되어있을 경우 이다. EXE로 되어있는 COM 객체에 Client Application이 접근하면 COM 서버는 자체적으로 프로세스를 생성된다. 내부적으로 Client Application에서는 Proxy로 COM서버의 Stub으로 연결된 구조로 In-process 보다 복잡하지만 개발자는 별다른 신경을 쓰지않아도 In-Process와 동일하게 작성하면 된다. 단지 Client Application내에 COM 서버가 인스턴스화 되는지 아니면 다른 프로세스로 생성 되는지 가 중요하다. 그래서 여러 Client Application에서 하나의 COM 객체를 호출할 때 Out-of-Process의 경우에는 호출한 Client Application의 수 만큼 COM 서버 프로세스가 생성되고, In-Process의 경우에는 호출한 Client Application의 수 만큼 COM 서버 인스턴스가 생성되는 것이다.
-. 그 외로 다른 컴퓨터의 COM서버의 COM객체를 호출하는 구조의 Remote COM 이 있다. 하지만 이 문서에는 따로 언급을 하지 않겠다.
COM의 확장이란?
-.MS나 그 외 여러 문서를 살펴보면 OLE, ActiveX, COM 등의 정의를 분명하게 하지않아서 혼동의 여지가 있다. 어떤 곳에서는 COM에서 OLE한 면이 없으면 ActiveX 이라고도 하고 OLE3.0에서 부터 COM를 ActiveX라고 부르기도 하지만 모두 틀린 말은 아니다.
-.그래도 계속 혼동스럽 다면 기본 COM에 추가된 기능, 확장된 기능 이라고 생각하자. (단어에 연연하지 말자는 뜻 이다.)
•.Automation Server (독립실행 가능한 Application(EXE)이나 DLL이 프로그래밍을 할수 있도록 객체(COM객체)를 다른 애플리케이션에 제공하는것)
•.Automation Control (위에서 설명한 Automation Sever에서 제공된 COM 객체를 이용하는 Client Application)
•.ActiveX Control(프로그래밍의 언어에 상관 없이 일반 컴포넌트처럼 사용할 수 있고 웹에서도 사용 가능한 객체)
•.Type Library (COM 서버내의 COM객체에 대한 정보를 Client Application에서 사용 가능하도록 하는 바이너리 코드. 표준적인 방식으로 저장되므로, 프로그래밍의 언어와 상관없이 읽을 수 있다. 또 COM 서버파일(DLL)등에 함께 저장될 수 있고 따로 저장해서 링크해서 사용할 수 있다. )
-.그 외 ActiveX Documemt , DCOM, MTS 등은 COM를 기초로 확장된 모습이다.
실습 (간단한 COM서버(DLL=In-Process)와 Client Application 만들기. Delphi5 Ent 기준)
-. COM 서버와 COM 객체 만들기.
1. 모든 프로젝트를 종료하고 File|New 해서 New Items 대화상자에서 --> ActiveX 탭 --> ActiveX Library 를 선택하고 [ OK ]버튼을 클릭한다. 여기서 추가한 ActiveX Library는 일반 DLL과 같은 파일을 생성하지만 COM객체를 레지스트리에 등록하고 해제하고 COM 서버 내의 특정 COM객체를 얻을 수 있는 함수를 Export 한다.
2.File|Save 해서 프로젝트명을 COMSrv.dpr로 저장한다. 다시 File|New --> ActiveX 탭 --> COM Object 를 선택하고 [ OK ]버튼을 클릭한다. CoClassName 을 COMObject로 하고 나머지 옵션은 기본사항으로 하고 [ OK ]버튼을 클릭한다.
옵션 설명
그림3-1처럼 STA의 경우에는 COM 객체를 생성한 Thread 만이 해당 COM 객체를 접근할 수 있다. 다른 Thread에서 생성한 COM객체는 접근할 수 없다. 그림3-2 처럼 MTA의 경우에는 COM 객체를 생성한 Thread 말고도 다른 쓰레드 에서도 COM객체에 접근할 수 있다. 개발자가 프로젝트가 쓰레드를 사용하지 않는 다면, STA로 만들고 별로 신경 쓰지 않아도 된다. |
3. 타입 라이브러리에서 ICOMObject (COM 객체의 인터페이스)에 팝업메뉴을 띄워서 method를 새로 추가한다.
4. Method 이름을 "callDialog" 로 변경하고 오른쪽 파라메타 탭에서 파라메타를 1개 추가 한다. Name = uName , Type = BSTR
5. Method 를 한 개 더 추가해 이름을 "getNowTime" 로 변경하고 오른쪽 파라메타를 1개 추가한다. Name = nowtime, Type = BSTR* , Modifier = [out, retval] nowTime 파라메타는 호출한 Application으로 리턴할 수 있다.
6. Refresh 버튼을 눌러서 현재 상태를 적용한다.
-. 참고로 기본 리턴값인 HResult 는 COM서버의 내장된 객체의 메소드를 호출이 성공, 실패의 리턴값을 돌려준다.
7. File|SaveAll 해서 Unit1.pas를 ComSrvImpl.pas 로 저장한다. 그리고 다음과 같이 소스코드를 작성한다.
unit ComSrvImpl; interface uses Windows, ActiveX, Classes, ComObj, COMServer_inpro_TLB, StdVcl; type TMyCOMObject = class(TTypedComObject, IMyCOMObject) protected function callDialog(const uName: WideString): HResult; stdcall; function getNowTime(out nowTime: WideString): HResult; stdcall; end; implementation uses ComServ, Dialogs, SysUtils; function TMyCOMObject.callDialog(const uName: WideString): HResult; begin ShowMessage('이름: ' + uName +#13#10 + 'COM 서버에서실행된 대화상자'); end; function TMyCOMObject.getNowTime(out nowTime: WideString): HResult; begin nowTime := TimeToStr(Now); end; initialization TTypedComObjectFactory.Create(ComServer, TMyCOMObject, Class_MyCOMObject, ciMultiInstance, tmApartment); //COM Object Factory 에 인스턴스 등록 end. |
-. Client Application 만들기
[그림 4] Client Application 폼
1. 그림4 처럼 폼을 디자인 한다. 그리고 아래와 같이 소스코드를 작성한다.
uses COMSrv_TLB, COMObj; {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var COMObj: ICOMObject; strTime: wideString; begin COMObj := CoCOMObject.Create; oleCheck(COMObj.callDialog(Edit1.Text)); oleCheck(COMObj.getNowTime(strTime)); Label2.Caption := '호출된 시간: ' + strTime end; |
2. 테스트.
-. 일반적인 DLL 파일은 실행파일과 같은 디렉토리나 Windows\System\ 디렉토리에 위치하면 되지만 COM 서버 DLL은 위치에 상관없도록 레지스트리에 등록해서 사용한다.
-. 레지스트리에 등록되는 내용은 ClassID (CLASS_), Type Libray ID (LibID_), InterfaceID(IID_) 등에 DLL 파일의 위치와 ProID 등이 저장된다.
-. 등록하는 방법은 COMSrv.dpr프로젝트를 Open 하고 RUN 메뉴에 Register ActiveX Server를 선택하면 된다. Out-Of-Process 경우 RUN만 한다.
-. Client Application을 실행하고 [COM 객체의 함수 호출] 버튼을 클릭한다. 그러면 메시지 창과 함께 현재시간이 Label1에 출력되면 COM 서버를 레지스트리 에서 위치를 얻고 난 후에 해당 인터펭이스를 통해 COM서버를 Client Application 내에 바인딩 한다.
Automation 서버 / Client 만들기
- Automation 서버 만들기 ( Out-Of-Process )
-.델파이에서는 자동화 컨트롤러가 자동화 서버를 호출하는 3가지방법을 제공한다. |
[그림 5 ] Automation 서버의 폼
1. 그림5 처럼 File|New Application 해서 폼안에 TShape 컴포넌트를 한 개 추가해서 폼을 디자인한다. File|SaveAll해서 프로젝트이름 AutoSrv.dpr 로 Unit1.pas --> SrvFrm.pas 로 한다.
2. File|New 해서 ActiveX 탭 --> Automation Object 를 선택하고 [ OK ]버튼을 클릭한다. CoClassName을 AutoTest 로 하고 나머지는 기본값으로하고 [ OK ] 버튼을 클릭한다.
3. Type Library 에서 IAutoTest 인터페이스를 클릭하고, setShapeType 메소드를 추가한다. 파라메타 탭에서 paramater name = sType , Type = int 로 파라메타 한개를 추가한다.
5. File Save All 해서 COM 객체 유닛을 AutoImpl.pas로 저장한다.
6. AutoImpl.pas 파일에 선언되어있는 setShapeType 메소드를 구현한다.
uses ComServ,SrvFrm, extCtrls ; procedure TAutoTest.setShapeType(sType: SYSINT); begin Form1.Shape1.Shape := TShapeType(sType); end; |
7. 전체를 다시 저장하고, COM 서버를 레지스트리에 등록한다. Out-Of-Process(.Exe)는 실행만 해도 레지스트리에 자동 등록 된다.
- Automation Control 만들기
[그림6 ] Automation Control의 폼
1. 그림6 처럼 File | New Application 해서 폼안에 TEdit 한개와 TUpDown 1개 Associcate 속성을 Edit1 으로 한다. 그리고 TButton 컴포넌트 4개를 추가하고 위에서부터 vTable호출 (Button1) ~ 연결해제 (Button4) 로 캡션을 입력한다.
2. 소스코드를 아래와 같이 작성한다.
uses AutoServer_TLB, COMObj; {$R *.DFM} var AutoTest: IAutoTest; // interface 이용 AutoTestDisp: IAutoTestDisp; //dispinterface 이용 vAutoTest: Variant; // variant 이용 procedure TForm1.Button1Click(Sender: TObject); // Interface(Vtable)을 이용해서 COM 객체 생성 begin AutoTest := CoAutoTest.Create; AutoTest.setShapeType(UpDown1.Position); end; procedure TForm1.Button2Click(Sender: TObject); // Dispatch Interface를 이용해서 COM 객체 생성 begin AutoTestDisp := CreateComObject(Class_AutoTest) as IAutoTestDisp; AutoTestDisp.setShapeType(UpDown1.Position); end; procedure TForm1.Button3Click(Sender: TObject); // Variant 변수에 Program ID 값을 넣고 COM 객체 생성 begin vAutoTest := CreateOleObject('AutoServer.AutoTest'); vAutoTest.setShapeType(UpDown1.Position); end; procedure TForm1.Button4Click(Sender: TObject); begin AutoTest := nil; // Pointer 변수 해제 AutoTestDisp := nil; vAutoTest := Unassigned; //Variant 변수 해제 end; |
3. 모두 저장하고 Automation Control (Client Application ) 을 실행한다. UpDown 컴포넌트의 값을 0 ~5 사이에서 변경하면서 테스트 해보자.
Excel 97, 2000 을 Control 하는 Automation Controler 만들기
-. MS사에서 만든 많은 제품들이 COM 객체로써 외부에서 Control 할 수 있도록 만들어져 있다. 이번 실습은 Excel 97, 2000 을 간단히 Control 할 수 있도록 COM Controler 를 만들어 본다.
[그림7 ] Excel Controler 폼
- . 델파이 5 에서 Server 탭에 MS의 Office 제품군을 Control 할 수 있도록 컴포넌트를 만들어 놓았는데, 기본적으로 Interface (VTable) 방식으로 접근할수 있다. 물론 다른 방식도 가능하지만 위에서 설명했듯이 Automation 서버를 Control하는 Client Application 을 델파이에서 만들때에는 Interface 방식의 성능이 가장 우수하다.
1. File|New Application 해서 그림7과 같이 TMemo 컴포넌트 1개와 TButton 3개, Server탭에서 TExcelApplication, TExcelWorkSheet, TExcelWorkBook 1개를 폼안에 추가한다.
2. 아래와 같이 소스코드를 작성한다.
var vExcel: Variant; implementation uses COMObj; procedure TForm1.Button1Click(Sender: TObject); Var i: Integer; begin varExcel := CreateOleObject('Excel.Application'); varExcel.workbooks.Add; for i := 0 to Memo1.Lines.Count-1 do varExcel.workbooks[1].worksheets[1].Cells[i+1, 1] := Memo1.Lines[i]; varExcel.Visible := true; end; procedure TForm1.Button2Click(Sender: TObject); var i: Integer; begin ExcelApplication1.Connect; ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Item[1]); ExcelWorkSheet1.ConnectTo(ExcelWorkBook1.Sheets[1] as _WorkSheet); with ExcelWorkSheet1 do for i := 0 to Memo1.Lines.Count-1 do Cells.Item[i+1, 1] := Memo1.Lines[i]; ExcelApplication1.Visible[0] := True; end; procedure TForm1.Button4Click(Sender: TObject); begin if not varIsEmpty(varExcel) then varExcel.quit; if not varIsEmpty(ExcelApplication1.Application) then begin ExcelApplication1.Disconnect; ExcelApplication1.Quit; end; end; |
3. 실행 하고 버튼을 눌러본다. 위의 예제는 PC에 Excel 프로그램이 설치되어 있는 경우에만 제대로 동작 한다.
-이외에도 Delphi에서는Excel의 차트등 거의 모든 객체를 Control 할수 있다. Excel .vbs 파일을 생성해서 실행할수도 있다
아래 소스코드는 Excel 내에 특정 매크로를 생성해서 실행시키는 예제 이다.
procedure TForm1.Button1Click(Sender: TObject); var str: String; vModule: OleVariant; begin str := 'Sub Macro()' + #13#10 + 'Dim X, Y' + #13#10 + 'Dim X_END, Y_END' + #13#10 + 'Dim Min, Max' + #13#10 + 'If Cells(1, 2) = "N" Then'+ #13#10 + 'X_END = 21'+ #13#10 + 'Else'+ #13#10 + 'X_END = 25'+ #13#10 + 'End If'+ #13#10#13#10+ 'Y_END = Cells(1, 3) + 4'+ #13#10#13#10+ 'For Y = 5 To Y_END'+ #13#10 + ' For X = 2 To X_END'+ #13#10 + ' Min = Cells(3, X)'+ #13#10 + ' Max = Cells(4, X)'+ #13#10 + ' Cur = Cells(Y, X)'+ #13#10#13#10+ ' Cells(Y, X).Font.ColorIndex = 2'+ #13#10 + ' Cells(Y, X).Font.FontStyle = "굵게"'+ #13#10#13#10+ ' If (Min <= Cur) And (Cur <= Max) Then'+ #13#10 + ' Cells(Y, X).Interior.ColorIndex = 5'+ #13#10 + ' Else'+ #13#10 + ' Cells(Y, X).Interior.ColorIndex = 3'+ #13#10 + ' End If'+ #13#10 + ' Next X' + #13#10 + ' Next Y' + #13#10 + 'End Sub'; vModule := ExcelWorkBook1.VBProject.VBComponents.Add(1); vModule.CodeModule.AddFromString(str); ExcelApplication1.Run('Macro'); end; |
'핫이슈' 카테고리의 다른 글
★냉동인간★ 부활시킬 단초 발견!!! (0) | 2011.07.09 |
---|---|
고지전 예고편!! (0) | 2011.07.09 |
나도가수다!! 도플겡어들..ㅋ (0) | 2011.07.08 |
연금복권 인터넷구매 방법!!!! (0) | 2011.07.08 |
옵티머스3d 상세스펙 (0) | 2011.07.08 |