c++动态加载dll

今天尝试写了一个简单的C++DLL,并且用另一个CPP调用它,啥都不说,先贴代码

1.DLL(冒泡算法)

extern "C"_declspec(dllexport) void maopao(int *p,int count);
void maopao(int *p,int count)
{ int temp=0;
  for(int i=1;i<count;i++)
  {for(int j=count-1;j>=i;j--)
  { if(p[j]>p[j-1])
  {temp=p[j];
    p[j]=p[j-1];
    p[j-1]=temp;
  }
  }
  }
}

2.调用DLL

#include<iostream>
#include<Windows.h>
#include<time.h>
typedef int(*Dllfun)(int *,int);
using namespace std;
int main()
{ Dllfun maopao1;
  HINSTANCE hdll;
  hdll=LoadLibrary("D:\\net源码\\maopaoa_dll\\Debug\\maopaoa_dll.dll");
  if(hdll==NULL)
  {FreeLibrary(hdll);
  }
  maopao1=(Dllfun)GetProcAddress(hdll,"maopao");
  if(maopao1==NULL)
  {FreeLibrary(hdll);
  }
  int a[10];
  srand(time(0));
  for(int i=0;i<10;i++)
      a[i]=rand()%50;
  maopao1(a,10);
   for(int i=0;i<10;i++)
       cout<<a[i]<<endl;

   FreeLibrary(hdll);

}

C++如何调用DLL呢,有两种,一种是静态,另外一种是动态,即通过调用windowsAPI 来加载和卸载DLL,具体思路:

1.先编写一个DLL,我这里是直接在CPP里编写了函数声明和定义,没有单独的头文件,因为很多情况下的DLL都是没有和lib和头文件一起的。

2.然后另外新建一个项目,来调用DLL,方法是:

1.声明头文件<windows.h>,说明我想用windows32方法来加载和卸载DLL

2.然后用typedef定义一个指针函数类型.typedef  void(*fun) //这个指针类型,要和你调用的函数类型和参数保持一致,记住,是指针参数就是(int *,int)

3.定一个句柄实例,用来取DLL的实例地址。HINSTANCE hdll;

格式为hdll=LoadLibrary(“DLL地址”);这里字符串类型是LPSTR,当是unicode字符集的时候会不行,因此要在配置-属性-常规里面把默认字符集“unicode”改成支持多字符扩展即可。

4.取的地址要判断,返回的句柄是否为空,如果为无效句柄,那么要释放加载DLL所占用的内存。

FreeLibrary(hdll);

5.然后定义一个函数指针,用来获取你要用的函数地址,这个咋用呢?

先是定一个函数指针 fun FUN;然后通过GetProcAdress来获取函数的地址,这个函数参数是什么呢?

参数是DLL的句柄和你要调用的函数名:比如:FUN=(fun)GetProcAdress(hdll,"sum");

这里也要判断要函数指针是否为空,如果没取到要求的函数,那么要释放句柄

FreeLibrary(hdll);

6.然后通过函数指针来调用函数。

FUN(int *p,int count);这里不能用函数名来使用函数,因为这个DLL本身不是当前CPP的一部分,而是通过windows去调用.没有在这个工程里声明或者定义,而是暴露出一个头,要指针获取他的地址,通过指针来调用.

最后调用结束后,就释放句柄

FreeLibrary(hdll);

这里只是通过动态加载没有涉及到静态的。这个在后续会学习。



原文链接:http://www.cnblogs.com/lhbssc/archive/2012/02/08/2342853.html

