深度理解:Windows DLL 二进制兼容性探究

深度理解:Windows DLL 二进制兼容性探究

作者:BlogUpdater |  时间:2018-06-18 |  浏览:3806 |  评论已关闭 条评论

使用C++开发工程代码的时候,一般采取模块化设计来降低项目的复杂度。一个典型的C++工程,一般分为一个EXE工程作为主启动进程,若干个DLL工程提供各种不同的功能集合。今天我们通过一个具体的实例来看看DLL的二进制兼容性。

研究环境
编译环境:VS2010
主EXE工程:Win32控制台应用,名称Test
DLL工程:MFC共享DLL,名称Function

工程代码

主EXE工程
主EXE工程采用VS2010内置的Win32控制台应用模板,在主工程中的main函数中调用了DLL工程的导出方法MyAdd。

#include "stdafx.h"
#include "..\Function\Include.h"


int _tmain(int argc, _TCHAR* argv[])
{
	printf("%d + %d = %d", 10, 20, MyAdd(10, 20));

	getchar();
	return 0;
}

DLL工程
DLL工程采用VS2010内置的MFC共享DLL模板,在DLL工程中,我们定义并实现了一个导出方法MyAdd。这个方法的实现比较简单:接收两个整数,并返回这两个整数之和。

#include "stdafx.h"
#include "Include.h"

int MyAdd(int a, int b)
{
	return a + b;
}

第一种情况:主EXE工程调用DLL工程
分别编译EXE和DLL工程,执行EXE工程,可以得到以下结果:

在上述代码中,我们传入DLL方法了两个整数,10和20,DLL方法准确的返回了它们之和30。一切都是我们预期的。

第二种情况:DLL工程中的方法实现修改且主EXE工程不重新编译
我们将DLL工程实现代码进行修改,从计算两个整数之和修改为计算两个整数之乘积。

#include "stdafx.h"
#include "Include.h"

int MyAdd(int a, int b)
{
	return a * b;
}

在只编译DLL工程的情况下,我们直接执行主EXE工程,看看执行结果:

从执行结果来看,主EXE工程代码没有经过重新编译,但它”感知”到了DLL实现代码的变更,此场景我们认为:DLL的内部实现修改保持了其二进制的兼容性。

第三种情况:DLL工程中的方法声明修改且主EXE工程不重新编译
我们将DLL工程方法声明代码进行修改,从接收两个参数,我们修改为接收三个参数。

FUNCTION_API int MyAdd(int a, int b, int c);
int MyAdd(int a, int b, int c)
{
	return a + b;
}

在只编译DLL工程的情况下,再次执行主EXE工程,看看执行结果:

我们看到,虽然DLL的参数增加了,但内部实现没有变更。但是主EXE工程在执行阶段提示找不到函数入口点,说明此时DLL工程的方法声明修改需要主EXE工程重新编译。此场景我们认为:DLL方法声明修改破坏了其二进制兼容性,任何DLL代码的方法声明的变更,其调用者必须重新编译。

结论
对于导出类C方法的DLL工程,当DLL内部实现代码变更时,DLL的调用者不需要重新编译。
对于导出类C方法的DLL工程,当DLL方法声明代码变更时,DLL的调用者需要重新编译。

标签:

评论已关闭。