블로그는 귀차니즘

First Sensation
  • 공지
  • 지역로그
  • 태그
  • 방명록

Com 개체를 Retun in Com Programming

Programming 2008/07/08 22:21 귀차니스트

  어떻게 하다보니 오늘 Com Dll을 만드는 일을 하게 되었습니다. 원인 인즉, .Net 1.1로 이미 배포되어있던 프로그램에 추가했던 Ftp 모듈이 약간 신뢰성이 안좋은 부분이 있어 그 부분을 수정하기 위해서 였습니다. 당시 %진행도가 필요한 Ftp 다운로드 모듈이 필요하여 웹상에 공개되어 있던 소스를 하나 받아 구성하긴 했는데, 그 마저도 바로 적용하지는 못하고 수정을 거쳐 적용을 했었습니다.
  그런데 이번에 부족한 부분이 없도록 수정을 해야 했는데, .Net 1.1에서 지원하지도 않는 것 소켓을 이용해서 통째로 짜기에는 너무 시간이 부족하더군요. 그래서 일단 WinAPI를 땡겨쓴 dll을 만들기로 했습니다. 제가 짧은 시간에 만든 것 보다야 MS에서 오래전에 공개된 API가 신뢰성이 높다고 판단하기 때문이었습니다.
  조금씩 만들어가다 보니 디자인이 영 별로더군요. 그래서 CFtpProgress 라는 클래스에서 Download, Upload 함수를 파일명과 함께 호출을 하면 CProgressObject라는 하나의 Com 개체를 리턴하는 쪽으로 수정하였습니다. 그런데 이게 또 아주 잘 알지 못하는 부분이다 보니 삽질을 하게 되더군요. 일단 삽질을 거쳐 수정을 하긴 했습니다. 방법이 대충 아래와 같더군요.( 테스트 설명 과정이다 보니 개체를 대충 작성 했습니다. )

TestDll.cpp (Language : cpp)
  1. // TestCom.idl : IDL source for TestCom
  2. //
  3.  
  4. // This file will be processed by the MIDL tool to
  5. // produce the type library (TestCom.tlb) and marshalling code.
  6.  
  7. import "oaidl.idl";
  8. import "ocidl.idl";
  9.  
  10. [
  11.     object,
  12.     uuid(4F6057F5-8CED-464E-B0D7-6DC45F50B87B),
  13.     dual,
  14.     nonextensible,
  15.     helpstring("IMain Interface"),
  16.     pointer_default(unique)
  17. ]
  18. interface IMain : IDispatch{
  19.     [id(1), helpstring("method GetSub")] HRESULT GetSub(IDispatch** RetVal);
  20. };
  21. [
  22.     object,
  23.     uuid(E77D270C-26F8-4E31-A7CB-F3BCEDC153A2),
  24.     dual,
  25.     nonextensible,
  26.     helpstring("ISub Interface"),
  27.     pointer_default(unique)
  28. ]
  29. interface ISub : IDispatch{
  30.     [id(1), helpstring("method ShowMessageBox")] HRESULT ShowMessageBox(void);
  31. };
  32. [
  33.     uuid(EAB88B2E-5DD1-4EF0-9354-6C009D79C40E),
  34.     version(1.0),
  35.     helpstring("TestCom 1.0 Type Library")
  36. ]
  37. library TestComLib
  38. {
  39.     importlib("stdole2.tlb");
  40.     [
  41.         uuid(54146920-3926-44F5-9260-7F5A11276E6B),
  42.         helpstring("Main Class")
  43.     ]
  44.     coclass Main
  45.     {
  46.         [default] interface IMain;
  47.     };
  48.     [
  49.         uuid(0FA43AE1-6482-48BA-A096-937DFC03D057),
  50.         helpstring("Sub Class")
  51.     ]
  52.     coclass Sub
  53.     {
  54.         [default] interface ISub;
  55.     };
  56. };
  57.  

  위와 같이 대충 IMain, ISub 인터페이스를 정의 해봤습니다. http://www.filewiki.net/tc/entry/ATL-Inherit-Implement-ATL으로-COM-라이브러리-작성시-상속-구현하는-방법 에 적어놓은 방법으로 Com Class를 생성 하시면 됩니다. 일단 그냥 Com Class 추가만 하다보니 IDispatch** RetVal로 정의 해놓은 부분이 있습니다. 이 부분이 수정 포인트라고 할 수 있겠군요.

