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

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

cheungmine

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

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

文件1:DllCppTmpl.h

//
// DllCppTmpl.h-Win32CPPDllTemplate
// cheungmine
// underlicenceBSD
// 2007
//
#ifndef_DLLCPPTMPL_H_
#define _DLLCPPTMPL_H_

//
// DllExport
//
#ifdefDLLCPPTMPL_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 > // fornew_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 & );
typedefnew_handler(DLLCPPTMPL_API
* PtrSetNewHandler)(new_handler);
typedef
void (DLLCPPTMPL_API * PtrSetNewAndDelete)(PtrNew,PtrDelete,PtrSetNewHandler);

//
// DLLCPPTMPL_IMPORTS
//
#ifdefDLLCPPTMPL_IMPORTS
#ifdef_DLL
// causeCRTDLLtobeinitializedbeforeCrypto++sothatwecanusemallocandfreeduringDllMain()
#ifdefNDEBUG
#pragma comment(lib,"msvcrt")
#else
#pragma comment(lib,"msvcrtd")
#endif
#endif

#if !(defined(_MSC_VER)&&(_MSC_VER<1300))
using std::new_handler;
#endif


// WhenDllCppTmplattachestoanewprocess,itsearchesallmodulesloaded
// intotheprocessspaceforexportedfunctions"GetNewAndDeleteFor_DllCppTmpl"
// and"SetNewAndDeleteFrom_DllCppTmpl".Ifoneofthesefunctionsisfound,
// Crypto++usesmethods1or2,respectively,bycallingthefunction.
// Otherwise,method3isused.
static PtrNew_s_pNew = NULL;
static PtrDelete_s_pDelete = NULL;

extern " C " __declspec(dllexport) void __cdeclSetNewAndDeleteFrom_DllCppTmpl(PtrNewpNew,PtrDeletepDelete,PtrSetNewHandlerpSetNewHandler)
... {
_s_pNew
=pNew;
_s_pDelete
=pDelete;
}


void * __cdecl operator new (size_tsize)
... {
return_s_pNew(size);
}


void __cdecl operator delete( void * p)
... {
_s_pDelete(p);
}

#endif // DLLCPPTMPL_IMPORTS


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

voidDLLCPPTMPL_DLLTest1(constchar*in,char**out);

voidDLLCPPTMPL_DLLTest2(conststring&in,string&out);

}
; // Canbeignored!
/**/ //
#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 > // forthedebugheap
#endif


/**/ ////
// 如果使用动态库:DllCppTmpl
using namespace DllCppTmpl;

//
// DLL标准输出
//
#ifdefDLLCPPTMPL_EXPORTS
#if !(defined(_MSC_VER)&&(_MSC_VER<1300))
using std::new_handler;
using std::set_new_handler;
#endif

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

if(newHandler)
newHandler();
else
throwstd::bad_alloc();
}


static PtrNew_s_pNew = NULL;
static PtrDelete_s_pDelete = NULL;

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

returnp;
}


static void SetNewAndDeleteFunctionPointers()
... {
void*p=NULL;
HMODULEhModule
=NULL;
MEMORY_BASIC_INFORMATIONmbi;

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);

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


PtrSetNewAndDeletepSetNewAndDelete
=(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");//operatornew
_s_pDelete=(PtrDelete)GetProcAddress(hModule,"??3@YAXPAX@Z");//operatordelete
return;
}


OutputDebugString(
"DllCppTmplwasnotabletoobtainnewanddeletefunctionpointers. ");
throw0;
}


void * operator new (size_tsize)
... {
if(!_s_pNew)
SetNewAndDeleteFunctionPointers();

return_s_pNew(size);
}


void operator delete( void * p)
... {
_s_pDelete(p);
}


void * operator new [](size_tsize)
... {
returnoperatornew(size);
}


void operator delete[]( void * p)
... {
operatordelete(p);
}

#endif // #ifdefDLLCPPTMPL_EXPORTS


/**/ /////
// Test
void DLLCPPTMPL_DLLDllCppTmpl::Test1( const char * in , char ** out )
... {
*out=newchar[strlen(in)+20];
strcpy(
*out,"Hello");
strcat(
*out,in);
}


void DLLCPPTMPL_DLLDllCppTmpl::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[])
... {
charin[]="cheungmine";
char*out=0;

DllCppTmpl::Test1(
in,&out);

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


stringin2="cheungmine";
stringout2;

DllCppTmpl::Test2(in2,out2);

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


return0;
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值