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

来源:互联网 发布:sql删除表中带约束的列 编辑:程序博客网 时间:2024/05/01 19:40

 一个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 *inchar** out);

void  DLLCPPTMPL_DLL Test2(const string& instring& 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 *= 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 *inchar** out)
{
    
*out = new char[strlen(in+ 20];
    strcpy(
*out"Hello ");
    strcat(
*outin);
}


void  DLLCPPTMPL_DLL DllCppTmpl::Test2(const string& instring& 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下。