페이지

2015년 1월 6일 화요일

[Reny Kim] DLL 제작방법 – 3.MFC Extension DLL

3.1 Basis

3.1.1 Features
Extension DLL은 MFC로부터 상속받은 재사용가능한 Class를 구현하는 DLL이다. 이는 아래와 같은 특징을 가진다.
?
  • DLL을 사용하는 Client는 반드시 “_AFXDLL”이 정의되어 Compile된 MFC Application이어야 한다. 따라서 Client는 VC++ 또는 MFC를 지원하는 개발도구로만 개발될 수 있다.
  • Extension DLL은 MFC Regular DLL에서 사용될 수 있다.
  • Extension DLL은 반드시 “_AFXEXT”가 정의 되어 Compile되어야 한다.
  • Extension DLL은 MFC의 Dynamic Link Library version을 사용하여 만들어지며, DLL과 Client는 반드시 같은 버전의 MFCx0.DLL을 사용하여야 한다.
  • Extension DLL은 Client Application은 Address 공간에 Load된다. 따라서 Client와 같은 메모리할당공간, Resource, Module State를 갖는다.
?
3.1.2 Class Export and Import
Extension DLL은 Class의 Export/Import를 위하여 “AFX_EXT_CLASS” Macro를 사용한다. 이 Macro는 Preprocessor Symbol인 “_AFXDLL”과 “_AFXEXT” 모두가 정의 되어 있는 경우, 기존의 DLL Function의 Export에 사용했던 “__declspec(dllexport)”로 정의된다. 따라서 Extension DLL Project에서는 export로 정의 되어 사용된다. 반대로 앞에서 말한 2개의 Proprocessor Symbol이 정의 되어 있지 않다면, “__declspec(dllimport)”로 정의 되어 import하는 것으로 사용된다.
?
· Using AFX_EXT_CLASS
AFX_EXT_CLASS를 이용하여 Class를 Export/Import를 하기 위해서는 Class의 Header File에 Class의 정의부분에 AFX_EXT_CLASS를 추가하면 된다.
class AFX_EXT_CLASS CMyClass : public CDocument
{
// <body of class>
};
· Export/Import for Multiple Layer
앞에서 얘기했듯이, AFX_EXT_CLASS는 “_AFXEXT”의 정의 여부에 따라 Export/Import가 결정된다. 따라서 만약 Extension DLL이 또다른 Extension DLL을 Import하는 경우에는 문제가 발생하게 된다. 예를 들어 A라는 Extension DLL이 B라는 Extension DLL을 Import한다고 하면, A 역시 DLL이므로 AFX_EXT_CLASS는 export로 동작하게 된다. 따라서 B는 Import임에도 불구하고, B 역시 export로 인식하게 된다. 이러한 문제를 방지하기 위해서 Multiple Layer를 가지는 경우, AFX_EXT_CLASS를 사용하면 안되며, 각 DLL을 위한 고유한 Preprocessor가 필요하게 된다.
// A.H
#ifdef A_IMPL
   #define CLASS_DECL_A   __declspec(dllexport)
#else
   #define CLASS_DECL_A   __declspec(dllimport)
#endif

class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };

// B.H
#ifdef B_IMPL
   #define CLASS_DECL_B   __declspec(dllexport)
#else
   #define CLASS_DECL_B   __declspec(dllimport)
#endif

class CLASS_DECL_B CExampleB : public CExampleA

{ ... class definition .. };
위와 같이 각각의 DLL마다 고유한 export/import 정의문을 만들어 사용하고, 각 DLL의 Project는 해당 Preprocessor를 Option에 정의하여 Compile한다. 이렇게 하여 각 DLL의 Header가 적절하게 export/import로 동작하게 된다.


3.2 Making Extension DLL

3.2.1 Object
간단한 DLL을 만들기 위하여 아래와 같은 기능을 가지는 Class를 DLL로 만들기로 한다.
?
  • CObject로부터 상속받은 Class를 사용한다.
  • Class는 Constructor에 이름(String), 번호(int)를 인자로 넘겨받아 멤버변수에 저장한다.
  • Class는 GetName(), GetNumber() 함수를 제공한다.
?
3.2.2 Implementation
  • 아래와 같이 새 프로젝트를 선택하고 “Visual C++” 카테고리의 “MFC DLL”을 선택한다.
 
  • MFC DLL 마법사에서 “MFC 확장 DLL”을 선택하고 프로젝트를 생성한다.
  • 프로젝트에서 “추가-새항목”을 선택한 후, 아래와 같이 MFC 클래스를 선택하고, 클래스 추가마법사에서 아래와 같이 CObject로부터 상속받는 클래스를 생성한다.
  • CTest Class의 Header를 열어 아래와 같이 Export Class로 만들고 각 함수를 선언한다.
[Test.h]
class AFX_EXT_CLASS CTest : public CObject  
{
public:
   CTest(CString sName, int nNumber);
   virtual ~CTest();
private:
   CString m_sName;
   int m_nNumber;
public:
   CString GetName();
   int GetNumber();
};
  • CTest의 Implementation을 작성한다.
[Test.cpp]
CTest::CTest(CString sName, int nNumber)
{
   m_sName = sName;
   m_nNumber = nNumber;
}

CTest::~CTest()
{
}

CString CTest::GetName()
{
   return m_sName;
}

int CTest::GetNumber()
{
   return m_nNumber;
}
  • 위와 같이 하나의 Class를 완성하고 Compile을 하면 “SimpleExtDll.dll”이 만들어진다.
?
?
3.3 Using Extension DLL
Extension DLL의 Import는 Project에서 DLL의 Library를 설정해주고, Class의 Header만 Include하면 된다. Test를 위하여 새로운 Project를 만들고 아래와 같이 Class의 Object를 생성하여 각 멤버변수를 호출한다.
#include "Test.h"

void CSimpleExtDllTestDlg::OnTestGetname() 
{
   CTest test("Test", 10);
   CString sName = test.GetName();
   int nNum = test.GetNumber();

   CString sTest;
   sTest.Format("Name: %s Number: %d", sName, nNum);
   AfxMessageBox(sTest);
}
위와 같은 Code를 작성하여 테스트하면, 정상적으로 CTest Class가 Import됨을 알수 있다. “Test.h”는 모든 멤버를 나타낼 필요는 없다. 실제로 DLL의 Client에 노출되는 public Member만을 가지면 동작할 수 있다.
[Test.h]
class AFX_EXT_CLASS CTest : public CObject  
{
public:
   CTest(CString sName, int nNumber);
   virtual ~CTest();

public:
   CString GetName();
   int GetNumber();
};

출처 : http://rainiac.com/dev/

댓글 없음:

댓글 쓰기