C++ 생성자를 DLL로부터 동적 로드해 객체를 생성한다면?
다음과 같은 질문이 있군요. ^^
C++ DLL로 class를 export후 LoadLibrary로 DLL을 불러와 new로 class 객체를 생성할 수 있는 방법 없을까요
; http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_QnA_etc&no=3843&z=
질문의 요지는 이렇습니다. C++ 클래스를 DLL에 구현해 두었는데, 이 클래스의 인스턴스를 외부 EXE/DLL에서 접근해 생성하고 싶다는 것입니다. 검색해 보면 이를 위한 방법을 다음의 글에서 찾을 수 있습니다.
Using classes exported from a DLL using LoadLibrary
; http://www.codeproject.com/Articles/9405/Using-classes-exported-from-a-DLL-using-LoadLibrar
직접 실습을 해볼까요? ^^
우선, Visual Studio에서 C++ Win32 DLL 프로젝트를 "Export symbols" 옵션을 켜서 생성한 후, 기본 포함된 CWin32Project1 클래스의 코드에 다음과 같이 테스트를 위해 필드 n과 Print 함수를 포함시켜 둡니다.
#define WIN32PROJECT1_API __declspec(dllexport)
#include <stdio.h>
class WIN32PROJECT1_API CWin32Project1 {
public:
int n;
CWin32Project1(void);
void Print()
{
printf("%d\r\n", n);
}
};
CWin32Project1::CWin32Project1()
{
n = 500;
return;
}
컴파일하고 Visual Studio 명령 프롬프트를 실행시켜 dumpbin.exe를 실행하면 생성자가 export된 심볼을 구할 수 있습니다.
C:\temp\Win32Project1\x64\Debug>dumpbin /exports Win32Project1.dll
Microsoft (R) COFF/PE Dumper Version 14.00.23026.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file Win32Project1.dll
File Type: DLL
Section contains the following exports for Win32Project1.dll
00000000 characteristics
55FAAD26 time date stamp Thu Sep 17 21:08:06 2015
0.00 version
1 ordinal base
6 number of functions
6 number of names
ordinal hint RVA name
1 0 0001100A ??0CWin32Project1@@QEAA@XZ = @ILT+5(??0CWin32Project1@@QEAA@XZ)
2 1 00011069 ??4CWin32Project1@@QEAAAEAV0@$$QEAV0@@Z = @ILT+100(??4CWin32Project1@@QEAAAEAV0@$$QEAV0@@Z)
3 2 000111B8 ??4CWin32Project1@@QEAAAEAV0@AEBV0@@Z = @ILT+435(??4CWin32Project1@@QEAAAEAV0@AEBV0@@Z)
4 3 000112B2 ?Print@CWin32Project1@@QEAAXXZ = @ILT+685(?Print@CWin32Project1@@QEAAXXZ)
5 4 000112CB ?fnWin32Project1@@YAHXZ = @ILT+710(?fnWin32Project1@@YAHXZ)
6 5 0001C164 ?nWin32Project1@@3HA = ?nWin32Project1@@3HA (int nWin32Project1)
Summary
1000 .00cfg
1000 .data
1000 .idata
1000 .pdata
3000 .rdata
1000 .reloc
1000 .rsrc
8000 .text
10000 .textbss
이 값을 이용해 LoadLibrary/GetProcAddress로 함수 포인터를 구하는 코드는 이렇습니다.
#include "stdafx.h"
#include <Windows.h>
class CWin32Project1 {
public:
int n;
CWin32Project1(void);
void Print();
};
typedef void(*CTORFUNC) (void *pThis);
typedef void(*PRINTFUNC) (void *pThis);
int main()
{
HMODULE hModule = ::LoadLibrary(L"Win32Project1.dll");
if (hModule == NULL)
{
printf("NOT FOUND: Module\r\n");
return 1;
}
// Why can't I GetProcAddress a function I dllexport'ed?
// 64비트와 32비트에서의 export symbol 이름이 다르다는 점!
#if defined(_AMD64_)
char *ctorName = "??0CWin32Project1@@QEAA@XZ";
char *printName = "?Print@CWin32Project1@@QEAAXXZ";
#else
char *ctorName = "??0CWin32Project1@@QAE@XZ";
char *printName = "?Print@CWin32Project1@@QAEXXZ";
#endif
CTORFUNC ctorProc = (CTORFUNC)::GetProcAddress(hModule, ctorName);
PRINTFUNC printProc = (PRINTFUNC)::GetProcAddress(hModule, printName);
if (ctorProc == NULL || printProc == NULL)
{
printf("NOT FOUND: ctor or print\r\n");
return 1;
}
// 해당 클래스의 객체 크기만큼 미리 메모리를 할당
int size = sizeof(CWin32Project1);
char *pBytes = new char[size];
// 할당된 메모리가 바로 this 포인터 역할을 함.
// 생성자를 호출해 인스턴스를 초기화하고,
ctorProc(pBytes);
// 멤버 함수를 호출
printProc(pBytes); // 출력 결과: 500
delete [] pBytes;
return 0;
}
첨부한 파일은 위의 코드를 포함하고 있습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]