0
点赞
收藏
分享

微信扫一扫

一个Win32 C++ 动态连接库的模板 --- 调用方可管理DLL分配的内存


 一个Win32 C++  动态连接库的模板

cheungmine

  一般情形下,使用C++编写动态库(DLL),在方法参数中不能输出STL对象类型, 如 std::string,这给我们的工作带来极大的麻烦。我参考一些资料,写了个C++ DLL模板,专门解决了这个问题。

     使用VS2003新建一个Win32 DLL工程——DllCppTmpl,选择空项目,即什么也不自动创建。然后把下面2个文件加入到你的工程中,编译之。

     文件1:DllCppTmpl.h

 

//

//
DllCppTmpl.h - Win32 CPP Dll Template
//
cheungmine
//
under licence BSD
//
2007
//
#ifndef _DLLCPPTMPL_H_
#define
_DLLCPPTMPL_H_


//

//
DllExport
//
#ifdef DLLCPPTMPL_DLLEXPORT

#define
DLLCPPTMPL_DLL __declspec(dllexport)

#elif
defined(DLLCPPTMPL_IMPORTS)


#define
DLLCPPTMPL_DLL __declspec(dllimport)

#else


#define
DLLCPPTMPL_DLL

#endif


//

//
公共头文件
//
#include
<
string
>

using

namespace
std;

#include
<
new
>

//
for new_handler


#define
DLLCPPTMPL_API __cdecl


typedef
void

*
(DLLCPPTMPL_API
*
PtrNew)(size_t);
typedef
void
(DLLCPPTMPL_API
*
PtrDelete)(
void

*
);
typedef
void
(DLLCPPTMPL_API
*
PtrGetNewAndDelete)(PtrNew
&
, PtrDelete
&
);
typedef new_handler (DLLCPPTMPL_API
*
PtrSetNewHandler)(new_handler);
typedef
void
(DLLCPPTMPL_API
*
PtrSetNewAndDelete)(PtrNew, PtrDelete, PtrSetNewHandler);

//

//
DLLCPPTMPL_IMPORTS
//
#ifdef DLLCPPTMPL_IMPORTS
#ifdef _DLL

//
cause CRT DLL to be initialized before Crypto++ so that we can use malloc and free during DllMain()

#ifdef NDEBUG

#pragma
comment(lib, "msvcrt")


#else


#pragma
comment(lib, "msvcrtd")


#endif


#endif



#if
!(defined(_MSC_VER) && (_MSC_VER < 1300))


using
std::new_handler;

#endif




//
When DllCppTmpl attaches to a new process, it searches all modules loaded

//
into the process space for exported functions "GetNewAndDeleteFor_DllCppTmpl"

//
and "SetNewAndDeleteFrom_DllCppTmpl". If one of these functions is found,

//
Crypto++ uses methods 1 or 2, respectively, by calling the function.

//
Otherwise, method 3 is used.


static
PtrNew _s_pNew
=
NULL;

static
PtrDelete _s_pDelete
=
NULL;


extern

"
C
"
__declspec(dllexport)
void
__cdecl SetNewAndDeleteFrom_DllCppTmpl(PtrNew pNew, PtrDelete pDelete, PtrSetNewHandler pSetNewHandler)

...
{
_s_pNew = pNew;
_s_pDelete = pDelete;
}



void

*
__cdecl
operator

new
(size_t size)

...
{
return _s_pNew(size);
}



void
__cdecl
operator
delete (
void

*
p)

...
{
_s_pDelete(p);
}

#endif

//
DLLCPPTMPL_IMPORTS



//

//
DLL接口方法
//
namespace
DllCppTmpl
...
{

void DLLCPPTMPL_DLL Test1(const char *in, char** out);

void DLLCPPTMPL_DLL Test2(const string& in, string& out);

}
;
//
Can be ignored!

/**/
//

#endif
/* ndef _DLLCPPTMPL_H_ */

文件2:DllCppTmpl.cpp



#define DLLCPPTMPL_DLLEXPORT __declspec(dllexport)


#include "
DllCppTmpl.h
"


#include <
string
.h
>


#include <
iostream
>

#include <
time.h
>

#include <
windows.h
>



#if
(_MSC_VER >= 1000)

#include <
crtdbg.h
>

//
for the debug heap

#endif



/**/
////

// 如果使用动态库: DllCppTmpl

using

namespace
DllCppTmpl;