Main.cpp (Language : cpp)
  1. STDMETHOD(GetSub)(ISub** RetVal);
Main.cpp (Language : cpp)
  1. STDMETHODIMP CMain::GetSub(ISub** RetVal)
  2. {
  3.     // TODO: Add your implementation code here
  4.  
  5.     return S_OK;
  6. }

  일단 해당 Main 클래스를 정의한 C++ 소스에서 위와 같이 IDispatch를 ISub로 바꾸어 줍니다. 그리고 하나 더바꿔주어야 하는 부분이 있습니다. 바로 IDL 파일 부분입니다.

Main.idl (Language : cpp)
  1. [
  2.     object,
  3.     uuid(E77D270C-26F8-4E31-A7CB-F3BCEDC153A2),
  4.     dual,
  5.     nonextensible,
  6.     helpstring("ISub Interface"),
  7.     pointer_default(unique)
  8. ]
  9. interface ISub : IDispatch{
  10.     [id(1), helpstring("method ShowMessageBox")] HRESULT ShowMessageBox(void);
  11. };
  12. [
  13.     object,
  14.     uuid(4F6057F5-8CED-464E-B0D7-6DC45F50B87B),
  15.     dual,
  16.     nonextensible,
  17.     helpstring("IMain Interface"),
  18.     pointer_default(unique)
  19. ]
  20. interface IMain : IDispatch{
  21.     [id(1), helpstring("method GetSub")] HRESULT GetSub([out,retval]ISub** RetVal);
  22. };

  IMain, ISub의 순서를 제대로 바꿔주어야 합니다. 아래에 있는 정의를 위에서 판단하지는 못하겠죠? 일단 ISub를 위로 순서를 수정한 다음, IMain을 아래로 바꾸어 주고, IDispatch역시 ISub로 바꾸어 줍니다. 그리고 마지막 남은 소스 부분에서 정의 해야 합니다.

Main.cpp (Language : cpp)
  1. STDMETHODIMP CMain::GetSub(ISub** RetVal)
  2. {
  3.     // TODO: Add your implementation code here
  4.     CComQIPtr< ISub > ComPtr;
  5.     ComPtr.CoCreateInstance( CLSID_Sub );
  6.     ComPtr.QueryInterface( RetVal );
  7.  
  8.     return S_OK;
  9. }
  10.  

  바로 위와같이 해당 기능을 구현합니다. CComQIPtr SmartPointer 클래스를 통하여 ISub 인터페이스에 대한 관리를 쉽게 처리하기로 했습니다. 그냥 그저 ISub 자체만으로도 처리는 가능합니다. 하지만 여기서 다루지는 않겠습니다. 그리고 CoCreateInstance( CLSID_Sub );를 통한 SmartPointer에 실질적인 Com 개체를 생성합니다.
  그런 다음 바로 중요한 것이 QueryInterface인데 Com개체가 Addref, Release와 같은 함수를 통하여 Reference Counting을 수행한다는 것을 알고 계신분들이 계실겁니다. 그래서 그냥 그러 *RetVal = ComPtr;과 같은 대입식으로 Com개체를 리턴한다면 해당 ComPtr이 Scope를 벗어났을때 해당 Com개체는 메모리상에서 삭제되게 됩니다.
  그래서 QueryInterface기본 구현에서 Addref를 호출해주므로 이를 통한 Interface를 얻으면서 대입합니다. 그런 다음 Sub에서는 ShowMessageBox같은 함수를 만들어 테스트를 해보도록 하겠습니다.

