수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1694123
  • Today | 474
  • Yesterday | 588

1 Articles, Search for '형식라이브러리'

  1. 2007/01/05 COM 형식 라이브러리 사용하기
Programming/ATL/COM2007/01/05 10:15

COM 형식 라이브러리 사용하기

고수닷넷 - bro님

[형식 라이브러리 추출]

원하는 인터페이스의 idl을 midl 컴파일러를 통해 형식 라이브러리(tlb)를 얻어내어 이를 #import 하여 쉽게 COM을 억세스 하도록 합니다.

이해를 돕기 위하여 Microsoft의 MSN Messenger COM Library인 Messenger 인터페이스를 가져다 쓰는 예를 들며 설명합니다.


먼저, 원하는 인터페이스의 idl을 얻어내야 합니다. idl 파일이 직접 있다면 이를 이용하고, 없다면 VC++의 툴인 OLE/COM Object Viewer를 연 후, 원하는 COM 오브젝을 찾아내야 합니다.


Type Libraries 노드 밑에 Messenger API Type Library를 선택한 후 오른클릭 하여 View를 선택합니다.

( MSN 5.0 이하에서는 All Object 노드에서 Messenger를 찾을 수 있습니다. )

사용자 삽입 이미지


이렇게 하면 Messenger API 형식 라이브러리의 idl 을 볼 수 있습니다. 이제 이 idl을 메뉴에서 File/ Save As로 msnmsgr.idl로 저장 한 후 ( 이름은 마음대로 정하셔도 됩니다 ) 우리가 이 인터페이스를 사용하는데 도움을 주는 형식 라이브러리 (.tlb)로 만들어 봅시다.


아래는 idl에서 tlb 형식라이브러리를 만드는 예입니다.

D:\>midl /mktyplib203 msnmsgr.idl


MSN 5.0 이하에서는 문제없이 컴파일이 되었는데 MSN 6.0에서는 아래와 같은 결과를 출력합니다.


D:\>midl /mktyplib203 msnmsgr.idl

Microsoft (R) MIDL Compiler Version 5.01.0164

Copyright (c) Microsoft Corp 1991-1997. All rights reserved.

Processing .\msnmsgr.idl

msnmsgr.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\oaidl.idl

oaidl.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\objidl.idl

objidl.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\unknwn.idl

unknwn.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\wtypes.idl

wtypes.idl

.\msnmsgr.idl(76) : error MIDL2025 : syntax error : expecting a type specificati

on near "MOPTIONPAGE"

.\msnmsgr.idl(76) : error MIDL2026 : cannot recover from earlier syntax errors;

aborting compilation


이 idl을 노트패드에서 열어보면 MOPTIONPAGE 의 정의가 아래 쪽에 있는 것을 확인 하 실 수 있습니다. 따라서 인자로 쓰이는 구조체의 정의 부를 해당 인터페이스 정의 부 위로 옮겨야 합니다. ( 예전 버전의 MSN 인터페이스는 그러지 않았는데 새로 인자 형식이 많이 생긴 듯합니다 )


그런 식으로 에러 나지 않게 정의부를 위로 옮기시면 아래와 같이 컴파일이 잘 됩니다. 그리고 그 결과로 msnmsgr.tlb 파일이 생기게 됩니다.


D:\bro\mine\gosunet\using_tlb>midl /mktyplib203 msnmsgr.idl

Microsoft (R) MIDL Compiler Version 5.01.0164

Copyright (c) Microsoft Corp 1991-1997. All rights reserved.

Processing .\msnmsgr.idl

msnmsgr.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\oaidl.idl

oaidl.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\objidl.idl

objidl.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\unknwn.idl

unknwn.idl

Processing C:\Program Files\Microsoft Visual Studio\VC98\include\wtypes.idl

wtypes.idl


이제 우리가 원하는 형식 라이브러리를 얻게 되었습니다. 이를 이용하여 COM 프로그래밍을 쉽게 할 수 있습니다.


간단하게 이 형식 라이브러리를 이용해서 MSN 자동 로그인을 하도록 하는 기능을 만들어 봅니다.


Visual C++을 실행 한 후 다이얼로그 기반의 프로젝트를 생성합니다.

그리고 방금 만든 msnmsgr.tlb를 해당 프로젝트 폴더로 복사합니다.

stdafx.h 파일에 다음을 추가합니다.


#import "msnmsgr.tlb" named_guids, no_namespace


버튼 클릭 시 아래와 같은 코드가 실행되게 합니다.


   AfxOleInit(); // COM 초기화는 App::InitInstance() 에 두길 추천합니다.


   IMessengerPtr msn;

   msn.CreateInstance( __uuidof(Messenger), NULL, CLSCTX_LOCAL_SERVER );      


   msn->AutoSignin();


