打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C/C++ (函数、变量和类)动态库的创建、导出和使用
userphoto

2017.09.26

关注

Windows

 1引入库的原因:

   a.项目的复杂程度大

   b.提高代码的利益利用率

 2库的分类

   2.1静态库: *.lib,不能被加载的程序,可以理解为目标程序的归档。

2.2动态库:*.dll,可以被应用程序加载的程序。

 

 二 动态库

1动态库优点

 1.1可以提供模块化的方式,方便协调开发(对于大项目,每个人写的东西编译为动态库,直接链接即可)

 1.2对源代码保护

 1.3减小可执行文件大小

 1.4提高代码重用率


2动态库的基本使用方法

 2.1动态库的创建

 2.2加载动态库

 2.3获取并使用库函数、变量或类

 2.4释放动态库


3动态库的函数

 3.1动态库的创建

   3.1.1创建DLL项目

     创建Win32Dll项目,创建DLL项目,添加*.cpp文件。

  


  

3.1.2增加动态库函数


    3.1.3导出动态库函数(告诉使用者动态库中可提供的函数,代码示例如上)


     (1)使用__declspec(dllexport)方式,在函数前增加关键字。举例如下:

  1. __declspec(dllexport) intDll_Add(intnLeft,intnRight){  
  2.   
  3.       return(nLeft + nRight);  
  4.   
  5. }//C++方式导出  

     (2)增加extern “C”方式,举例如下

  1. extern"C" __declspec(dllexport)//  以C语言方式导出函数  

                    (3)使用def方式导出(在项目中添加*.def文件)


 //*.def文件中信息


   LIBRARY dllfunc.dll //导出库


   EXPORTS        //导出表


     Dll_Mul @1   //导出函数


     Dll_Div @2

 (VC6中def导出方式与 extern “C”导出方式导出.lib文件内容基本相同,可用于显式链接)

 

  动态库导出函数代码示例如下:

  1. #include<Windows.h>  
  2. #include <iostream>  
  3.   
  4. using namespace std;  
  5.   
  6. BOOL WINAPI DllMain(//返回值代表是否记载成功  
  7.     HINSTANCE hinstDll,//DLL句柄  
  8. DWORD   fdwReason,//DLL被调用的原因  
  9. LPVOID  lpvReserved)//保留值  
  10. {  
  11.     cout << "DLL = " << hinstDll << endl;  
  12.     cout << "fdwReason = " << fdwReason << endl;  
  13.     return TRUE;      
  14. }  
  15.   
  16.   
  17.   
  18. //C++导出方式  
  19. extern "C" __declspec (dllexport)  int Dll_Add(int nLeft, int nRight)  
  20. {  
  21.     return (nLeft + nRight);  
  22. }  
  23.   
  24.   
  25. //C的导出方式  
  26. extern "C"__declspec (dllexport)  int Dll_Sub(int nLeft, int nRight)  
  27. {  
  28.     return (nLeft - nRight);  
  29. }  
  30.   
  31. //DEF导出方式  
  32.   
  33. int Dll_Mul(int nLeft, int nRight)  
  34. {  
  35.     return (nLeft * nRight);  
  36. }  

    3.2 使用

   3.2.1隐式链接


     (1)导入lib


      a.在项目属性->链接器->输入->附加依赖项中设置即可。


      b.使用#pragma导入,举例如下:


 

  1. #pragma comment (lib,"../lib/Dll_Func.lib")  

      

    (2) 定义函数原型

        声明一个和导出函数一致的函数原型,如下所示:

  1. #pragma comment (lib,"../lib/Dll_Func.lib")  
  2.   
  3.  extern "C" int  Dll_Add(int nLeft, int nRight);  
  4.  extern "C" int  Dll_Sub(int nLeft, int nRight);  

   

    (3) 使用函数(注意:生成.dll文件最好与调用其的.exe文件在同一个目录)

        直接使用函数即可,示例代码如下:

  1. #include <cstdio>  
  2.   
  3. #pragma comment (lib,"../lib/Dll_Func.lib")  
  4.   
  5. extern "C" int  Dll_Add(int nLeft, int nRight);  
  6. extern "C" int  Dll_Sub(int nLeft, int nRight);  
  7. int Dll_Mul(int nLeft, int nRight);  
  8. int main()  
  9. {  
  10.     int nAdd = Dll_Add(100, 100);  
  11.     int nSub = Dll_Sub(100, 100);  
  12.     int nMul = 0;//Dll_Mul(100, 100);  
  13.     printf("nAdd = %d\n", nAdd);  
  14.     printf("nSub = %d \n", nSub);  
  15.     printf("nMul = %d \n", nMul);  
  16.     return 0;  
  17. }  

        (4) 应用程序查找Dll路径(最好将要调用的动态库与调用动态库的.exe文件放在同一目录下)

        A查找当前应用程序的目录


        B当前工作目录


        C查找Windows System32目录


        D查找Windows System的目录


        E查找Windows目录


        F查找环境变量Path指定的目录


   3.2.2显式链接

     (1)加载动态库

  1. LoadLibraryW(  
  2.              LPCSTR lpLibFileName  //DLL文件路径  
  3.           );  

    

     (2) 定义函数原型对应的函数指针


     (3)获取函数地址

  1. FARPROC  GetProcAddress(//返回对应函数地址  
  2.   
  3.     HMODULE hModule, // DLL句柄  
  4.   
  5.     LPCSTR lpProcName);//函数名称  

     注意: a.__declspec(dllexport)导出的函数由于函数名称发生变化,所以无法使用函数名称获取对应函

                 数地址,所以尽量采用隐式链接的方式。

            b. extern “C”__declspec(dllexport)方式导出的函数可以正常使用函数名称获取函数地址。

            c.使用def导出方式在VC6.0下可使用显示链接(本人在VS2013中对def导出方式导出动态库未成功使

              用,希望哪位大神可以指点迷津)


     (4)使用函数


     (5)释放动态库

  1. FreeLibrary(HMOUDLE)  

         显式链接示例代码如下:

  1. #include <iostream>  
  2. #include <Windows.h> /  
  3. #include <tchar.h>  
  4.   
  5. using namespace std;  
  6.   
  7. typedef int(*DLL_ADD)(int nLeft, int nRight);  
  8. typedef int(*DLL_SUB)(int nLeft, int nRight);  
  9. typedef int(*DLL_MUL)(int nLeft, int nRight);  
  10.   
  11. void useDll()  
  12. {  
  13.     HMODULE  hDll = LoadLibrary(_T("Dll_Func.dll"));  
  14.     if (nullptr == hDll)  
  15.     {  
  16.         cout << "Load Failed!" << endl;  
  17.         return;  
  18.     }  
  19.     //定义函数指针  
  20.     DLL_ADD Dll_Add = nullptr;  
  21.     DLL_SUB Dll_Sub = nullptr;  
  22.     DLL_MUL Dll_Mul = nullptr;  
  23.   
  24.     //获取函数地址  
  25.   
  26.     Dll_Add = (DLL_ADD)GetProcAddress(hDll, "Dll_Add");  
  27.     if (nullptr == Dll_Add)  
  28.     {  
  29.         cout << "Get Dll_Add Failed!" << endl;  
  30.     }  
  31.     cout << Dll_Add << endl;  
  32.     Dll_Sub = (DLL_SUB)GetProcAddress(hDll, "Dll_Sub");  
  33.     if (nullptr == Dll_Sub)  
  34.     {  
  35.         cout << "Get Dll_Sub Failed!" << endl;  
  36.     }  
  37.     cout << Dll_Sub << endl;  
  38.     Dll_Mul = (DLL_MUL)GetProcAddress(hDll, "Dll_Mul");  
  39.     if (nullptr == Dll_Mul)  
  40.     {  
  41.         cout << "Get Dll_Mul Failed!" << endl;  
  42.     }  
  43.     cout << Dll_Mul << endl;  
  44.       
  45.     //使用函数  
  46.     int nSub = Dll_Sub(100, 100);  
  47.     int nAdd = Dll_Add(100, 100);  
  48.     cout << "Add = " << nAdd << endl;  
  49.     cout << "Sub = " << nSub << endl;  
  50.   
  51.   
  52.     //释放动态库  
  53.     FreeLibrary(hDll);  
  54. }  
  55.   
  56. int main()  
  57. {  
  58.     useDll();  
  59.     return 0;  
  60. }  

 

 4.动态库中的变量