Sub.cpp (Language : cpp)
  1. STDMETHODIMP CSub::ShowMessageBox(void)
  2. {
  3.     // TODO: Add your implementation code here
  4.     MessageBox(NULL, L"aaa", L"", MB_OK);
  5.  
  6.     return S_OK;
  7. }
  8.  
Test.cs (Language : csharp)
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9.  
  10. namespace WindowsFormsApplication5
  11. {
  12.     public partial class Form1 : Form
  13.     {
  14.         public Form1()
  15.         {
  16.             InitializeComponent();
  17.         }
  18.  
  19.         private void button1_Click(object sender, EventArgs e)
  20.         {
  21.             TestComLib.IMain MainObj = new TestComLib.MainClass();
  22.             TestComLib.ISub SubObj = MainObj.GetSub();
  23.             SubObj.ShowMessageBox();
  24.         }
  25.     }
  26. }
  27.  

  이렇게 테스트를 해보시길 바랍니다. 이렇게 하면 ShowMessageBox에서 처리한대로 MessageBox 함수를 통한 메시지박스가 표시됩니다. 어떻게 생각하면 약간 복잡할 수도 있지만 의외로 간단할 수 있습니다. 그럼 이를 이용한 좋은 라이브러리를 만들어 보세요^^.



 

크리에이티브 커먼즈 라이센스
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.

"Programming" 분류의 다른 글

한게임 자동테트리스 Ver 0.6 (0)2008/11/15
한게임 자동테트리스 Ver 0.2 (18)2008/11/03
Read Sector From Floppy (0)2008/07/17
어제 무작정 맹글어봤던 것입니다.. (2)2008/07/16
Com Control에서 Event 제작하기 (0)2008/07/10
2008/07/08 22:21 2008/07/08 22:21
TAG ATL, COM, Return
받은 트랙백이 없고, 댓글 2개가 달렸습니다.

트랙백 주소 :: http://www.filewiki.net/tc/trackback/89

댓글을 달아 주세요

  1. kkamagui 2008/07/09 07:53  댓글주소  수정/삭제  댓글쓰기

    와우 멋진데 >ㅁ<;)-b

    COM 소스는 언제봐도 적응이 안된다야 ㅜ_ㅜ

    드라이버 소스가 더 쉬운거 같오... ㅜ_ㅜ)-b

    • 귀차니스트 2008/07/09 21:48  댓글주소  수정/삭제

      헐 ㅋㅋ 형 드라이버가 더 어려운거잖아요 ㅠㅠ
      이건 드라이버에 비하면 ㅠㅠ

RCW 에러의 원인 - ???

Small Talk 2008/04/10 11:59 귀차니스트

  오늘 회사에서 옆에서 저와 같이 일하는 형이 C#에서 프로젝트를 하는데 있어서 문제가 생기더군요. 그 원인은 바로 COM 개체를 C# UserControl 로 Wrapping 한 뒤, 그 프로젝트에서 UserControl을 등록하여 폼에 위지윅 배치를 할 경우 "RCW개체에서 분리된 COM개체는 사용할 수 없습니다" 와 비슷한 에러가 뜨는 것이었습니다.
  그래서 집에 와서 대충 한 번 살펴보긴 했는데. 테스트 대상은 Windows Media Player 이었죠. 이것은 문제가 없더군요. 그래서 제가 임의로 추측하기론 멀티쓰레드를 고려하지 않은 즉, Thread-Safe하지 않은 Com 개체에 있어서는 에러가 생긴다고 판단하였습니다.
  실제로 Com 개체의 코드를 보면 대충 이렇게 구현이 되어있죠.

