오후 5:54 2002-08-23
확장DLL을 ActiveX에서 가져다 쓰기
조경민 (bro@shinbiro.com)
=============================================================

문제상황 :
OCX 컴파일시 UI를 갖는 확장 DLL을 가져다 쓸때 아래와 같은
에러가 발생할때는 아래의 얘기를 따라해 봅니다.
OMGroupmapTreeCtrl.obj : error LNK2001: unresolved external symbol
"protected: static struct AFX_MSGMAP const CGroupMapTreeCtrl::messageMap"
(?messageMap@CGroupMapTreeCtrl@@1UAFX_MSGMAP@@B)

OMRankmapTreeCtrl.obj : error LNK2001: unresolved external symbol
"protected: static struct AFX_MSGMAP const CTreeCtrlEx::messageMap"
(?messageMap@CTreeCtrlEx@@1UAFX_MSGMAP@@B)


해결책 :
testdll.dll이라는 MFC 확장 DLL은
testdll.h 에

class AFX_EXT_CLASS CWSocket
{ .. }

로 해서 내주면 된다.

그런후 testocx.ocx에서 testdll.dll을 가져다 쓸 때
Project/Setting에 /MD로 되어있는지 체크한 후
testocx.ocx내의 stdafx.h 를

#define VC_EXTRALEAN                // Exclude rarely-used stuff from Windows headers
//#define _AFXDLL               // <-- MFC Static Link라면 넣어야 한다.
                                // MFC Shared라면 넣으면 안됨

#include <afxctl.h>         // MFC support for ActiveX Controls
#include <afxext.h>         // MFC extensions
#include <afxdtctl.h>                // MFC support for Internet Explorer 4 Comon Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>                        // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT

// Delete the two includes below if you do not wish to use the MFC
//  database classes
#include <afxdb.h>                        // MFC database classes
#include <afxdao.h>                        // MFC DAO database classes

#include "testdll.h"         // <- 익스포트 헤더파일



------------------------
그 외 관련된 또 다른 문제 상황들.

PRB: Using Extension DLL, Database/OLE/Sockets in Regular DLL
정규DLL에서 확장DLL을 썼을떄 db나 소켓등이 동작 안하면 위의 해결책을 읽어야한다.

/////////////////////
   // YourExtDLL.cpp:

   #include "afxdllx.h"    // standard MFC Extension DLL routines

   static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };

   extern "C" int APIENTRY
   DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
   {
       if (dwReason == DLL_PROCESS_ATTACH)
       {
           // Extension DLL one-time initialization.
           if (!AfxInitExtensionModule(extensionDLL, hInstance))
              return 0;
       }
       return 1;   // ok
   }

   // Exported DLL initialization is run in context of application
   // or Regular DLL.
   extern "C" void WINAPI InitYourExtDLL()
   {
       // Create a new CDynLinkLibrary for this app.
       new CDynLinkLibrary(extensionDLL);

       // Add other initialization here.
   }

한후 def에 export 함수 하나 더 해주고
   /////////////////////
   // YourExtDLL.Def:

   LIBRARY      YOUREXTDLL

   CODE         PRELOAD MOVEABLE DISCARDABLE
   DATA         PRELOAD SINGLE

   EXPORTS
       InitYourExtDLL

확장DLL을 쓰는 정규 DLL에서 초기화 함수를 써줘서 확장DLL에서 정규DLL의
인스턴스를 라이브러리 체인에 제대로 연결 할 수 있도록 한다.

   /////////////////////////
   // YourRegularDLL.cpp:

   class CYourRegularDLL : public CWinApp
   {
   public:
       virtual BOOL InitInstance(); // Initialization
       virtual int ExitInstance();  // Termination

       // Nothing special for the constructor.
       CYourRegularDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { }
   };

   BOOL CYourRegularDLL::InitInstance()
   {
       // Any DLL initialization goes here.
       TRACE0("YOUR Regular DLL initializing\n");

       // Wire any extension DLLs into CDynLinkLibrary chain.
       InitYourExtDLL();

       return TRUE;
   }

-------------------------------------------------------------------------
문제 상황 TN033 확장DLL을 가져다 쓰는 확장DLL이 있는 상황에 대한 해결책
Limitations of _AFXEXT
이떄엔 AFX_EXT_CLASS를 쓸 수 없다.

A.DLL과 B.DLL이라는 확장 DLL이 있고 B가 A를 쓰는 모양이라면

// 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 ... };

A 컴파일할때는 A_IMPL을 #define 해주고
#define A_IMPL을 A 클래스 헤더 위에 놓던지 stdafx.h에 놓던지
프로젝트 세팅 C++에 A_IMPL을 놓던지.. 해서.

// 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 .. };


이번에 B를 컴파일할떈 B_IMPL을 해야 한다. 따라서 A 라이브러리
가져다쓰는 A 헤더 파일엔 A클래스의 __declspec(dllimport) 버전이
붙게되는 것이다.

+ Recent posts