c源码编译dll-VC++MFCDLL动态链接库的编译与解释

这是导入类的最简单的方法,你也可以使用.def文件来导入它们,所以我们在这里不讨论它们。

2.导出变量、常量和对象

很多时候不需要导入一个类,可以让DLL导入一个变量、常量、对象,导入它们只需要做一个简单的声明:_declspec(dllexport)intMyInt;

_declspec(dllexport)externconstCOLORREFMyColor=RGB(0,0,0);

_declspec(dllexport)CRectrect(10,10,20,20);

导入常量时必须使用关键字extern,否则会出现链接错误。

注意:如果客户端程序识别该类并且有自己的头文件,则只能导入一个类对象。 如果在DLL中创建类,那么如果不使用头文件,客户端程序将很难识别该类。

导入对象或变量时,加载 DLL 的每个客户端程序都有自己的副本。 也就是说,如果两个程序使用相同的 DLL,则一个应用程序所做的更改不会影响另一应用程序。

当我们导入时,只能导入DLL中的全局变量或对象,而不能导入局部变量和对象,因为它们在经过作用域后就不再存在,因此DLL将无法正常工作。 喜欢:

我的函数()

_declspec(dllexport)intMyInt;

_declspec(dllexport)CMyClass对象;

3.导出功能

导入函数与导入变量/对象类似,只需在函数原型的开头添加 _declspec(dllexport) 即可:

_declspec(dllexport)intMyFunction(int);

如果是常规DLL,则与C编写的程序一起使用,声明方法如下:

extern "c"_declspec(dllexport) intMyFunction(int);

完成:

extern "c"_declspec(dllexport) intMyFunction(intx)

...//操作

c源码编译dll-VC++MFCDLL动态链接库的编译与解释

如果要创建动态链接到 MFC 代码库 DLL 的常规 DLL,则必须插入 AFX_MANAGE_STATE 作为导入函数的第一行,因此定义如下:

extern "c"_declspec(dllexport) intMyFunction(intx)

AFX_MANAGE_STATE(AfxGetStaticModuleState());

...//操作

有时,为了安全起见,将其添加到每个常规DLL中,不会有问题,但静态链接时该宏无效。 这是导入函数的方式,记住只有MFC扩展DLL才能使用MFC数据类型作为参数和返回值。

4.导出指针

导入指针的形式如下:

_declspec(dllexport)int*pint;

_declspec(dllexport)CMyClassobject=newCMyClass;

如果指针在声明的时候就被初始化了,那么就需要找一个合适的地方来释放指针。 扩展DLL中有一个函数DllMain()。 (注意,如果函数名中的两个ls都是大写字母),可以在这个函数中处理指针:

#include“MyClass.h”

_declspec(dllexport)CMyClass*pobject=newCMyClass;

DllMain(HINSTANCEhInstance,DWORDdwReason,LPVOIDlpReserved)

if(dwReason==DLL_PROCESS_ATTACH)

......//

elseif(dwReason==DLL_PROCESS_DETACH)

删除对象;

常规DLL有一个从CWinApp派生的类对象来处理DLL的打开和关闭,并且可以使用类向导添加InitInstance/ExitInstance函数。

intCMyDllApp::ExitInstance()

删除对象;

返回 CWinApp::ExitInstance();

3. 在客户程序中使用DLL

编译DLL将创建两个文件:.dll文件和.lib文件。 首先将这两个文件复制到客户端程序项目的文件夹中,这里需要注意DLL和客户端程序的版本,尽量使用相同的版本,都使用RELEASE或DEBUG版本。

然后需要在客户端程序中设置LIB文件c源码编译dll,打开ProjectSettings--->Link--->Object/libraryModules并输入LIB文件名和路径。 如:Debug/SampleDll.lib。 不仅DLL和LIB文件,客户端程序还需要头文件来导入类、函数、对象和变量。 现在导出添加的关键字为:_declspec(dllimport),如:

_declspec(dllimport)intMyFunction(int);

_declspec(dllimport)intMyInt;

_declspec(dllimport)CMyClass对象;

extern "C"_declspec(dllimport) intMyFunction(int);

有时为了导出一个类,必须在客户端程序中添加相应类的头文件,不同的是类声明的flag需要改变:

class_declspec(dllimport)CMyClass,如果创建扩展 DLL,两个位置都是:

类AFX_EXT_CLASSCMyClass。