ComExample.cpp (Language : cpp)
  1. #pragma once
  2. #include "resource.h"       // 주 기호입니다.
  3.  
  4. #include <boost/function.hpp>
  5. #include <string>
  6. #include <stack>
  7. #include <cmath>
  8. #include <map>
  9.  
  10. #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
  11. #error "단일 스레드 COM 개체는 전체 DCOM 지원을 포함하지 않는 Windows Mobile 플랫폼과 같은 Windows CE 플랫폼에서 제대로 지원되지 않습니다. ATL이 단일 스레드 COM 개체의 생성을 지원하고 단일 스레드 COM 개체 구현을 사용할 수 있도록 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA를 정의하십시오. rgs 파일의 스레딩 모델은 DCOM Windows CE가 아닌 플랫폼에서 지원되는 유일한 스레딩 모델이므로 'Free'로 설정되어 있습니다."
  12. #endif
  13.  
  14. // CCCalculator
  15.  
  16. class ATL_NO_VTABLE CCCalculator :
  17.     public CComObjectRootEx<CComSingleThreadModel>,
  18.     public CComCoClass<CCCalculator, &CLSID_CCalculator>,
  19.     public IDispatchImpl<ICCalculator, &IID_ICCalculator, &LIBID_IPangYaLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
  20. {
  21. public:
  22.     CCCalculator()
  23.     {
  24.     }
  25.  
  26. DECLARE_REGISTRY_RESOURCEID(IDR_CCALCULATOR)
  27.  
  28.  
  29. BEGIN_COM_MAP(CCCalculator)
  30.     COM_INTERFACE_ENTRY(ICCalculator)
  31.     COM_INTERFACE_ENTRY(IDispatch)
  32. END_COM_MAP()
  33.  
  34.  
  35.  
  36.     DECLARE_PROTECT_FINAL_CONSTRUCT()
  37.  
  38.     HRESULT FinalConstruct()
  39.     {
  40.         return S_OK;
  41.     }
  42.  
  43.     void FinalRelease()
  44.     {
  45.     }
  46. };
  47.  
  48. OBJECT_ENTRY_AUTO(__uuidof(CCalculator), CCCalculator)
  49.  

  위에서 보는 코드와 비슷한 Com Object Class 들에서 static 코드가 존재하는 Com 개체였기에 해당 에러가 발생하지 않았나 생각합니다.
  그런데 신기한건 VS.net 2003 에서는 또 별다른 문제가 없이 작동하는 Wrapping 방법이었다는 점이죠. 이 역시 아마 VS.net 2005 로 넘어가면서 IDE 자체의 큰 변화가 있었고, 작동방법이 다르게 구현이 되었기 때문이지 않을까 생각합니다.
  막연한 추측이긴 합니다만 공통된 주제를 가지고 다음에도 토론이 되었으면 하고 포스팅을 합니다.

크리에이티브 커먼즈 라이센스
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.

"Small Talk" 분류의 다른 글

또 오랜기간의 공백을... (0)2008/10/12
남의 소스를 보는 것은 어렵습니다. 그리고... (2)2008/09/27
음.. 바빠서 한 동안 신경을 못 쓰고 있다가... (2)2008/09/22
음.. 슬슬 달려 봐야 겠습니다. 그리고 최근 현황 (2)2008/08/18
해로를 소개합니다. (0)2008/08/13
2008/04/10 11:59 2008/04/10 11:59
TAG C#, COM, RCW
받은 트랙백이 없고, 댓글 2개가 달렸습니다.

트랙백 주소 :: http://www.filewiki.net/tc/trackback/48

댓글을 달아 주세요

  1. kkamagui 2008/04/21 09:27  댓글주소  수정/삭제  댓글쓰기

    쿠아~ 그런 문제도 있구나~
    완전 어렵네... ㅜ_ㅜ... 천지 이래가되긋나 ㅜ_ㅜ

    • 귀차니스트 2008/04/22 01:17  댓글주소  수정/삭제

      ㅠㅠ 글게용 원인을 잘 모르겠네요 횽이 어떻게 좀 해결을 해줘욤

IPangYa - 팡야 계산기 라이브러리

