이제 우리는 CSmartPtr 템플릿 클래스를 사용하여 다음과 같이 클라이언트 코드를 작성할 수 있다.

 

void Foo(IUnknown* pUnk)

{

             HRESULT hr;

             CSmartPtr<IHello> plHello;

 

             hr = pUnk->QueryInterface(IID_IHello, (void**)&plHello);

             //이미 참조 카운터가 증가되었으므로

             //이 시점에서 참조 카운터의 값은 1이다.

             if(hr != S_OK)

             {

                          return;

             }

            plHello->sayHello(...);

 

            CSmartPtr<IHello> plHello2;

            plHello2 = plHello;                                //참조 카운터 == 2

            //plHello2 인스턴스의 operator=() 함수에서 자동으로 AddRef() 메서드를 호출하여

            //참조카운터를 증가시키므로, AddRef() 메서드를 호출할 필요가 없다.

           plHello2->sayHello(...);

 

plHello2 인스턴스의 SmartPtr 클래스 소멸자에서 자동으로 Release() 메서드를 호출하여 참조 카운터를 감소시키므로(참조 카운터 == 1)

Release() 메서드를 호출할 필요가 없다.

 

plHello 인스턴스의 SmartPtr 클래스 소멸자에서 자동으로 Release() 메서드를 호출하여 참조 카운터를 감소시키므로(참조 카운터 == 0)

Release() 메서드를 호출할 필요가 없다. 이 시점에서 Hello COM 객체는 소멸된다.

 

'COMPUTER TECH > COM' 카테고리의 다른 글

스마트 포인터 클래스 - 2  (0) 2010.08.12
스마트 포인터 클래스 - 1  (0) 2010.08.12
문자열을 변환해주는 API 함수  (0) 2010.08.12
COM에서의 문자열 사용  (0) 2010.08.12
CLSIDFromProgID 함수  (0) 2010.08.12
HRESULT 에 대한 내용  (0) 2010.08.12
Posted by ... XJAPAN

기존 방식으로 인터페이스의 사용이 번거롭게 느껴질 것이다. 조금 편하게 인터페이스를 사용할 수 없을까?

 

여기 한 가지 방법이 있다. 스마트 포인터 클래스를 활용하는 것이다.

 

스마트 포인터 클래스란 말 그대로 아주 영리하게 인터페이스 포인터를 관리하는 클래스를 말한다.

 

우리는 다음과 같이 CSmartPtr이란 템플릿 클래스를 정의할 수 있다.

 

template <class I>

class CSmartPtr

{

public:

          //생성자

          CSmartPtr(I* pl = NULL) : m_pl(pl)

          {

                      if (m_pl != NULL)

                                 m_pl->AddRef();

          }

 

          //복사생성자

          CSmartPtr(const CSmartPtr<I>& rl) : m_pl(rl.m_pl)

          {

                      if (m_pl != NULL)

                                 m_pl->AddRef();

           }

 

           //소멸자

           ~CSmartPtr()

          {

                       if (m_pl != NULL)

                                 m_pl->Release();

          }

      

           //대입연산자

         CSmartPtr<I>& operator=(I* pl)

         {

                       if(m_pl != pl)

                       {

                                  if(m_pl != NULL)

                                             m_pl->Release();

                                  m_pl = pl;

                                  if(m_pl != NULL)

                                             m_pl->AddRef();

                       }

                       return *this;

          }

 

          //변환연산자

          operator I*()

          {

                       return m_pl;

          }

         

          I* operator->()

          {

                       return m_pl;

          }

 

          I* operator&()

          {

                       return &m_pl;

          }

 

          BOOL operator==(I* pl) const

          {

                       return (m_pl == pl);

          }

 

          BOOL operator!=(I* pl) const

          {

                       return (m+pl != pl);

          }

 

          BOOL operator!() const

          {

                       return !m_pl;

          }

protected:

           I* m_pl;

};

'COMPUTER TECH > COM' 카테고리의 다른 글

스마트 포인터 클래스 - 2  (0) 2010.08.12
스마트 포인터 클래스 - 1  (0) 2010.08.12
문자열을 변환해주는 API 함수  (0) 2010.08.12
COM에서의 문자열 사용  (0) 2010.08.12
CLSIDFromProgID 함수  (0) 2010.08.12
HRESULT 에 대한 내용  (0) 2010.08.12
Posted by ... XJAPAN

문자열의 타입을 바꿔주는 API 함수에 대한 예제

 

char szCLSID(129)

wchar_t wszCLSID(129)

 

StringFromGUID2(CLSID_Hello, wszCLSID, 128);

wcstombs(szCLSID, wszCLSID, 128);

 

StringFromGUID2() API함수는 CLSID를 whcar_t* 데이터 타입의 문자열로 변환해준다.

wcstombs() C 런타임 함수는 wchar_t* 데이터 타입의 문자열을 char* 데이터 타입의 문자열로 변환한다.

'COMPUTER TECH > COM' 카테고리의 다른 글

스마트 포인터 클래스 - 2  (0) 2010.08.12
스마트 포인터 클래스 - 1  (0) 2010.08.12
문자열을 변환해주는 API 함수  (0) 2010.08.12
COM에서의 문자열 사용  (0) 2010.08.12
CLSIDFromProgID 함수  (0) 2010.08.12
HRESULT 에 대한 내용  (0) 2010.08.12
Posted by ... XJAPAN

COM에서는 유니코드를 사용하든 사용하지 않든 관계없이 COM 라이브러리 함수를 사용할 때나 COM 인터페이스 메서드의 인수에 문자 또는 문자열 데이터 타입을 지정할 때 항상 유니코드 데이터 타입을 사용해야 한다.

 

사용되는 타입인 LPCOLESTR 데이터 타입에 대한 내용은 wtypes.h 헤더 파일 안에 정의되어있다.

 

   typedef wchar_t WCHAR;

   typedef WCHAR OLECHAR;

   typedef OLECHAR *LPOLESTR;

   typedef const OLECHAR *LPCOLESTR;

 

결국 LPCOLESTR 타입은 const wchar_t* 타입이 된다.

 

'COMPUTER TECH > COM' 카테고리의 다른 글

스마트 포인터 클래스 - 1  (0) 2010.08.12
문자열을 변환해주는 API 함수  (0) 2010.08.12
COM에서의 문자열 사용  (0) 2010.08.12
CLSIDFromProgID 함수  (0) 2010.08.12
HRESULT 에 대한 내용  (0) 2010.08.12
COM 라이브러리 초기화  (0) 2010.08.12
Posted by ... XJAPAN

COM 라이브러리는 ProgID로부터 CLSID를 구할 수 있는 CLSIDFromProgID() API 함수를 제공한다.

 

  

               HRESULT CLSIDFromProgID(

                          LPOLESTR lpszProgID,              // ProgID 문자열 값

                          LPCLSID pclsid                                // 반환된 CLSID 값을 저장할 CLSID 포인터

                )

 

 

CLSIDFromProgID() API 함수는 우리가 시스템 레지스트리에서 ProgID에 대응하는 CLSID를 찾는 과정을 대신해주는 것이다. 우리는 이 함수를 사용하여 다음과 같이 실행 시에 ProgID에 대응하는 CLSID를 구할 수 있다.

'COMPUTER TECH > COM' 카테고리의 다른 글

문자열을 변환해주는 API 함수  (0) 2010.08.12
COM에서의 문자열 사용  (0) 2010.08.12
CLSIDFromProgID 함수  (0) 2010.08.12
HRESULT 에 대한 내용  (0) 2010.08.12
COM 라이브러리 초기화  (0) 2010.08.12
COM 클라이언트 애플리케이션 생성 과정  (0) 2010.08.12
Posted by ... XJAPAN

COM을 사용하는 대부분의 함수들과 마찬기지로 CoInitializeEx() 함수는 HRESULT 값을 리턴한다. HRESULT는 함수의 호출 결과를 나타내는 32비트의 값을 표현하며 함수가 성공적으로 호출된 경우 S_OK를 리턴하는 등의 정보를 제공해준다.

 

다음의 표는 가장 많이 사용되는 HRESULT 에러 코드이다.

 

 에러코드

값 

설명 

 E_NOTIMPL

0x80004001L 

인터페이스의 메서드가 구현되지않음 

 E_OUTOFMEMORY

0x8007000EL

요청한 메모리를 할당하지 못함

 E_INVALIDARG

0x80070057L

인터페이스 메서드에 잘못된 인수가 옴

 E_NOINTERFACE

0x80004002L

요청한 인터페이스를 지원하지 않음

 E_ACCESSDENIED

0x80070005L

요청한 컴포넌트에 접근 할 수 없음

 S_OK

0x00000000L

성공적으로 호출 된 경우

 E_FAIL

0x80000000L

함수를 호출하는 중에 에러가 생길 경우

 

 

함수의 호출 결과를 검사하기 위해 다음과 같이 == 연산자를 사용하여 검사가 가능하다.

 

  HRESULT hr;

  hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

  if(hr != S_OK) // 만약 실패했다면

  {

    cout << "초기화 할 수 없습니다!" << endl;

    return 0;

  } 

 

또는 SUCCEEDED와 FAILED 매크로를 사용하여 함수 호출 결과를 검사할 수 있다.

 

   #define SUCCEEDED(hr)        ((HRESULT(hr)>=0)

   #define FAILED(hr)                  ((HRESULT(hr)<0)  

 

 

SUCCEEDED를 사용한 예

 

   HRESULT hr;

   hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

   if(!SUCCEEDED(hr))   // 만약 실패했다면

  {

     cout << "초기화 할 수 없습니다!" << endl;

     return 0;

  }

 

'COMPUTER TECH > COM' 카테고리의 다른 글

COM에서의 문자열 사용  (0) 2010.08.12
CLSIDFromProgID 함수  (0) 2010.08.12
HRESULT 에 대한 내용  (0) 2010.08.12
COM 라이브러리 초기화  (0) 2010.08.12
COM 클라이언트 애플리케이션 생성 과정  (0) 2010.08.12
.Net 컴포넌트 COM에서 사용하기  (0) 2010.08.12
Posted by ... XJAPAN

CoInitialize / CoInitializeEx 함수

 

1. CoInitializeEx

 

 

  HRESULT CoInitializeEx(

             void * pvReserved,       //예약됨, 반드시 NULL이어야 함

             DWORD dwCoInit          //COINIT 열거형 값

  };

 

 

두번째 인수는 스레딩 모델관련 부분이다.

COINIT_APARTMENTTHREADED를 지정한다고 생각하면 된다.

 

2. CoInitialize

 

 

HRESULT CoInitalize(

          LPVOID pvReserved       //예약됨, 반드시 NULL이어야 함

};

 

 

현재는 CoInitialize 함수를 잘 사용하지 않기 때문에 CoInitializeEx() 함수를 쓰는것이 좋다.

Posted by ... XJAPAN

COM 클라이언트 애플리케이션 생성 과정

 

1. COM 라이브러리를 초기화한다.

2. COM 객체의 CLSID를 구한다.

3. COM 객체의 인스턴스를 생성한다.

4. COM 객체가 지원하는 인터페이스의 포인터를 구하여 해당 인터페이스가 제공하는 메서드를 호출함으로써 COM 객체가 제공하는 서비스를 사용한다.

5. COM 객체의 사용이 모두 끝나면 COM 라이브러리의 초기화를 해제한다.

 

Posted by ... XJAPAN

.Net 컴포넌트를 Register Assembly(RegAsm)을 사용해 레지스터리에 등록하는데
이것은 .Net 컴포넌트를 COM형태로 만드는것이 아니라 
COM처럼 보이도록 하는것이구요 
표준 Windows클라이언트들은  컴포넌트 클래스를 런타임시에 바인드합니다.

예를들어 설명하겠습니다.

=========================================================================
아래와 같은 닷넷 클래스가 있습니다.

using System;

namespace TestClass
{
    
    public class TestClass
    {
        public TestClass()
        {
            
        }
        public string Hello(string name)
        {
            return "Hello "+name;
        }
    }
}

==================================================================
이를 등록하려면 command창에서 
c:>regasm  TestClass.dll 

====================================================================
그런후에 기존에 com처럼 사용하시면 됩니다.
vb 스크립트로 간단하게 작성하면

Option Explicit

Dim objTestClass 
Dim InputValue
Dim Result 


Set objTestClass = CreateObject (" TestClass.TestClass")
InputValue=" 장성호 "
Result = objTestClass.Hello(CLng(InputValue))
Call MsgBox(Result )

뭐 위와 같은 식으로 하면 될껍니다.

참 그런데 한가지 문제가 있습니다.
===============================================================================
이것을 사용하기 위해서 한가지 해야하는것이 있습니다.
그것은 .Net 어셈블리 컴포넌트를 COM에서 호출하려면 COM서비스가 .NET 어셈블리 컴포넌트의 위치를 
찾을수 있어야 합니다.

그러려면 전역 어셈블리로 등록하던지 아니면 클라이언트 작업폴더에 가져다 놓던지 해야합니다.
================================================================================
그럼 닷넷 어셈블리를 전역어셈블리로 등록하는 법을 말씀드리겠습니다.

그것은 StrongName 강력한이름이 있어야 합니다.
그것을 만드는 방법은 
C : > sn   -k   Test.snk
=================================================================================
그런다음 이파일을 닷넷 프로젝트 Bin \ Debug 폴더에 가져다 놓고
AssemblyInfo.cs파일에서 KeyFile을 적어줘야 합니다.

[assembly: AssemblyKeyFile( " Test.snk") ]
=================================================================================
그런후 컴파일하고 
=================================================================================
컴파일된 dll파일( 여기서는 TestClass.dll 이 되겠군요) 을 공유 어셈블리가 있는 폴더로 옮겨 놓으면 됩니다.

공유어셈블폴더는 WINNT\ Microsoft.NET\Framework\v1.0.3705        // 맞는가 모르것네...쩝쩝

그냥 복사해서 옮기는 방법말고
gacutil이라는 툴이 있습니다.


cmd창에서 어셈블이 폴더(C:\WINNT\ Microsoft.NET\Framework\)로가서

gacutil / i  TestClass.dll  
이러면 dll이 전역 캐시에 설치가 됩니다.

===================================================================================
TlbExp.exe

이것은 닷넷어셈블리파일을 COM 형식 라이브러리( * .tbl )를 만들어 줍니다.
그러면 VB 6.0같은 .NET환경에 기반을 두지 않은 개발 언어들도 이 형식 라이브러리 파일을 이용하여
 .NET 컴포넌트에 대한 런타임시 바인딩을 수행하여 참조할수 있습니다/

 c : > TlbExp  TestClass.dll

=====================================================================================
위의 두과정을 한번에 하려면 

c : > regasm  TestClass.dll    / tlb: TestClass.tlb

 / tlb  플래그를 사용하시면 됩니다.

 
Posted by ... XJAPAN

#1  레지스트리 등록/해제

#2  IUnkonown 인터페이스  구현

#3  클래스 펙토리 컴포넌트-1

 

공통적으로 또는 기본적으로 모든 COM 컴포넌트가  갖추어야 할 내용들중에

#1, #2 는 앞에서  언급됬던 내용들이여서 생략한다.

 

이제 클래스펙토리 컴포넌트( 이제부터 컴포넌트를 객체라는 용어와 혼용되도 

이해가 가능할 것 같애서 그냥 "객체"라고 하자. )

에 대해서 알아보자.

 

클래스 팩토리( Class Factories : 객체공장@@)

정의 :  객체를 생성하고 소멸시킬 때 COM 서브시스템에서 사용된다. 그래서 모든 서버는

           이 객체를 제공해야 한다. 

 

클래스팩토리 객체의 쓰임 시나리오 :

  -> 도대체 COM 서브시스템은 어떻게 클래스 팩토리 객체를 사용하는 것일까? 알아보자

 

인프로세스 서버인 경우 쓰임

 

  1. COM 클라이언트가 컴포넌트 요구

      2. COM 서브시스템이 요구사항을 받음.

           -> 레지스트리에서 요구된 서버를 찾는다.

           -> 레지스트레서 요구된 서버 정보를 찾았다면

           -> 이정보를 가지고 DLL를 메모리에 올린다.

           -> 인프로세스 서버가 필수적으로 구현해야 하는 함수

                DllGetClassObject() 를 호출

 

           3. 컴포넌트 안(객체)에서  함수 실행

               DllGetClassObject()

              {

                   // 클래스팩토리 객체 생성

                   // 클래스팩토리 객체를 이용해서 요구된 컴포넌트(객체)를 생성한다.

              }

 

 

로컬 서버인 경우 쓰임

 

  1. COM 클라이언트가 컴포넌트 요구

      2. COM 서브시스템이 요구사항을 받음.

           -> 레지스트리에서 요구된 서버를 찾는다.

           -> 레지스트레서 요구된 서버 정보를 찾았다면

           -> 이정보중에

               로컬서버가 필수로 구현해야 하는 함수

               CoRegisterClassObject() 호출

 

           3. 컴포넌트 안(객체)에서  함수 실행

               CoRegisterClassObject()

              {

                    // 클래스팩토리 객체를 레지스트리에 등록한다.

                   // 클래스팩토리 객체 생성

                   // 클래스팩토리 객체를 이용해서 요구된 컴포넌트(객체)를 생성한다.

              }

 

#3  클래스 펙토리 컴포넌트-2

클래스팩토리 객체는 하나의 컴포넌트이다.

 

여기에도 인터페이스를 가지고 있는데,

이것이 IClassFactory란 이름의 표준 인터페이스를 통해서 클래스 팩토리

프로토콜이 제공되고 있다.

 

// IClassFactory 클래스

class IClassFactory : public IUnknown

{

      virtual HRESULT CreateInstance( IUnknown *pUnkOuter ,

                                                      REFIID riid,

                                                      void **ppvObject) = 0;

      virtual HRESULT LockServer(BOOL fLock) = 0;

};

 

와 같이 인터페이스 선언되어져 있다.

IClassFactory  의  핵심은 CreateInstance 이다. 

이 인터페이스의 역활은 다음과 같다.

 

               - 새로운 객체를 생성

               - 생성한 객체중 요구된 인터페이스 포인터 반환

 

CreateInstance

 - pUnkOuter 매개변수 :  이것은 컴 통합(aggregation)과 관련되어 있다.

                                이것은 현재 컴포넌트가 다른 컴포넌트의 내부로

                                통합될때 의미가 있다.  이건 나중에 다루도록 하자.

 

LockServer

 - 잠금카운트, 즉 객체의 생성과 해제를 자주하는 클라이언트에 대해 성능을

   보장해 주기 위하여 사용된다. 

   규칙적으로 객체를 생성하고, 짧은 기간동안 사용한 다음, 해제하는 것을 반복하는

   클라이언트가 있을때, 이것은 OS에게 많은 무리를 준다.

   생성하고, 해제하는 과부하게 걸리게 된다.

   이런 클라이언트를 만났을지라도 효율적으로 사용할수 있도록  잠금카운터가 있는 것이다.

  

   사실 서버는 객체카운와 참조카운트 모두 0이 되었을때 메모리에서 해제된다.

   "생성-사용-해제-반복"패턴을 가진 클라이언트를 만났을지라도 딱 한번만 메모리에

   올라와서 객체 카운트와 참조카운트가 0이 되었을때만 메모리에서 해제된다고 한다. 

 

Posted by ... XJAPAN
TAG COM & ATL
이전버튼 1 2 이전버튼