<think>嗯,用户让我介绍一下C++动态加载DLL。我需要先回忆一下相关知识,确保自己理解正确。动态链接库(DLL)在Windows中很常见,动态加载指的是在运行时根据需要加载库,而不是在编译时链接。这样做的优点是可以灵活控制资源,比如插件系统。 首先,应该解释动态加载和静态加载的区别。静态加载是在编译时链接,而动态加载是在运行时通过API函数来加载动态加载的关键步骤包括使用LoadLibrary加载DLL,GetProcAddress获取函数指针,最后用FreeLibrary释放。 需要提到Windows API中的几个关键函数:LoadLibrary、GetProcAddress、FreeLibrary。可能还需要给出一个简单的代码示例,比如加载一个DLL中的函数并调用。要注意跨平台的问题,比如Linux下使用dlopen、dlsym等,但用户问的是C++,可能主要关注Windows环境。 另外,要提醒注意事项,比如函数调用约定(__stdcall或__cdecl),避免名称修饰(extern "C"),以及错误处理。可能用户需要知道如何正确声明函数指针,以及如何处理可能出现的加载或获取函数失败的情况。 还有,动态加载的应用场景,比如插件系统、按需加载模块以减少内存占用,或者支持不同版本的库。用户可能想知道为什么选择动态加载而不是静态链接,这里需要强调灵活性和资源管理的优势。 需要检查是否有遗漏的步骤,比如导出函数的声明方式,在DLL中需要使用__declspec(dllexport),而在调用方需要使用__declspec(dllimport)或者直接通过指针调用。但动态加载的情况下,通常是通过GetProcAddress直接获取函数地址,所以可能不需要导入声明。 还要注意Unicode和多字节字符集的问题,比如LoadLibraryA和LoadLibraryW的区别,建议使用TEXT宏或者宽字符串处理。 最后,代码示例部分应该尽可能简单明了,展示加载DLL、获取函数、调用、释放的过程。同时要指出可能出现的错误点,比如路径问题、函数名错误等。可能还需要提到使用依赖查看工具检查导出函数名称是否正确,避免因为名称修饰导致找不到函数。 总结一下,回答的结构应该是:动态加载的概念,与静态加载的区别,详细步骤(加载、获取函数、调用、释放),代码示例,注意事项,应用场景。需要确保术语准确,示例正确,注意事项全面。</think>C++ 动态加载 DLL动态链接库)是一种在运行时按需加载和调用外部代码的技术。与静态链接不同,它允许程序在运行时灵活决定加载哪些模块,常用于插件系统、模块化设计等场景。以下是核心知识点和步骤: --- ### **1. 核心步骤** #### (1) **加载 DLL** 使用 Windows API `LoadLibrary` 或 `LoadLibraryEx`: ```cpp HMODULE hDll = LoadLibrary(TEXT("MyLibrary.dll")); if (!hDll) { DWORD error = GetLastError(); // 处理加载失败 } ``` #### (2) **获取函数指针** 使用 `GetProcAddress` 获取导出函数地址: ```cpp typedef int (*AddFunc)(int, int); // 定义函数指针类型 AddFunc add = (AddFunc)GetProcAddress(hDll, "Add"); if (!add) { // 处理函数未找到 } ``` #### (3) **调用函数** 通过函数指针调用: ```cpp int result = add(3, 5); // 调用 DLL 中的 Add 函数 ``` #### (4) **卸载 DLL** 使用 `FreeLibrary` 释放资源: ```cpp FreeLibrary(hDll); ``` --- ### **2. DLL 导出函数的声明** 在 DLL 代码中,需用 `__declspec(dllexport)` 显式导出函数: ```cpp // MyLibrary.cpp extern "C" __declspec(dllexport) int Add(int a, int b) { return a + b; } ``` --- ### **3. 关键注意事项** - **名称修饰问题**: 使用 `extern "C"` 避免 C++ 函数名被编译器修饰(如 `Add` 可能变成 `?Add@@YAHHH@Z`)。 - **调用约定**: 确保调用约定(如 `__stdcall` 或 `__cdecl`)一致,否则会导致栈损坏。 - **路径问题**: DLL 需位于程序工作目录、系统目录或 `LoadLibrary` 指定的完整路径。 - **错误处理**: 检查 `LoadLibrary` 和 `GetProcAddress` 的返回值,用 `GetLastError()` 获取错误码。 --- ### **4. 动态加载 vs 静态加载** | **特性** | **动态加载** | **静态加载** | |----------------|---------------------------|---------------------------| | 链接时机 | 运行时加载 | 编译时链接 | | 资源占用 | 按需加载,节省内存 | 全部链接,占用较多内存 | | 灵活性 | 支持热插拔、插件化 | 代码固定 | | 依赖管理 | 需手动管理 DLL 文件 | 自动处理依赖 | --- ### **5. 典型应用场景** - **插件系统**:允许第三方开发者扩展程序功能。 - **按需加载**:减少程序启动时间,仅在需要时加载模块。 - **多版本兼容**:运行时选择不同版本的 DLL。 --- ### **6. 跨平台替代方案** - **Linux/macOS**:使用 `dlopen`、`dlsym`、`dlclose`。 - **通用方案**:封装平台相关代码,或使用跨平台库(如 Boost.DLL)。 --- 通过动态加载 DLLC++ 程序可以实现高度模块化和灵活性,但需谨慎处理函数签名、内存管理和错误检测,以避免运行时崩溃。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值