Library 2008/02/21 01:11 귀차니스트
  예전에 팡야 계산기를 만든 적이 있습니다. Microsoft Visual C++ IDE을 사용하여 만든 계산기였죠. 그 프로그램은 비록 수식과 변수를 입력받아 처리하게 하였지만 제가 만든 프로그램으로만 작동한다는 점이 있었죠. 그래서 생각한 것이 Microsoft 의 COM 기술을 사용한 라이브러리를 만들어보자는 것이었습니다. 그래서 만든 것이 IPangYa 라이브러리입니다.
  사용할 수 있는 언어는 COM 기술을 지원하는 언어라면 모두 사용할 수 있습니다. 이를테면 C#, VB, C++, Java, Delphi 같은 언어들 말이죠. 사용법은 특정 언어에 종속된 것으로 설명하지는 않겠습니다.

  먼저 아래 사항을 실행하시기 전 regsvr32 "dll경로\IPangYa.dll"로 등록을 해주셔야 합니다.

  IPangYa 라이브러리에는 CCalculator 클래스가 존재합니다. 이 클래스가 팡야 계산기 라이브러리의 대들보죠. 이 클래스에는 void SetVarialble( string VariableName, double VariableValue ); 함수와 double EvalExpress( string Expression, out int ErrorIndex ); 함수가 존재합니다.
  라이브러리를 사용할 때 수식에 필요한 변수는 SetVariable로 세팅 후, EvalExpress로 수식을 계산하게 됩니다. 그런데 수식을 어떻게 작성하고 변수와 함수를 호출하느냐가 중요한 포인트겠죠^^?

  1. 먼저 수식을 그냥 입력할 때입니다.
    1. SetVariable 함수를 호출하지 않습니다.
    2. EvalExpress함수의 첫 번째 인자에 "1 + 2 + 3 * ( 4 - 3 )" 과 같은 수식을 입력합니다.
    3. 리턴 값을 이용합니다.

  2. 변수를 사용하여 계산할 때입니다.
    1. ABC 변수에 100이라는 값을 넣으려고 한 다면 SetVariable( "ABC", 100 );을 호출합니다.
    2. EvalExpress함수의 첫 번째 인자에 "1 + 2 + [ABC]" 를 입력하고 호출합니다.
    3. 리턴 값을 이용합니다.

  3. 함수를 이용하여 계산할 때입니다.
    1. 기본적으로 지원하는 내장 함수들은 sin( 사인 ), cos( 코사인 ), tan( 탄젠트 ), abs( 절대값 ), asin( 아크사인 ), acos( 아크코사인 ), atan( 아크탄젠트 ), sgn( 0보다 크면 1, 0이면 0, 0보다 작으면 -1 ) , sqrt( 루트값 ), log( 자연로그 ), log2( 이진 로그 ), log10( 십진 로그 ), exp( 제곱 승 ), ceil( 올림 ), floor( 내림 ), round( 반올림 ) 입니다.
    2. EvalExpress함수의 첫 번째 인자에 "1 + 2 + [sin{30}]" 라고 입력하고 호출합니다.
    3. 리턴 값을 이용합니다.
    4. 만약 변수를 함수의 인자로 이용하고 싶다면 "1 + 2 + [sin{ABC}]" 라고 입력하면 됩니다. 물론 그전에 SetVariable로 ABC에 값을 할당해야 합니다.

  위와 같이 사용할 수 있습니다. 다만, 각 언어에 대해서 COM 객체의 클래스를 할당받는 방법은 다릅니다. 간단하게 C#을 예로 들겠습니다. C++도 있지만 갑자기 에러가 나네요.;

C# (Language : csharp)
  1. 1. 프로젝트 솔루션 뷰의 참조부분에서 IPangYa 라이브러리를 참조합니다.
  2. 2. 작성 코드 부분에 아래와 같이 작성합니다.
  3.  
  4. IPangYa.CCalculator clsCalc = new IPangYa.CCalculatorClass();
  5. clsCalc.SetVariable( "ABC", 100 );
  6.  
  7. int ErrorIndex;
  8. System.Windows.Forms.MessageBox.Show( clsCalc.EvelExpress( "1 + 2 + [ABC]", out ErrorIndex ).ToString() );

  위와 같이 쓰시면 해당 팡야 계산기 라이브러리를 이용하여 계산하실 수 있으실 겁니다.
