首页 > 代码库 > C/C++ (函数、变量和类)动态库的创建、导出和使用(图文+示例代码)

C/C++ (函数、变量和类)动态库的创建、导出和使用(图文+示例代码)



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)方式,在函数前增加关键字。举例如下:

__declspec(dllexport) intDll_Add(intnLeft,intnRight){

      return(nLeft + nRight);

}//C++方式导出

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

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

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


 //*.def文件中信息


   LIBRARY dllfunc.dll //导出库


   EXPORTS        //导出表


     Dll_Mul @1   //导出函数


     Dll_Div @2

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

 

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

#include<Windows.h>
#include <iostream>

using namespace std;

BOOL WINAPI	DllMain(//返回值代表是否记载成功
	HINSTANCE hinstDll,//DLL句柄
DWORD   fdwReason,//DLL被调用的原因
LPVOID  lpvReserved)//保留值
{
	cout << "DLL = " << hinstDll << endl;
	cout << "fdwReason = " << fdwReason << endl;
	return TRUE;	
}



//C++导出方式
extern "C" __declspec (dllexport)  int Dll_Add(int nLeft, int nRight)
{
	return (nLeft + nRight);
}


//C的导出方式
extern "C"__declspec (dllexport)  int Dll_Sub(int nLeft, int nRight)
{
	return (nLeft - nRight);
}

//DEF导出方式

int Dll_Mul(int nLeft, int nRight)
{
	return (nLeft * nRight);
}

    3.2 使用

   3.2.1隐式链接


     (1)导入lib


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


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


 

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

      

    (2) 定义函数原型

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

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

     extern "C" int  Dll_Add(int nLeft, int nRight);
     extern "C" int  Dll_Sub(int nLeft, int nRight);

   

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

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

#include <cstdio>

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

extern "C" int  Dll_Add(int nLeft, int nRight);
extern "C" int  Dll_Sub(int nLeft, int nRight);
int Dll_Mul(int nLeft, int nRight);
int main()
{
	int nAdd = Dll_Add(100, 100);
	int nSub = Dll_Sub(100, 100);
	int nMul = 0;//Dll_Mul(100, 100);
	printf("nAdd = %d\n", nAdd);
	printf("nSub = %d \n", nSub);
	printf("nMul = %d \n", nMul);
	return 0;
}

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

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


        B当前工作目录


        C查找Windows System32目录


        D查找Windows System的目录


        E查找Windows目录


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


   3.2.2显式链接

     (1)加载动态库

  LoadLibraryW(
               LPCSTR lpLibFileName  //DLL文件路径
            );

    

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


     (3)获取函数地址

          FARPROC  GetProcAddress(//返回对应函数地址

              HMODULE hModule, // DLL句柄

              LPCSTR lpProcName);//函数名称

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

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

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

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

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


     (4)使用函数


     (5)释放动态库

        FreeLibrary(HMOUDLE)

         显式链接示例代码如下:

#include <iostream>
#include <Windows.h> /
#include <tchar.h>

using namespace std;

typedef int(*DLL_ADD)(int nLeft, int nRight);
typedef int(*DLL_SUB)(int nLeft, int nRight);
typedef int(*DLL_MUL)(int nLeft, int nRight);

void useDll()
{
	HMODULE  hDll = LoadLibrary(_T("Dll_Func.dll"));
	if (nullptr == hDll)
	{
		cout << "Load Failed!" << endl;
		return;
	}
	//定义函数指针
	DLL_ADD Dll_Add = nullptr;
	DLL_SUB Dll_Sub = nullptr;
	DLL_MUL Dll_Mul = nullptr;

	//获取函数地址

	Dll_Add = (DLL_ADD)GetProcAddress(hDll, "Dll_Add");
	if (nullptr == Dll_Add)
	{
		cout << "Get Dll_Add Failed!" << endl;
	}
	cout << Dll_Add << endl;
	Dll_Sub = (DLL_SUB)GetProcAddress(hDll, "Dll_Sub");
	if (nullptr == Dll_Sub)
	{
		cout << "Get Dll_Sub Failed!" << endl;
	}
	cout << Dll_Sub << endl;
	Dll_Mul = (DLL_MUL)GetProcAddress(hDll, "Dll_Mul");
	if (nullptr == Dll_Mul)
	{
		cout << "Get Dll_Mul Failed!" << endl;
	}
	cout << Dll_Mul << endl;
	
	//使用函数
	int nSub = Dll_Sub(100, 100);
	int nAdd = Dll_Add(100, 100);
	cout << "Add = " << nAdd << endl;
	cout << "Sub = " << nSub << endl;


	//释放动态库
	FreeLibrary(hDll);
}

int main()
{
	useDll();
	return 0;
}


 

 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使用变量


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

#include <iostream>

using namespace std;
#pragma comment(lib,"../lib/DllValue.lib")

//声明DLL导入变量
extern __declspec(dllimport) int g_nValue1;//动态库导出文件中有此全局变量,在此再次声明此变量原型

int main()
{
	cout << "g_nValue1 = " << g_nValue1 << endl;
	return 0;
}

 

 5动态库的类导出



5.1创建静态库并定义类



5.2导出类


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


  class__declspec(dllexport)Math


   {……}

 

  导出类示例代码如下:

//**.h文件
#ifndef _MATH_H_
#define _MATH_H_

//定义类导入导出宏,
#ifdef _DLLCLASS_DLL__
#define DLLCLASS_EXT  __declspec(dllexport)
#else   
#define DLLCLASS_EXT  __declspec(dllimport)
#endif //_DLLCLASS_DLL_

//增加类的导入 导出符号
class DLLCLASS_EXT Math
{
public:

	Math()
	{
	}

	virtual ~Math()
	{
	}

	int Add(int nLeft, int nRight);
	int Sub(int nLeft, int nRight);
};

#endif

//**.cpp文件
#include "Math.h"


int Math::Add(int nLeft, int nRight)
{
	return (nLeft + nRight);
}
int Math::Sub(int nLeft, int nRight)
{
	return (nLeft - nRight);
}

5.3使用时导入LIB文件


5.4导入类


5.5使用类


5.6关于类的导入和导出

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

     

#ifdef_DLLCLASS_DLL__
 
#defineDLLCLASS_EXT __declspec(dllexport)
 
#else  
 
#define DLLCLASS_EXT  __declspec(dllimport)
 
#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    线程卸载


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

 

#include <iostream>
#include "..\DllClass\Math.h"
using namespace std;

#pragma comment(lib,"../lib/DllClass.lib")

int main(int argc, char *argv[])
{
	Math math;
	int add = math.Add(100,100);
	int sub = math.Sub(100,100);
	cout << "Add = " << add << endl;
	cout << "Sub = " << sub << endl;
	return 0;
}


C/C++ (函数、变量和类)动态库的创建、导出和使用(图文+示例代码)