您的位置:首页 > 编程语言 > C语言/C++

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

2007-04-04 18:47 417 查看
 一个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下。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