1. Basis
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를 갖는다.
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로 동작하게 된다.
간단한 DLL을 만들기 위하여 아래와 같은 기능을 가지는 Class를 DLL로 만들기로 한다.
- CObject로부터 상속받은 Class를 사용한다.
- Class는 Constructor에 이름(String), 번호(int)를 인자로 넘겨받아 멤버변수에 저장한다.
- Class는 GetName(), GetNumber() 함수를 제공한다.
- 아래와 같이 새 프로젝트를 선택하고 “Visual C++” 카테고리의 “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”이 만들어진다.
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(); };
댓글 없음:
댓글 쓰기