버튼 클릭으로 위의 코드가 실행되면 msn 메신저가 로그 오프일 때 자동 로그인이 실행되게 됩니다.


만일 형식라이브러리를 Import하여 스마트 포인터를 사용하지 않는다면


HRESULT get_MyContacts(

   IDispatch ** ppMContacts

);


를 사용하려 한다면 raw한 COM 프로그래밍으로 하려면

  IMessengerGroups* Groups;

IMessenger2* msg;

    :

IDispatch* lpGroups;

msg->get_MyGroups( &lpGroups );

Groups = lpGroups;

lpGroups->Release();


이렇게 해야 합니다만, 형식라이브러리 Import 후 스마트 포인터를 사용하면 아래와 같이 간결하고 안전한 코드를 짤 수 있습니다.


IMessengerGroupsPtr Groups;

IMessenger2Ptr msg;

Groups = msg->MyGroups;


이는 형식라이브러리를 import 할때 인터페이스의 프로퍼티를 자동으로 추가해주어서 가능한것으로 VB에서 프로퍼티 접근 하듯이 무척 간단하고 보기 좋은 프로그래밍을 할 수 있게 됩니다.


참고로, 만일 형식라이브러리를 사용하지 않고 직접 스마트 포인터를 사용하게 된다면


#include "msgruaid.h"

#include "msgrua.h"

#pragma comment(lib,"msgrguid.lib")


_COM_SMARTPTR_TYPEDEF(IMessenger, __uuidof(IMessenger));

_COM_SMARTPTR_TYPEDEF(IMessenger2, __uuidof(IMessenger2)););

_COM_SMARTPTR_TYPEDEF(IMessenger3, __uuidof(IMessenger3)););

:

위처럼 사용하여 스마트 포인터를 쓸 수는 있지만 프로퍼티를 위에서 했듯이 불편한 방법으로 접근해야 할 것입니다.



[이벤트 받기]


이벤트를 받는 코드를 raw하게 짜려 한다면 무척 불편하기도 합니다. 따라서 저는 ATL의 이벤트 받는 방식으로 접근합니다. 장점은 무엇보다 이벤트 메소드를 정의해서 쓰므로 가독성도 좋고 코드도 보기 좋다는 점입니다.


만일 signin 말고 다른 이벤트를 받기 위해서 이벤트의 메소드 아이디를 알고 싶으시면 모든 인터페이스의 정의가 되어 있는 idl 파일에서 그 값을 보실 수 있습니다.


예를 들어 아래 0x400의 OnSign 이벤트는

BEGIN_SINK_MAP(CMessengerEvents)

  SINK_ENTRY_EX(0, DIID_DMessengerEvents, 0x400, OnSigninx)

END_SINK_MAP()