그리고 EvalExpress 의 두 번째 인자인 ErrorIndex 는 에러가 난 지점을 건네받는데, 만약 그 값이 -3이라면 에러가 발생하지 않았고, -2 라면 알 수 없는 에러가 발생, 그 이후는 에러 지점의 한 칸 앞을 리턴 해줍니다. 다만 에러 그 자체가 아닌 에러가 발생한 단위의 인덱스입니다.
  미진한 부분이 많은 라이브러리이지만 유용하게 쓰셨으면 합니다.

IPangYa.rar
크리에이티브 커먼즈 라이센스
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.

"Library" 분류의 다른 글

HTML Parser - XHTML 변환 파싱 (0)2008/02/23
2008/02/21 01:11 2008/02/21 01:11
TAG ATL, COM, IPangYa, Library, 라이브러리, 팡야계산기
받은 트랙백이 없고, 댓글이 없습니다.

트랙백 주소 :: http://www.filewiki.net/tc/trackback/13

댓글을 달아 주세요

◀ 이전페이지 1 다음페이지 ▶

블로그 이미지
First Sensation 귀차니스트
rss
  • 관리자
  • 글쓰기

카테고리

  • 전체 (108)
    • Computer (3)
    • Language (14)
    • Reverse Engineering (1)
    • Algorithm (9)
    • TopCoder (3)
    • Library (2)
    • Programming (19)
    • Programming Tip (9)
    • PSP-Programming (10)
    • Program (5)
    • Small Talk (29)
    • Document (4)

최근에 올라온 글

  • 한게임 자동테트리스 Ve....
  • Intel 64 And IA32 Arch.... (1)
  • 한게임 자동테트리스 Ve.... (18)
  • 재귀적 합성이랄지...
  • 또 오랜기간의 공백을....

최근에 달린 댓글

  • 오오~ 멋진데 :) 좋은 일 하.... kkamagui 11/17
  • .. 그렇군요;;.. 사실 뭐 저.... 귀차니스트 11/16
  • 고생은하셨다만.. 벌써 프로.... 뉴올리언스 11/16
  • 이 부분은 본문에 명시되어.... 귀차니스트 11/15
  • 관리자만 볼 수 있는 댓글입.... 비밀방문자 11/15

달력

«   2008/11   »
일 월 화 수 목 금 토
            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            

링크

  • kkamagui 프로그래밍 세상.
  • 류광의 번역 이야기.
  • 서광열의 프로그래밍 언....
  • 준호씨의 블로그.
  • 최익필의 이름없는 블로그.
  • 위키는 귀차니즘.

최근에 받은 트랙백

  • 궁극의 예외처리. 이름없는 블로그 05/16
  • Maximum sum. 티스토리 지점 04/09

글 보관함

  • 2008/11 (3)
  • 2008/10 (2)
  • 2008/09 (3)
  • 2008/08 (5)
  • 2008/07 (13)

태그목록

  • Codegear
  • Contest
  • ostream_iterator
  • OTF
  • Array
  • 분양
  • Call By Reference
  • ASM
  • Printer
  • Secure
  • 한글표현
  • OS
  • XML
  • XHTML
  • Programming
  • Warcraft III
  • 예외
  • boost::shared_ptr
  • LGT
  • FreeType
  • istream_iterator
  • RCW
  • tr1
  • 디아블로3
  • 키보드
  • KDevelop
  • 병렬처리
  • \r\n
  • Reverse Engineering
  • ICPC

지역로그 : 태그 : 방명록 : 관리자 : 글쓰기
귀차니스트’s Blog is powered by Textcube 1.7.5 : Risoluto / Designed by DesignNia.net