4.1定义全局变量


4.2导出全局变量


 4.2.1  __declspec(dllexport)导出


 4.2.2 DEF导出

   Int g_nValue1 = 100;

   DEF文件中到处列表增加 g_nValue1 @1 DATA


4.3导入LIB文件


4.4声明导入变量

 需要使用__declspec(dllimport)声明变量,举例如下:

 extern__declspec(dllimport)int g_nValuel;


4.5使用变量


 动态库变量使用代码示例如下:

  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4. #pragma comment(lib,"../lib/DllValue.lib")  
  5.   
  6. //声明DLL导入变量  
  7. extern __declspec(dllimport) int g_nValue1;//动态库导出文件中有此全局变量,在此再次声明此变量原型  
  8.   
  9. int main()  
  10. {  
  11.     cout << "g_nValue1 = " << g_nValue1 << endl;  
  12.     return 0;  
  13. }  

 

 5动态库的类导出



5.1创建静态库并定义类



5.2导出类


 在类名称前__declspec(dllexport)定义:


  class__declspec(dllexport)Math


   {……}

 

  导出类示例代码如下:

  1. //**.h文件  
  2. #ifndef _MATH_H_  
  3. #define _MATH_H_  
  4.   
  5. //定义类导入导出宏,  
  6. #ifdef _DLLCLASS_DLL__  
  7. #define DLLCLASS_EXT  __declspec(dllexport)  
  8. #else     
  9. #define DLLCLASS_EXT  __declspec(dllimport)  
  10. #endif //_DLLCLASS_DLL_  
  11.   
  12. //增加类的导入 导出符号  
  13. class DLLCLASS_EXT Math  
  14. {  
  15. public:  
  16.   
  17.     Math()  
  18.     {  
  19.     }  
  20.   
  21.     virtual ~Math()  
  22.     {  
  23.     }  
  24.   
  25.     int Add(int nLeft, int nRight);  
  26.     int Sub(int nLeft, int nRight);  
  27. };  
  28.   
  29. #endif  

  1. //**.cpp文件  
  2. #include "Math.h"  
  3.   
  4.   
  5. int Math::Add(int nLeft, int nRight)  
  6. {  
  7.     return (nLeft + nRight);  
  8. }  
  9. int Math::Sub(int nLeft, int nRight)  
  10. {  
  11.     return (nLeft - nRight);  
  12. }  