//

//
DLL标准输出
//
#ifdef DLLCPPTMPL_EXPORTS
#if
!(defined(_MSC_VER) && (_MSC_VER < 1300))

using
std::new_handler;
using
std::set_new_handler;
#endif


void
_CallNewHandler()
...
{
new_handler newHandler = set_new_handler(NULL);
if (newHandler)
set_new_handler(newHandler);

if (newHandler)
newHandler();
else
throw std::bad_alloc();
}

static
PtrNew _s_pNew
=
NULL;
static
PtrDelete _s_pDelete
=
NULL;

static

void

*
New (size_t size)
...
{
void *p;
while (!(p = malloc(size)))
_CallNewHandler();

return p;
}

static

void
SetNewAndDeleteFunctionPointers()
...
{
void *p = NULL;
HMODULE hModule = NULL;
MEMORY_BASIC_INFORMATION mbi;

while (true)
...{
VirtualQuery(p, &mbi, sizeof(mbi));

if (p >= (char *)mbi.BaseAddress + mbi.RegionSize)
break;

p = (char *)mbi.BaseAddress + mbi.RegionSize;

if (!mbi.AllocationBase || mbi.AllocationBase == hModule)
continue;

hModule = HMODULE(mbi.AllocationBase);

PtrGetNewAndDelete pGetNewAndDelete = (PtrGetNewAndDelete)GetProcAddress(hModule, "GetNewAndDeleteFor_DllCppTmpl");
if (pGetNewAndDelete)
...{
pGetNewAndDelete(_s_pNew, _s_pDelete);
return;
}

PtrSetNewAndDelete pSetNewAndDelete = (PtrSetNewAndDelete)GetProcAddress(hModule, "SetNewAndDeleteFrom_DllCppTmpl");
if (pSetNewAndDelete)
...{
_s_pNew = &New;
_s_pDelete = &free;
pSetNewAndDelete(_s_pNew, _s_pDelete, &set_new_handler);
return;
}
}

hModule = GetModuleHandle("msvcrtd");
if (!hModule)
hModule = GetModuleHandle("msvcrt");
if (hModule)
...{
_s_pNew = (PtrNew)GetProcAddress(hModule, "??2@YAPAXI@Z"); // operator new
_s_pDelete = (PtrDelete)GetProcAddress(hModule, "??3@YAXPAX@Z"); // operator delete
return;
}

OutputDebugString("DllCppTmpl was not able to obtain new and delete function pointers. ");
throw 0;
}

void

*

operator

new
(size_t size)
...
{
if (!_s_pNew)
SetNewAndDeleteFunctionPointers();

return _s_pNew(size);
}

void

operator
delete (
void

*
p)
...
{
_s_pDelete(p);
}

void

*

operator

new
[] (size_t size)
...
{
return operator new (size);
}

void

operator
delete [] (
void

*
p)
...
{
operator delete (p);
}
#endif

//
#ifdef DLLCPPTMPL_EXPORTS



/**/
/////

// Test

void
DLLCPPTMPL_DLL DllCppTmpl::Test1(
const

char

*
in
,
char
**

out
)
...
{
*out = new char[strlen(in) + 20];
strcpy(*out, "Hello ");
strcat(*out, in);
}

void
DLLCPPTMPL_DLL DllCppTmpl::Test2(
const

string
&

in
,
string
&

out
)
...
{
out = "hello ";
out += in;
}


好了,开始写客户端。建一个Win32 console项目,如下:



// testDllCppTmpl.cpp : 定义控制台应用程序的入口点。
//

#include " stdafx.h
"


#include < windows.h
>


#define
DLLCPPTMPL_IMPORTS
//
必须定义在前


#include " ../DllCppTmpl/DllCppTmpl.h
"

#pragma
comment(lib, "../DllCppTmpl/Debug/DllCppTmpl.lib")


/**/
//

using namespace
DllCppTmpl;
/**/
////

int _tmain( int
argc, _TCHAR
*
argv[])
...
{
char in[] = "cheungmine";
char* out = 0;

DllCppTmpl::Test1(in, &out);

printf("Test1: %s ", out);
delete out;


string in2="cheungmine";
string out2;

DllCppTmpl::Test2(in2, out2);

printf("Test2: %s ", out2.c_str());


return 0;
}

 

注意路径的正确,和DllCppTmpl.dll要放到system32下。

 

举报

相关推荐

0 条评论