'COM'에 해당되는 글 2건

  1. 2009.09.02 CQ Workflow Viewer - 1 Day.
  2. 2009.05.13 .NET 2.0(C#) 에서 Active X 컨트롤 만들기. (14)

이 작업에서 기술적으로 풀어야 되는 최고의 숙제는 COM 개체를 CPP 코드를 이용하여 붙이는 작업이다.
그렇다고 COM 관련 API를 직접 붙여 만들기는 귀찮기도 하고, 기술적으로 능력이 딸리기 때문에, 힘들고, 대신 Visual Studio의 기능을 십분활용하는 방법으로 진행한다.

이 중 MFC 기반으로 만드는 응용 프로그램인 경우, 전체 프로그램의 사이즈는 커지지만,
그래도 편하게 작성할 수 있는 장점은 확실히 이용가능하다고 본다.
여기서 작업 결과물은 ActiveX로 나와야 겠지만, 먼저 COM 연결과 같은 테스트에 가까운 작업 부분에 대해서는 MFC 기반 응용 프로그램으로 만들어 직접 테스트와 디버깅을 하여 결과물을 만든 후 그 내용을 ActiveX로 붙이는 것이 좋을 것 같다.
이를 위해 하는 작업은 COM의 TypeLib를 사용하여 ProxyClass를 자동으로 생성하는 방법을 적용한다.
TypeLib에서 ProxyClass를 만드는 방법은 Visual Studio 버전에 따라 틀리지만, 여기서는 모든 작업을 Visual Studio 2005로 할 것이며, 이 방법을 중심으로 펼칠 예정이다.

Proxy Class 만들기.

  • 프로젝트에서 컨텍스트 메뉴를 띄우고 추가를 선택한다.
  • 추가 아래에서 클래스를 선택한다.
  • 클래스 추가라는 제목의 마법사가 뜨면, 그 중 MFC 항목을 선택한 후 템플릿 중 TypeLib의 MFC 클래스를 선택한다.
  • 사용 가능한 형식 라이브러리에서 원하는 COM을 선택한다. 여기서는 ClearQuest OleServer를 선택한다.
  • 그러면 이 COM에 딸린 각종 인터페이스들이 나열되는데, 그 중 필요한 인터페이스를 선택한다. 여기서는 CQ Workflow의 작업에 필요한 IOAdEntityDef, IOAdEntityDefs, IOAdSession 세가지가 필요하다. 그래서 그 클래스를 추가한다.
  • 그러면 프로젝트의 헤더 파일 목록에 위의 세가지에 대한 프락시 클래스 정의 내용이 담긴 헤더 파일(*.h) 파일이 추가된다.

 

일단 위의 헤더 파일이 만들어졌으면 1차적으로 완성된 것이다.

 

Proxy Class 활용하기.

COM에서 인터페이스를 이용하여 사용하려면, COM에 대한 인스턴스가 필요하다. 지금 위의 작업까지 된 부분은 운영체제 내 등록되어 있는 COM 자체의 설정 값들을 읽어온 것이 전부이다. 이 설정 값만으로는 실제 메모리 존재하는 것이 아니다. 그렇다고 단순하게 Proxy Class를 new 해서 만드는 것은 사실 아무 의미 없다. Proxy Class를 new해서 만드는 것 만큼이나, COM 자체에 대한 인스턴스를 만드는 것이 같이 병행 되어야 하고, 인스턴스화 된 COM 개체를 new해서 만드는 Proxy Class와 연결하면 되는 것이다. 이제 이 COM을 메모리에 올리고 new 해서 만드는 Proxy Class와 연결하는 작업을 수행할 것이다.

ClearQuest OleServer를 사용하려면, 최초 Session 이 필요하다. 즉 이 Session에 대한 인스턴스가 있다면, 이 인스턴스를 통해서 각종 하위 내용들을 끄집어 낼 수 있다. 즉 시작점 같은 의미를 하는 부분을 먼저 인스턴스화 하는 것이 핵심인 것이다.  그래서 다음과 같은 순서로 실행하면 된다.

먼저 Proxy Class를 new 해준다. 여기서는 시작 인스턴스로 사용할 IOAdSession 이라는 것을 먼저 시도하게 된다.
COAdSession *pSession = new COAdSession();

이제 만들어진 ProxyClass에 COM 인스턴스를 싣는다. 이 Proxy Class들은 모두 COleDispatchDriver를 상속받는데, 그 상위 클래스에 정의된 CreateDispatch 함수를 실행하면 된다. 이 때 Program ID 혹은 CLSID를 알아야 하는데, 이 중 제일 접근하기 쉬운 Program ID로 정의해서 넣는다.
pSession->CreateDispatch(_T(“CLEARQUEST.SESSION”));

이제 인터페이스에 정의된 매소드를 실행해 본다.
pSession->UserLogon(_T(“admin”), _T(“”),_T(“udb1”), 1L, _T(“7.0.0”));

 

정리를 하자면, 일단 TypeLib를 통해 ProxyClass를 만든다. 이 작업은 직접 만들 수 있지만, 귀찮으니, MFC에서 제공하는 자동화 도구를 사용해서 만든다. 그리고 난뒤, Proxy Class의 인스턴스를 만들고, 그 안에서 다시 COM 자체의 인터페이스를 생성한 뒤, 실제로 사용한다는 것이다.

신고
Posted by 하인도

옛날 자료들, .NET 1.0 시절에서 부터 내려온 자료들을 근간으로 하나씩 하나씩 체크하면서 진행했습니다. 그런데 생각보다 의외의 요소들이 너무 많아 헷갈려 포기 할 즈음 간신히 성공했습니다.

성공했던 내용을 기반으로 지금까지 제가 판단했던 각종 정보들을 정리해보도록 하겠습니다.
현재 이 작업은 .NET 2.0 기반으로 Visual Studio 2005를 기준으로 작성하고 테스트 되었습니다.
(아직 Visual Studio 2008에서는 해보지는 않았지만… 잘 되리라 그냥 막연히 짐작합니다. 2003 버전은,
외국에 많은 사례들이 있으므로 한번 찬찬히 보시면 금방 하실 수 있을 것입니다. )
그리고 구현 언어는 C# 입니다.

1. 프로젝트 생성

먼저 프로젝트 생성입니다. 사실 대부분의 다른 사이트들의 예제를 보게 되면 Class Library 기반으로 시작하게 끔 유도하곤 합니다. 그런데, 생각보다 설정하거나 구성해야 되는 부분이 너무 많아 무언가 노가다 하는 기분이 들더군요. 그러다가 찾은 프로젝트 형식이 바로 “Windows Control Library”  였습니다.

이 프로젝트를 생성하려면 File –> New –> Project 라는 메뉴에 들어가시면 아래와 같은 화면이 뜨는데 그 중, Windows Control Library를 선택하시면 됩니다.

2. 클래스 설정.

ActiveX로 보여줄 컨트롤에 해당하는 클래스를 열도록 합니다. 보통 기본적으로 UserControl1 이라는 이름의 클래스가 만들어지는데, 바로 이 부분을 수정하게 될 것입니다. 더블 클릭하면 디자인 모드로 넘어가므로, 코드 보기로 들어가 주시기 바랍니다.

 

2.1 using 추가하기

맨처음 해주셔야 할 작업은 using을 걸어주시는 작업이 됩니다. Active X 설정을 위해 약간의 Assembly 및 COM 처리를 해야 하는 부분이 있기 때문입니다. using 해야 할 항목은 다음과 같습니다.

using System.Runtime.InteropServices; // 동적으로 컴파일러 관련 옵션을 업데이트하는 값을 넣기 위한 부분
using System.Reflection; // 현재 어셈블리 정보를 동적으로 가져오기 위한 부분
using Microsoft.Win32; // Registry에 정보를 업데이트 하기 위한 부분

일단 위의 3가지만 들어가면 지금 부터 업데이트 하는 부분은 큰 문제 없이 들어갈 것입니다.

2.2 ActiveX로 노출될 컨트롤 Class 옵션 적용

다음은 Class에 옵션을 설정하는 작업입니다.

먼저 제일 처음에 보이는 클래스 위쪽에 다음 3가지를 추가하여 주시기 바랍니다. 물론 프로젝트의 속성 값을 수정하여 대입되는 값들도 있기는 하지만, 혹시나 모르니 그냥 넣어주시면 좋을 듯 싶습니다.

[Guid("20F0F02D-044C-4013-AFAE-F2241D95FDA3")]
[ComVisible(true)]
[ProgId("HindNo1.TestAX")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public partial class UserControl1 : UserControl
{
      ………

대충 보시면 아시겠지만, [ ] 안에 들어가는 값이 바로 코드에 직접 박아서 명시적으로 설정하는 작업입니다.

맨 먼저 Guid 부분은 이 컨트롤의 고유한 ID 입니다. CLSID 같은 것으로 Active X 마다 각자 고유한 ID를 갖는데, 바로 그 ID를 의미합니다. 프로젝트 옵션에 있는 Assembly 옵션에도 이 비스무리한 값이 있는 것 같지만, 일단 저렇게 명시적으로 해주세요.( 전 VS 잘 몰라서, 장담드리기가 힘들어 가급적 그냥 제가 말씀 드린 방법대로 해보세요. )

두 번째에 있는 ComVisible 부분은 이 Control을 COM으로 노출 시키는 작업을 할 것인지 말 것인지를 결정하는 부분입니다. ActiveX도 어찌보면 COM의 일종이기 때문에, 반드시 COM 노출이 되어줘야 합니다. 이 역시 Project 속성의 Assembly 옵션에서 변경할 수 있긴 합니다.

세 번째 ProId 부분은 보통 VB 스크립트에서 쓰는 CreateObject(“xxxx.xxx”)의 xxxx.xxx 부분을 의미합니다. 일단 알기 쉽게 쓰는 것도 중요하지만, 가급적 특이하게 적어주시는 것이 좋습니다. Guid야 겹칠 일이 거의 전무하지만, 이 이름은 혹여나 겹칠 수 있으니깐, 조심조심 쓰시기 바랍니다. 문장이 길다 싶으면 “.” 으로 구분하여 표시해주시면 됩니다.

네 번째 ClassInterface(….) 부분은, COM(즉 ActiveX)가 외부에 노출되는 각종 Interface의 유형을 결정하는 부분입니다. 자세한 원리는 저도 잘 모르겠구요, COM에 대한 기초적인 지식이 필요할 것 같습니다. 일단 AutoDual로 하면 대부분의 인터페이스를 커버한다고 하더군요. 뭐 보안이나 성능상의 문제로 제한적으로 설정할 수 있는데, 이 역시 천천히 자습하시거나 내용을 찾아 설정해주시면 좋겠습니다.

2.3 컨트롤 등록 시 자동으로 실행되어야 할 사항

일단 위의 설명을 쭉 읽어보시고 만일 전혀 이해가 안되거나 도리어 헷갈린다 싶으면 위의 내용을 그대로 쓰세요. 그리고 난뒤에, Guid 와 ProgId 안의 값만 적절하게 변경해주시면 됩니다. (Guid는 Guid를 새로 생성해서 새롭게 넣으시고, ProgId는 겹치지 않게 적당한 문자열을 나열해주시면 됩니다. – 영어, 숫자, 마침표로만 – )

이제 이 Control이 등록될 때 몇 가지 Registry에 등록해야 되는데, 이 작업을 수행하기 위한 함수 두 개를 추가해 주시기 바랍니다.

///    <summary>
///    Register the class as a    control    and    set    it's CodeBase entry
///    </summary>
///    <param name="key">The registry key of the control</param>
[ComRegisterFunction()]
public static void RegisterClass(string key)
{
    // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
    StringBuilder sb = new StringBuilder(key);
    sb.Replace(@"HKEY_CLASSES_ROOT\", "");

    // Open the CLSID\{guid} key for write access
    RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

    // And create    the    'Control' key -    this allows    it to show up in
    // the ActiveX control container
    RegistryKey ctrl = k.CreateSubKey("Control");
    ctrl.Close();

    // Next create the CodeBase entry    - needed if    not    string named and GACced.
    RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
    inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
    inprocServer32.Close();

    // Finally close the main    key
    k.Close();
    MessageBox.Show(key + " 's registered");
}

///    <summary>
///    Called to unregister the control
///    </summary>
///    <param name="key">Tke registry key</param>
[ComUnregisterFunction()]
public static void UnregisterClass(string key)
{
    StringBuilder sb = new StringBuilder(key);
    sb.Replace(@"HKEY_CLASSES_ROOT\", "");

    // Open    HKCR\CLSID\{guid} for write    access
    RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

    // Delete the 'Control'    key, but don't throw an    exception if it    does not exist
    k.DeleteSubKey("Control", false);

    // Next    open up    InprocServer32
    RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);

    // And delete the CodeBase key,    again not throwing if missing
    k.DeleteSubKey("CodeBase", false);

    // Finally close the main key
    k.Close();
}

각 함수는 이 컨트롤을 해당 PC내에 등록할 때 자동으로 불려지는 함수입니다. RegisterClass(..) 함수는 등록될 때, UnregisterClass(..) 함수는 등록을 해제 될 때 자동으로 불리며, 각 함수의 내용은 마치 Active X처럼 필수적인 정보들을 Registry에 적어 추가하게 됩니다.

2.4 프로젝트 설정

자 마지막으로 설정해야 하는 부분은 프로젝트 설정 부분입니다.

솔루션 탐색기에서 해당 프로젝트에서 오른쪽 클릭을 하셔서 Context Menu를 띄우세요. 그리고 “속성”에 들어가시기 바랍니다.

속성 창에 들어가서 제일 먼저 응용 프로그램 탭을 선택한 뒤에 “어셈블리 정보를 클릭합니다.”

 

어셈블리 정보 창이 떴으면 맨 아래쪽에 있는 어셈블리를 COM에 노출을 선택해주시기 바랍니다.
그리고 어셈블리 버전 안에 "*" 표시가 있으면 반드시 지워주시기 바랍니다!!!!! - ( 가장 중요. 만일 * 가 들어가 있으면 계속 버전이 자동 갱신 되기 때문에, 알 수 없는 오류를 계속 뱉어 낼 수 있습니다. )

Update ( for pjyoung 님 ) - 2010.09.13.

현재 포스트 내용만으로는 regasm 으로 이 Active X 에 등록하려는데 문제가 있더군요.
만일 위의 내용만으로 등록하려고 하면 아래의 메시지가 뜹니다.

D:\MyData\Documents\Visual Studio 2010\Projects\ActiveXTest\ActiveXTest\bin\Debu
g>C:\windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /codebase ActiveXTest
.dll
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.4927
Copyright (C) Microsoft Corporation 1998-2004.  All rights reserved.

RegAsm : warning RA0000 : Registering an unsigned assembly with /codebase can ca
use your assembly to interfere with other applications that may be installed on
the same computer. The /codebase switch is intended to be used only with signed
assemblies. Please give your assembly a strong name and re-register it.
RegAsm : error RA0000 : An error occurred while writing the registration informa
tion to the registry. You must have administrative credentials to perform this t
ask.  Contact your system administrator for assistance

만일 한글판이면 한글판 나름 메시지가 뜨겟는데요.. 일단, 위의 내용을 간단히 언급하자면, 2가지 오류가 있는 것입니다. 하나는 일종의 경고로써, (warning RA0000). 만든 ActiveX 내에 강력한 이름의 서명이 없다는 것입니다. 이게 없다면 뭐 다른 컴퓨터에서 안된다는 의미 같은데.. 경고라고 할지라도, 일단 해결해야 겠죠. 두번째는 Windows Vista, 7 에서만 발생하는 오류인데.. 도스 창을 띄울때 관리자 권한으로 해서 넣으라는 의미입니다.
아래의 내용은 그 부분을 해결하기 위한 내용을 정리햇습니다.

  1. codebase로 등록하려면, 최소한 dll 내에 인증서가 들어가야 된다는 것입니다. 물론 파는 제품이라면, 상업용 인증서가 들어가야 겠지만, 테스트용도라면, 개인 인증서를 직접 만들어 넣을 수 있습니다.
    인증서를 넣는 방법은 아래와 같습니다.
    1. 프로젝트를 솔루션에서 연 뒤, 프로젝트 속성에 들어갑니다.
    2. 프로젝트 속성이 열리면, 왼편에 나열된 탭들 중 Signing (한글로는 아마 '서명' 정도 일거입니다.) 탭을 클릭하시고, 열리는 내용 중 Sign the assembly( 한글로는 아마 '어셈블리 내에 서명' 이겠죠)를 체크합니다.
    3. 다음은 안에 열린 Choose a strong name key file: 에서 아래의 콤보 박스 내용 중,  New… 를 선택합니다.
    4. 그러면 새로운 다이얼로그가 뜨는데, 이 창이 바로 새로운 개인 인증서 하나 멋대로 만드는 것입니다.
      (외부에서 쓰기에는 좀 많이 부족하지만, 프로그램 돌리는 인증서로는 적당합니다.)
      Key file name 에다가 적당한 이름을 넣고.. 암호 부분은 넣어도 되고 안넣어도 됩니다.
      (넣으면 코드도 보호를 하는 것 같습니다만.. 뭐.. 귀찮으면 안넣어도 됩니다. 전 그냥 버릇처럼 넣습니다.). 다 넣었으면 OK를 클릭해서 닫습니다.
    5. 그러면 Assembly 내에 String name key로 위에서 넣은 이름대로 들어갔음을 확인합니다.
      그리고 컴파일을 다시 해주세요.
  2. 두번째 등장한 오류는 관리자 권한 문제입니다. 제 PC 가 Windows 7 이므로 Windows 7 중심으로 갑니다.
    Windows XP 라면 아주 특이하게 사용하시는 분(관리자 권한이 아닌 사용자 권한으로 동작시키는 분들)이 아닌 이상 발생되는 오류는 아닐 겁니다.
    1. 시작 을 클릭하고 검색창에 cmd 입력한 뒤, cmd에서 오른쪽 버튼을 눌러 관리자 권한으로 실행을 합니다.
    2. 그리고 열린 도스창에서 작업을 시작합니다. ( 3. 컴파일 그리고 배포 부분 )

3. 컴파일 그리고 배포.

네 이제 컴파일을 해주시기 바랍니다. 오탈자의 문제가 없다면 큰 문제 없이 컴파일이 될 것입니다. 컴파일이 완료되면, 이제 명령창(cmd) 창을 띄우세요.(시작 –> 실행 –> cmd 입력 )

그리고 다음 명령을 넣어주시기 바랍니다.

C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm /codebase “어셈블리파일”

“어셈블리파일” 이라는 부분은 지금 컴파일 된 DLL 파일의 전체 경로를 의미합니다.

예를 들자면…

"E:\Prj\ExposingDotNetControls_src\Home\Prisoner\bin\Debug\Prisoner.dll"

과 같은 스타일로 하시면 됩니다.

예전 C++이나 VB로 만든 ActiveX는 보통 regsvr32로 등록하고 해제했지만, 이제 .NET 기반으로 만든 ActiveX 는 이 regasm 이라는 도구로 하셔야 합니다. .NET Framework 2.0 을 설치하셨다면 위의 경로와 같은 위치에 regasm이 있을 것입니다.

정상적으로 등록되면 등록한 GUID 값과 함께 해서 조그만한 다이얼로그가 뜨게 됩니다.

4. 테스트

뭐 Object 태그로 Html 소스 안에 직접 박아서 테스트를 할 줄 아시는 분은 Html 소스를 만들어 하실 수 있을 것이고, 아니면 Visual Studio의 C++ 관련도구를 설치하신 분은 tstcon32.exe 라는 프로그램을 실행해서 테스트 해보실 수 있을 것입니다.

HTML 코드를 아래와 같이 넣어보아서 IE를 띄워봅니다.

<HTML><BODY>
<OBJECT id="myX"  CLASSID="CLSID:20F0F02D-044C-4013-AFAE-F2241D95FDA3" width="560" height="480"> 
</OBJECT>
</BODY></HTML>

당연히 뜨는 노란색 바가 보이는데, 그것을 클릭해서 진행해주시면… 아래 처럼 만든 모양 대로 뜹니다.



5. 정리.

사실 VC++로 만드는 Active X 보다는 배포하기가 조금은 까탈스럽습니다. 이 Active X를 돌릴 클라이언트 PC내에 .NET Framework가 설치되어 있어야 겠죠. 게다가 개발 편의로 따지만 SmartClient가 훨 좋습니다 ^^;  하지만 .NET의 개발 편의성과 당장 ActiveX가 필요한 상황에서는 좋을 해결점이 될 수 있으리라 생각됩니다.

pjyoung 님의 질의 내용을 근간으로 다시 프로젝트를 생성하면서 일부 업데이트를 했습니다.
최종 된 상태에서 정리하다 보니, 일부 내용을 Skip 해서 오해의 소지가 다분 있었으리라 생각이 듭니다.
(최소한 진행을 재점검해서 실행은 했습니다.)

PS. 첨부한 파일은 이 글을 재 테스트하기 위해서 만든 프로젝트를 압축한 내용입니다.
애석하게도 Visual Studio 2010 용으로 되어 있어, 예전 Visual Studio로는 솔루션과 프로젝트 파일을 제대로 활용할 수 없을 것입니다. 새로 프로젝트를 만들어서 파일만 가져다가 재 생성해야 할지도 모르겠네요.
그래도 모르니 일단 업로드를 해봅니다.

신고
Posted by 하인도
TAG .NET, 2.0, activex, COM


티스토리 툴바