Windows中的库编程(一、动态库介绍及如何导出全局函数)
Windows操作系统中,库分为动态链接库(dll)和静态链接库(lib)
动态库是Windows中实现代码共享的一种方式。它是一个二进制式文件,不可单独运行,需要调用方调用才能运行。在Windows中,动态库可以被多种编程语言所支持。
静态链接库不同于动态链接库(dll),在静态库情况下,函数和数据被编译进一个二进制 文件(通常扩展名为*.lib),Visual C++的编译器在链接过程中将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为"静态链接",此时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。
使用动态库有以下好处:
1、有利于代码和数据的共享
2、有利于模块化开发
3、有利于软件升级
4、代码保护
动态链接库又分为Win32动态链接库和MFC动态链接库。区别就是是否使用了MFC类
Win32 DLL编程
如何导出Win32 DLL
1、通过关键字_declspec(dllexport导出)
新建一个C++ dll工程 DllExportTest
新建一个DllExportTest..h文件
输入
1 #pragma once 2 3 __declspec(dllexport) void PrintHelloWorld();
在DllExportTest.cpp中输入
1 #include "stdafx.h" 2 #include"DllExportTest.h" 3 #include<iostream> 4 5 using namespace std; 6 7 void PrintHelloWorld() 8 { 9 cout << "HelloWorld" << endl; 10 }
2、通过模块定义文件导出
新建一个C++ dll工程 DllExportWithDEFTest
新建一个DllExportWithDEFTest.h,输入
1 #pragma once 2 3 void PrintHelloWorld();
在DllExportWithDEFTest.cpp中输入
1 #include "stdafx.h" 2 #include"DllExportWithDEFTest.h" 3 #include<iostream> 4 5 using namespace std; 6 7 void PrintHelloWorld() 8 { 9 cout << "HelloWorld" << endl; 10 }
然后在“源文件”上右键选择“添加新项”,选择“代码”->”模块定义文件(.def)“
.def常用格式如下
LIBRARY DllName //dll名字, DllName可以为空 DESCRIPTION DllDescription //dll 描述 这一行可以省略 EXPORTS FuncOrVariables //要导出的函数名或变量的名字
我在前面的代码中定义了PrintHelloWorld函数,要将它导出,可以这样定义.def文件
LIBRARY
EXPORTS
PrintHelloWorld
如果要将PrintHelloWorld函数导出为其它的名字,如MyFuncName,可以这样定义.def文件
LIBRARY
EXPORTS
MyFuncName = PrintHelloWorld
如何使用导出的函数
C#调用可以参考以下链接
https://www.cnblogs.com/zhaotianff/p/8991847.html
C++调用
分为隐式链接和显式链接两种方式
隐式链接
步骤如下
1、引入lib文件
2、引入头文件
3、调用dll中的数据
新建一个C++ 控制台程序 InvokeDll
打开项目的目录,建立lib和include文件夹(这个操作不是必须的,.h和.lib可以通过路径引用,不一定非要建立这样的文件夹,但这样操作会更好管理)
把前面生成的DllExportTest.lib拷到lib文件夹下,把DllExportTest.h拷到include文件夹下
然后在项目上单击右键,选择属性,依次选择配置属性-》链接器-》常规-》附加库目录。新建一个路径,选择刚才建立 的lib文件夹,单击确定
再选择输入-》附加依赖项,增加DllExportTest.lib
在InvokeDll.cpp中输入以下代码
1 #include "stdafx.h" 2 #include "include\DllExportTest.h" 3 4 5 int main() 6 { 7 PrintHelloWorld(); 8 return 0; 9 }
运行之后可以看到屏幕输出HelloWorld
隐式链接还有一种方式,使用指令#pragma comment来引用lib文件
新建一个C++控制台程序 InvokeDll_2
复制InvokeDll项目路径下的include和lib文件夹到InvokeDll_2的项目路径下,在InvokeDll_2.cpp中输入以下代码
1 #include "stdafx.h" 2 #include "./include/DllExportTest.h" 3 4 #pragma comment(lib,"./lib/DllExportTest.lib") 5 6 int main() 7 { 8 PrintHelloWorld(); 9 return 0; 10 }
运行之后也可以看到屏幕输出HelloWorld
显示链接主要是通过调用LoadLibrary、GetProcAddress、FreeLibrary这三个API函数来实现
LoadLibrary()
声明如下
HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName);
用于载入指定的动态链接库
GetProcAddress()
声明如下
FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );
用于检索指定的动态链接库中函数地址
FreeLibrary()
声明如下
BOOL FreeLibrary( HMODULE hLibModule );
用于释放指定的动态链接库
新建一个C++控制台程序 InvokeDllExplicitly,在InvokeDllExplicitly.cpp中输入以下代码
1 #include "stdafx.h" 2 #include <Windows.h> 3 4 typedef void(*MyFunc)(); //后面是函数签名部分,需要跟导出函数中的保持一致。这个函数没有参数,所以后面部分为空 5 6 int main() 7 { 8 HMODULE hDll = NULL; 9 MyFunc myFunc = NULL; 10 11 //加载库 12 hDll= LoadLibrary("./DllExportTest.dll"); 13 14 if (hDll) 15 { 16 //获取函数或变量的地址 17 myFunc =(MyFunc)GetProcAddress(hDll, "PrintHelloWorld"); 18 19 if (myFunc) 20 { 21 //调用函数 22 myFunc(); 23 } 24 } 25 26 //释放动态链接库 27 FreeLibrary(hDll); 28 29 return 0; 30 }
运行可以看到屏幕输出 HelloWorld