自定义dll文件的使用方法

来源:互联网 发布:算法工程师 百度招聘 编辑:程序博客网 时间:2024/06/18 08:02

    关于导出类  
   
  要输出整个的类,对类使用_declspec(_dllexpot);要输出类的成员函数,则对该函数使用_declspec(_dllexport)。如:  
   
  class   AFX_EXT_CLASS   CTextDoc   :   public   CDocument  
  {  
  …  
  }  
   
  extern   "C"   AFX_EXT_API   void   WINAPI   InitMYDLL();   
    
  新建两个工程,其中一个是dll工程(我的示例程序中这个工程名为DllClass),另一个是测试和使用dll的工程(名字为DllClassTest)   
    
  注意点:  
        1.   Dll工程编译完成后,将.lib和.dll文件拷贝到测试和使用dll的工程的适当目录下(我的程序是release目录),然后将Dll工程中的导出类的头文件(以下简称头文件)拷贝到测试和使用dll的工程的适当目录下(在我的程序中是拷贝到此工程文件所在目录),然后把这个拷贝过来的头文件通过下面2和3进行修改。  
   
  2.   在Dll工程中的头文件使用的是   #define   DLLCLASS_API   __declspec(dllexport)   表示导出  
  在测试和使用dll的工程中的头文件使用的是   #define   DLLCLASS_API   __declspec(dllimport)   表示导入  
   
  3.   不论Dll工程的头文件如何实现(比如说包括内联函数等等),在测试和使用dll的工程中的头文件中全部都是声明而没有定义(即将类成员函数的实现部分去掉)  
   
  4。在测试和使用dll的工程的那个文件中包含对dll库的引入,分两步:  
   
  首先在是测试和使用dll的工程的setting菜单(按ALT+F7可以调出)中的LINK选项卡中的Object/Librarymodules:下填写对   dll   的连接,比如dll文件名字为DllClass.lib和DllClass.dll,则填写   ../Release/DllClass.lib(注意目录,我的程序中.lib文件是在目录release下)。  
  然后,添加对头文件的包含,比如dll文件名字为DllClass.lib和DllClass.dll,头文件为DllClass.h,则包含头文件为   #include   "DllClass.h"  
    
  由此,就可以使用了。  
   
  相关源码如下:  
   
  dll工程中的DllClass.h   内容:  
   
  //此处在dll的头文件中为   dllexport,在应用文件中为dllimport  
   
  #defineDLLCLASS_API__declspec(dllexport)  
   
  //导出一个类(包括其方法、属性)  
  classDLLCLASS_APICDllClass  
  {  
  public:  
  CDllClass(void);  
  voidMSG(constchar*conststr);  
  };  
   
  dll工程中的DllClass.cpp内容:  
  #include"stdafx.h"  
  #include"DllClass.h"  
   
  BOOL   APIENTRY   DllMain(HANDLE   hModule,DWORD   ul_reason_for_call,LPVOID   lpReserved)  
  {  
  switch(ul_reason_for_call)  
   {  
   case   DLL_PROCESS_ATTACH:  
   case   DLL_THREAD_ATTACH:  
   case   DLL_THREAD_DETACH:  
   case   DLL_PROCESS_DETACH:  
   break;  
  }  
  return   TRUE;  
  }  
   
   
  CDllClass::CDllClass()  
  {  
   return;  
  }  
   
  void   CDllClass::MSG(const   char*   const   str)  
  {  
  MessageBox(NULL,str,"",MB_OK);  
  }  
   
  Dll测试工程中的DllClass.h内容:  
   
  //此处在dll的头文件中为   dllexport,在应用文件中为dllimport  
  #define   DLLCLASS_API   __declspec(dllimport)  
   
  //导出一个类(包括其方法、属性)  
  class   DLLCLASS_API   CDllClass  
  {  
  public:  
   CDllClass(void);  
   void   MSG(const   char*   const   str);  
  };  
  Dll测试工程中DllClassTest.cpp内容:  
  首部:  
  #include   "DllClass.h"  
  class   DllClass;  
   
  代码部分:  
  CDllClass   CTest;  
  CTest.MSG("this   is   a   string   into   dll");  

 

简单的说:如果使用MFC的话,请在类声明前加AFX_EXT_DATA,这样在使用的时候,MFC会自动将AFX_EXT_DATA解析成__declspec(export)或__declspec(import)的,不需要你来关心。  
   
  class   AFX_EXT_DATA   A  
  {  
  public:  
          void   Fun(){}  
  };  
   
  class   AFX_EXT_DATA   B  
  {  
  public:  
          void   Fun2(){}  
  };  
   
  要想调用DLL中的类,一般有两种方式:  
  1:显示连接DLL,通过众所周知的LoadLibrary(DLL名称);加载成功后,因为这种加载方式只能导出函数,而不能导出类,所以需要一些辅助的技术,一般函数不多的话,可以在DLL里写一个导出函数,就是代理;比如:CallAFun,而CallAFun函数在DLL里再调用A的Fun函数;这个实现再高级一点就是COM模型了,因为隐藏了真正的实现,这里就不讨论了。  
   
  2:如果是隐式调用直接:  
  包含XXDLL.lib(Dll带的lib文件)和头文件就可以直接使用了。  
   
  3:最好的办法是使用MFC扩展DLL,它直接导出类,而不需要以上的操作。  