idl에서 아래에서 찾아볼 수 있고 id는 0x400인것을 확인 하실 수 있습니다.

   [

     uuid(C9A6A6B6-9BC1-43A5-B06B-E58874EEBC96),

     helpstring("Messenger Events"),

     hidden

   ]

   dispinterface DMessengerEvents {

       properties:

       methods:

           [id(0x00000415), helpstring("A new group has been created.")]

           void OnGroupAdded(

                           [in] long hr,

                           [in] IDispatch* pMGroup);

               :

       [id(0x00000400), helpstring("Signin attempt complete.")]

           void OnSignin([in] long hr);


또한 재미있는 팁은 msn에서 파일 보내기 메소드를 실행시 파일을 바로 보내지 못하게 msn 4.x 이후에는 보안상 막아두었습니다. ( msn 바이러스가 퍼지지 못하도록 하기 위해서 였겠죠 ) 제 프로젝트 성격상 파일 보내기가 자동으로 되어야 하기 때문에 작성된 저의 트릭을 보실 수 있을 것입니다. 98/2000/xp에서 잘 수행되었습니다.


이벤트 받는 코드를 포함한 모든 저의 샘플 코드를 적어 놓도록 하겠습니다.


msnx.h

#if !defined(AFX_MSNX_H__F7BD2C8E_8C37_4B4F_B106_CAB2E772167E__INCLUDED_)

#define AFX_MSNX_H__F7BD2C8E_8C37_4B4F_B106_CAB2E772167E__INCLUDED_


#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000


#include <atlbase.h>


//You may derive a class from CComModule and use it if you want to override

//something, but do not change the name of _Module

class CExeModule : public CComModule

{

public:

   CExeModule();

};

extern CExeModule _Module;


#include <atlcom.h>

#include <atlwin.h>



#import "msn6.tlb" named_guids, no_namespace



IMessengerPtr GetMessenger();


class CMessengerEvents :

   public IDispEventImpl<0,CMessengerEvents,&DIID_DMessengerEvents,&LIBID_MessengerAPI,1,0>

{

public:

   IUnknownPtr     m_psinkObj;

   bool Create( IUnknownPtr p )

   {

       m_psinkObj = p;

       return ( DispEventAdvise(p,&DIID_DMessengerEvents) == S_OK);

   }

   void Close()

   {

       if( m_psinkObj )

       {

           DispEventUnadvise(m_psinkObj);

           m_psinkObj = NULL;

       }

   }


   virtual ~CMessengerEvents() { Close(); }


   STDMETHOD (OnSigninx) ( long hr )

   {

       return S_OK;

   }


BEGIN_SINK_MAP(CMessengerEvents)

  SINK_ENTRY_EX(0, DIID_DMessengerEvents, 0x400, OnSigninx)

END_SINK_MAP()

};



class CMessengerAPI : public IMessengerPtr, public CMessengerEvents

{

public:

   

   virtual ~CMessengerAPI()

   {

       Close();

   }

   void Close()

   {

       CMessengerEvents::Close();

   }


   bool Create()

   {

       IMessengerPtr msn = GetMessenger();

       if( msn )

       {

           *(IMessengerPtr*)this = msn;

           return CMessengerEvents::Create( msn );

       }

       return false;

   }

   

   CString GetMyID();

   CString GetMyNick();


   IMessengerWindowPtr SendFile( LPCTSTR pszSigninName, LPCTSTR pszPath );

   IMessengerWindowPtr InstantMessage( LPCTSTR pszSigninName );


   STDMETHOD (OnSigninx)( long hr )

   {

       // 로그인 될때 이벤트가 떨어집니다.

       return S_OK;

   }

};


#endif // !defined(AFX_MSNX_H__F7BD2C8E_8C37_4B4F_B106_CAB2E772167E__INCLUDED_)


msnx.cpp

#include "stdafx.h"

#include "resource.h"

#include "msnx.h"


#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif


//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

CExeModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)

END_OBJECT_MAP()


CExeModule::CExeModule()

{

   Init(ObjectMap, NULL, &LIBID_MessengerAPI);

}


IMessengerPtr GetMessenger()

{

   IMessengerPtr msn = NULL;

   try

   {

       msn.CreateInstance( __uuidof(Messenger), NULL, CLSCTX_LOCAL_SERVER );      

   }

   //catch(_com_error &e)

   catch(...)

   {

       //PrintComError(e);

       return NULL;

   }


   return msn;

}


IMessengerWindowPtr CMessengerAPI::InstantMessage( LPCTSTR pszSigninName )

{

   IMessengerWindowPtr window = NULL;

   try

   {  

       IMessengerPtr msn = *this;

       IMessengerContactPtr contact = (IMessengerContactPtr)msn->GetContact( (_bstr_t)pszSigninName, (_bstr_t)msn->GetMyServiceId() );

       if( contact )

           window = msn->InstantMessage( _variant_t((IDispatch*)contact,true));

   }

   //catch(_com_error &e)

   catch(...)

   {

       //PrintComError(e);

       return NULL;

   }

   return window;

}


CString CMessengerAPI::GetMyID()

{

   CString id;

   try

   {  

       IMessengerPtr msn = *this;

       id = (LPCTSTR)msn->MySigninName;

   }

   //catch(_com_error &e)

   catch(...)

   {

       //PrintComError(e);

       return _T("");

   }

   

   return id;

}


CString CMessengerAPI::GetMyNick()

{

   CString nick;

   try

   {  

       IMessengerPtr msn = *this;

       nick = (LPCTSTR)msn->MyFriendlyName;

   }

   //catch(_com_error &e)

   catch(...)

   {

       //PrintComError(e);

       return _T("");

   }

   

   return nick;

}


typedef struct _tagHint

{

   CString text;

   HWND hFound;

}HINT,*LPHINT;


BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )

{

   LPHINT hint = (LPHINT)lParam;

   TCHAR szText[1000]={0,};

   GetWindowText( hwnd, szText, sizeof(szText) );

   CString sFileText;

   sFileText.Format(_T("%s 님에게 파일 보내기"), hint->text );

   if( sFileText == szText )

   //if( _tcsncmp( hint->text, szText, hint->text.GetLength() ) == 0)

   {

       //if( !_tcschr( szText+hint->text.GetLength(), '-' ) )

       {

           hint->hFound = hwnd;

           return FALSE;

       }

   }

   return TRUE;

}


IMessengerWindowPtr CMessengerAPI::SendFile( LPCTSTR pszSigninName, LPCTSTR pszPath )