5.3使用时导入LIB文件


5.4导入类


5.5使用类


5.6关于类的导入和导出

 5.6.1定义一个宏,举例如下(避免多次编写类头文件,使之可在导出、导入时使用同一个头文件):

     

  1. #ifdef_DLLCLASS_DLL__  
  2.    
  3. #defineDLLCLASS_EXT __declspec(dllexport)  
  4.    
  5. #else    
  6.    
  7. #define DLLCLASS_EXT  __declspec(dllimport)  
  8.    
  9. #endif//_DLLCLASS_DLL_  




 5.6.2 根据编译项目修改_DLLCLASS_DLL__宏声明,对于导出类,需定义_DLLCLASS_DLL__,否则,不需要定义  _DLLCLASS_DLL__

 在导出类时,项目设置如下(即定义_DLLCLASS_DLL__):


 


  6 DllMain函数(用于变量初始化等操作。使用可参照3.1.3 (3)中示例代码)


 Dll文件的入口函数,当程序加载或者释放动态库的时候,会自动调用此函数


 BOOL WINAPIDllMain(//返回值代表是否加载成功

     HINSTANCE hinstDll;//DLL句柄

     DWORD  fdwReason;//DLL被调用的原因

     LPVOID lpvReserved;)//保留值


    FdwReason –

      DLL_PROCESS_ATTACH   进程加载

      DLL_THREAD_ATTACH    线程加载

      DLL_PROCESS_DETACH   进程卸载

      DLL_THREAD_DETACH    线程卸载


   使用导出类代码示例如下:

 

  1. #include <iostream>  
  2. #include "..\DllClass\Math.h"  
  3. using namespace std;  
  4.   
  5. #pragma comment(lib,"../lib/DllClass.lib")  
  6.   
  7. int main(int argc, char *argv[])  
  8. {  
  9.     Math math;  
  10.     int add = math.Add(100,100);  
  11.     int sub = math.Sub(100,100);  
  12.     cout << "Add = " << add << endl;  
  13.     cout << "Sub = " << sub << endl;  
  14.     return 0;  
  15. }  


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Windows下静态库、动态库的创建和调用过程
VC++6.0生成动态库并使用
C 静态库(lib)及动态库(dll)的创建及调用
declspec(dllexport)和declspec(dllimport) 的使用说明
lib 和 dll 的区别、生成以及使用详解
标准Dll文件.返回字符串
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服