dll知识

本文探讨了C++中DLL的显式加载技术及名字改编问题,介绍了如何避免不同编译器间因名字改编导致的不兼容性问题,并提供了显式加载DLL的具体实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++动态链接库(dll)(二)

C++学习 2010-05-11 16:26:03 阅读103 评论0   字号: 订阅

 

(一)名字改编问题:

C++编译器生成DLL时,会对导出的函数进行名字改编,由于编译器采用的改编原则是不一样的,因此改编后的名字也是不一样的。这样如果利用不同的编译器分别生成DLL和访问该DLL的客户端程序的话,后者在访问该DLL的导出函数时会出现问题。

当希望动态链接库文件在编译时,导出函数的名称不要发生改变,可在定义导出函数时,需要加上限定符:extern “C”。还是以Dll1和DllTest为例。

Dll1.h如下:

#ifdef DLL1_API

#else

#define DLL1_API extern "C" _declspec(dllimport)

#endif

 

DLL1_API int add(int a,int b);

DLL1_API int subtract(int a,int b);

Dll1.cpp如下:

#define DLL1_API extern "C" _declspec(dllexport)

#include"Dll1.h"

#include<Windows.h>

#include<stdio.h>

 

int add(int a,int b)

{

    return a+b;

}

int subtract(int a,int b)

{

    return a-b;

}

则利用dumpbin命令查看可看到导出的函数名为add和subtract,但这种方法有一个缺陷,就是不能用于导出一个类的成员函数,只能用于导出全局函数这种情况,所以Dll1里的类定义被注释掉了。另外,如果导出函数的调用约定发生了改变,这种方法也会失效的。一种万全的方法是定义一个模块定义文件(.def)文件,在项目——>添加新项中选择添加def文件即可,然后在其中输入:

LIBRARY DLL1

 

EXPORTS

add

subtract

当链接器分析def文件时发现EXPORTS语句下有add和subtract这两个符号名,并且和源文件中定义的add和subtract函数的名字是一样的时候,它就会以add和subtract这两个符号名导出相应的函数。如果要导出的符号名和源文件定义的函数名不一样,则可以按照下述语法导出:

entryname=internalname

entryname是要导出的符号名,internalname是DLL中将要导出的函数的名字。

(二)显式加载DLL:

显式加载DLL,也即动态加载DLL时,客户端程序不再需要包含导出函数声明的头文件(.h)和引入库文件(.lib),只需要.dll文件即可。显式加载最主要有两个函数,分别是LoadLibrary和GetProcAddress,声明如下:

HMODULE LoadLibrary(LPCTSTR lpFileName);

FARPROC GetProcAddress(HMODULE hModule,LPCTSTR lpProcName);

LoadLibrary可以加载DLL,也可以加载可执行模块(.exe),返回的是加载的模块的句柄,注意HMODULE和HINSTANCE是可以通用的。

GetProcAddress中,hModule是动态链接库模块的句柄,lpProcName是要导出的函数的名字,当然也可以是序号,序号则需要用到MAKEINTRESOURCE宏,该宏会把指定的函数序号转换为相应的函数名字字符串,如上例,MAKEINTRESOURCE(1)表示函数add,要查看函数的序号可以用dumpbin命令中的exports选项查看。下面给出一个调用的例子:

{

HINSTANCE hInst;

    hInst=LoadLibrary(_T("Dll3.dll"));      //动态加载DLL

    typedef int (*ADDPROC)(int a,int b);          //定义函数指针类型

    ADDPROC Add=(ADDPROC)GetProcAddress(hInst,”add”);

    //也可以用(ADDPROC Add=(ADDPROC)GetProcAddress(hInst,(LPCSTR)MAKEINTRESOURCE(1));)

    if(!Add)

    {

         MessageBox(_T("获取函数地址失败!"));

         return;

    }

    CString str;

    str.Format(_T("5+3=%d"),Add(5,3));

    MessageBox(str);

    FreeLibrary(hInst);

}

上述代码中定义了一个函数指针类型:ADDPROC,用来接收通过GetProcAddress返回的函数地址,当然定义要根据导出的函数进行定义,由于GetProcAddress返回的是FARPROC类型,需要强制转换。另外注意的是,当不再需要访问该DLL时,必须调用FreeLibrary函数释放对该DLL的引用。一般地,使用动态加载效率更高。

以上是学习孙鑫老师的《VC++深入详解》相关内容后的笔记。接下来打算解决的问题是dll的搜索顺序和字符的区分和转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值