{

   IMessengerWindowPtr window = NULL;

   try

   {  

       IMessengerPtr msn = *this;

       IMessengerContactPtr contact = (IMessengerContactPtr)msn->GetContact( (_bstr_t)pszSigninName, (_bstr_t)msn->GetMyServiceId() );

       if( contact )

       {

           window = msn->SendFile( _variant_t((IDispatch*)contact,true), pszPath);

           //Sleep(100);

           if( window )

           {

               //// 열기 버튼을 클릭한다.

               //PostMessage( (HWND)window->HWND, WM_COMMAND, 1 , 0 );

               

               HINT hint;

               hint.text = (LPCTSTR)contact->FriendlyName;

               hint.hFound = NULL;


               // 찾을때까지 게속 창을 팢는다.

               while( !hint.hFound )

               {

                   // 피일 보내기 창을 찾는다.

                   EnumWindows( EnumWindowsProc, (LPARAM)&hint );

               

                   if( hint.hFound )

                   {

                       // 먼저 포커스를 주고..

                       ::AttachThreadInput( ::GetCurrentThreadId(), ::GetWindowThreadProcessId(hint.hFound, NULL) , TRUE);

                       SetFocus( hint.hFound );

                       ::AttachThreadInput( ::GetCurrentThreadId(), ::GetWindowThreadProcessId(hint.hFound, NULL) , FALSE);


                       // 열기 버튼을 클릭한다.

                       PostMessage( hint.hFound, WM_COMMAND, 1 , 0 );

                       break;

                   }

                   Sleep(100);

               }

           }

       }

   }

   //catch(_com_error &e)

   catch(...)

   {

       //PrintComError(e);

       return NULL;

   }

   return window;


}


정리

형식라이브러리를 Import 하여 스마트 포인터를 사용하여 COM 프로그래밍을 하면 무척 쉽고 편하게 프로그래밍을 하실 수 있습니다. 본 문서에서는 형식라이브러리를 일반적으로 Import하여 쓰는 것외에 자신이 원하는 어떠한 인터페이스도 idl을 추출하여 형식라이브러리로 만들어 사용 할 수 있다는데 중점을 두어 설명을 하였습니다.

"ATL/COM" 카테고리의 다른 글
  • Unicode/MBCS(DBCS)/ANSI/TCHAR (0)2007/03/05
  • [ATL] 새로운 인터페이스 추가하기 (0)2007/03/05
  • COM 형식 라이브러리 사용하기 (0)2007/01/05
  • GetProcAddress 쉽게 사용하기 (0)2006/12/27
  • OLE를 이용한 Drag and Drop (0)2006/11/29
2007/01/05 10:15 2007/01/05 10:15
Posted by webdizen
Tags COM, 형식라이브러리
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2557

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1  Next»

RSS HanRSS
Blog Image
webdizen
이곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (3009)
Webdizen (141)
Life (6)
Diary (16)
Blog (9)
IDEA (2)
Travel (10)
Book (16)
Photo (7)
Movie (8)
Music (14)
Leisure Sports (10)
Funny (6)
Hardware (121)
Software (120)
Windows (5)
Unix & Linux (120)
Installation (5)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (804)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (2)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (4)
Network (66)
Web (79)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • 검색 제한자
  • IDA
  • EJB
  • 예측 모델링
  • 세마포어
  • TEXTCUBE
  • 감정인식
  • 코드 성능 향상
  • 소스코드
  • OS
  • Next Statement
  • 연결연산자
  • Ansi
  • 여성
  • NULL 처리
  • Paging
  • Statistical
  • Unix
  • XPath
  • 프로젝트

Recent Articles

  • 트위터(Twitter)의 시작!.
  • 청년 리더의 조건.
  • 애플의 타블렛 PC - 아이패드....
  • 미래의 인터페이스 - 육감 기....
  • 기초발성법 동영상 강좌.

Recent Comments

  • 학교 과제물중 쓰레드에 대하....
    장진혁 03/17
  • 관리자만 볼 수 있는 댓글입....
    비밀방문자 03/12
  • 상대방의 이야기를 열심히 경....
    DoNuts 03/03
  • Lots of students know techn....
    Bobbi35Shannon 02/25
  • 좋은글 잘 보고 갑니다..
    Und_hacker 01/08

Recent Trackbacks

  • printf,scanf를 이용한 형식....
    yundream의 프로그래밍 이야기 03/10
  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 2009
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007

Archive

  • 2010/02 (1)
  • 2010/01 (6)
  • 2009/12 (5)
  • 2009/09 (3)
  • 2009/08 (1)

Calendar

«   2010/03   »
일 월 화 수 목 금 토
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.