如果是MFC规则DLL,不要加AFX_EXT_DATA,要用,AFX_CLASS_EXPORT,因为AFX_EXT_DATA是专门为扩展DLL准备的.

http://topic.csdn.net/t/20050217/14/3787475.html

 

 

输出整个class类的动态库必须用.lib文件,只要包含.h文件后,与MFC的类库用法相同。  
  输出函数的动态库有显示连接和隐式连接之分:  
  隐式连接:  
  在需要用到该函数的头文件里面包含动态库的.h文件,连接时加入.lib引入库。这种方式下,exe文件一加载,Windows就要加载动态库,首先寻找exe当前目录,其次找Windows和System目录,然后按照path环境变量指定的路径查找,找不到会弹出错误提示对话框。  
  显式连接:  
  用LoadLibrary("abc.dll")加载动态库,返回库的Handle,如果Handle==NULL,则说明没有该动态连接库。然后定义函数指针类型变量,用GetProcAddress(Handle,"FunctionName");取得函数的地址,然后调用该指针即可。  
  用GetProcAddress为关键字在MSDN上面可以找到许多许多的例子。

 

看下面的例子(动态连接),其中RegisterTCP为comm.dll定义的函数:

  HINSTANCE   hCommDLL;  
  BOOLEAN (_cdecl   *RegisterTCP)(HWND,   WORD);  
   
  hCommDLL   =   LoadLibrary("comm.dll");  
  if(hCommDLL!=NULL)  
  {  
          //得到DLL函数体的地址  
          (FARPROC   &)   RegisterTCP           =   GetProcAddress(   hCommDLL,"RegisterTCP");  
  }  
  else  
  {  
          Application->MessageBox("装入动态链接库comm.dll失败,程序退出!",   "DLL错误",   MB_OK);  
          FreeLibrary(hCommDLL);  
          return;  
  }  

http://topic.csdn.net/t/20000922/13/31253.html

 

建议为了动态库的通用性,还是将string全部换成char   *   或是pchar类型。

 

——————————————————————————————————————————————————————————————

 

公司里的项目里用到加密解密,使用的是客户指定的DLL库来加密解密.

开始,我按照以前的方法来使用DLL库,这里也介绍下吧,虽然网上很多.一般动态加载DLL的步骤如下:

HINSTANCE  DLL库实例名=LoadLibrary(_T("DLL库名.dll"));//加载解密函数库
typedef BOOL (CALLBACK *函数类型名)(函数参数1,函数参数2...... );//定义函数类型,格式一
//typedef BOOL (__cdecl *函数类型名)(函数参数1,函数参数2...... );//定义函数类型,格式二
函数类型名 使用时的函数名=(函数类型名)GetProcAddress(DLL库实例名,_T("DLL库里的原函数名"));//定义函数 

好了,就这么简单,然后就可以使用"使用时的函数名"这个了,把它当成是一般的函数使用就可以了

一般情况下我都是使用"定义函数类型,格式一"来定义函数类型的,而且网上的方法也都是提供这种方法的,没想到我在项目里使用时,居然总是出现错误,使用try{}catch{}也捕捉不到那个错误,错误的现象为:The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a funtion pointer declared with a different calling convention.

到网上找了一下,了现这个问题别人也经常出现,可惜没几个人给出了好的回答,最后看到一个人提供的方法,就是使用//typedef BOOL (__cdecl *函数类型名)(函数参数1,函数参数2...... );//定义函数类型,格式二.这种格式就没问题了,看来是调用约定不匹配造成的.因此,在使用DLL时还要熟悉这个DLL里函数的格式.


  • 也许还看不明白,那我做一个示例

    HINSTANCE mydll=LoadLibrary(_T("C://test.dll"));//加载解密函数库
    typedef BOOL (CALLBACK *ADD)(int a,int b);//定义函数类型,格式一
    ADD myadd=(ADD)GetProcAddress(mydll,_T("add"));//定义函数

    使用时:
    int x=2;
    int y=3;
    int r=0;
    r=myadd(x,y);

    结果r=5;
    当然,前提是那就DLL里有add这个函数,且参数也是(int a,int b)
  • 既然是动态加载 最后最好FreeLibrary(mydll)掉吧。


  • 如果不使用动态加载DLL的话,可以使用静态加载,不过,这需要事先得到LIB文件和.H文件,如果这三个文件都有的话,那就可以很方便的加载DLL了,方法如下:

    如何加载DLL
    1(配置头文件路径):选择项目->属性->C/C++-》常规-》附加包含目录:设置引用头文件路径
    2(配置DLL和Lib文件路径):选择项目->属性->连接器-》常规-》附加库目录:设置DLL路径
    3(加载Lib文件):选择项目->属性->连接器-》输入-》附加依赖项:输入要加载的Lib文件名(加载多个Lib文件时,以回车为分隔符)
    4(该主应用程序.exe的生成目录,和要加载的DLL、Lib放在同一目录):选择项目->属性->连接器-》常规-》输出文件
  • 原创粉丝点击