使用 DLL 的一个更严重的问题是编译器之间的兼容性问题。 不同的编译器对 C++ 函数在补码级别的实现方法不同。 所以对于基于C++的DLL来说,如果编译器不同的话,就会很麻烦。 如果创建 MFC 扩展 DLL,则不会有问题,因为它只能动态链接到 MFC 客户端应用程序。 这不是本文的重点。

1.重新编译问题

我们先来看一个实际中可能遇到的问题:

例如,现在已经构建了一个DLL并导入到CMyClass类中,客户也可以正常使用这个DLL,假设CMyClass对象的大小是30字节。 如果我们需要将DLL中的CMyClass类更改为具有相同的函数和成员变量,并添加一个私有成员变量int类型,则CMyClass对象的大小现在为34字节。 当客户直接使用这个新的DLL来替换原来的30字节DLL时c源码编译dll,客户应用程序期望的是一个30字节的对象,但现在它是一个34字节的对象。 哎呀,客户程序出了问题。

类似的问题,如果不导入CMyClass类,而是在导入的函数中使用CMyClass,改变对象的大小仍然会出现问题。 这时,改变这个问题的唯一办法就是替换客户端程序中CMyClass的头文件,重新编译整个应用程序,让客户端程序使用大小为34字节的对象。

这是一个严重的问题,有时如果没有客户程序的源代码,那么我们就无法使用这个新的DLL。

二、解决办法

为了防止客户端程序重新编译,这里有两种方法: (1)使用socket类。 (2) 使用创建和销毁类的静态函数。

1.使用socket类

socket类是创建第二个类,作为socket导入类,这样当导入的类改变时,不需要重新编译客户端程序,因为socket类没有改变。

假设导入的CMyClass类有两个函数FunctionAFunctionB。 现在创建一个套接字类CMyInterface,以下是DLL中CMyInterface类的头文件的代码:

#include“MyClass.h”

class_declspec(dllexport)CMyInterface

CMyClass*pmyclass;

CMyInterface();

〜CMyInterface();

民众:

intFunctionA(int);

intFunctionB(int);

};

客户端程序中的头文件略有不同,并且不需要 INCLUDE 语句,因为客户端程序没有它的副本。 相反,使用 CMyClass 的前向声明,它无需头文件即可编译:

class_declspec(dllexport)CMyInterface

classCMyClass;//声明转发

CMyClass*pmyclass;

CMyInterface();

〜CMyInterface();

民众:

intFunctionA(int);

intFunctionB(int);

};

CMyInterface在DLL中的实现如下:

CMyInterface::CMyInterface()

pmyclass=newCMyClass();

CMyInterface::~CMyInterface()

删除我的类;

intCMyInterface::FunctionA()

returnpmyclass->FunctionA();

intCMyInterface::FunctionB()

returnpmyclass->FunctionB();

……

对于导入类 CMyClass 的每个成员函数,CMyInterface 类都提供了自己对应的函数。 客户端程序与CMyClass没有任何联系,所以随意改变CMyClass不会有问题,因为CMyInterface类的大小没有改变。 虽然向CMyInterface类添加函数以便能够访问CMyClass中的新变量并不是问题。

然而,这些技术也存在明显的问题。 导入类的每个函数和成员变量都必须相应实现,有时socket类会很大。 同时,减少了客户端程序调用所需的时间。 减少了程序开销。

2.使用静态函数

您还可以使用静态函数来创建和销毁类对象。 创建导入类时,减少两个静态公共函数CreateMe()/DestroyMe(),头文件如下:

class_declspec(dllexport)CMyClass

CMyClass();

~CMyClass();

民众:

staticCMyClass*CreateMe();

静态 voidDestroyMe(CMyClass*ptr);

};

实现函数为:

CMyClass*CMyClass::CMyClass()

返回新CMyClass;

voidCMyClass::DestroyMe(CMyClass*ptr)

删除;

然后像其他类一样导入CMyClass类。 这时,在客户端程序中使用该类的方式就略有不同。 例如,如果您创建一个 CMyClass 对象,它应该是:

CMyClassx;

CMyClass*ptr=CMyClass::CreateMe();

使用后删除:

CMyClass::DestroyMe(ptr);

- - - - - - - - - - - - - - - - - - - - - - - -结束 - -----------------------------------------------------------

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 c源码编译dll-VC++MFCDLL动态链接库的编译与解释 https://www.wkzy.net/game/168145.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务