使用C++开发工程代码的时候,一般采取模块化设计来降低项目的复杂度。一个典型的C++工程,一般分为一个EXE工程作为主启动进程,若干个DLL工程提供各种不同的功能集合。今天我们通过一个具体的实例来看看DLL的二进制兼容性。
研究环境
编译环境:VS2010
主EXE工程:Win32控制台应用,名称Test
DLL工程:MFC共享DLL,名称Function
工程代码
主EXE工程
主EXE工程采用VS2010内置的Win32控制台应用模板,在主工程中的main函数中调用了DLL工程的导出方法MyAdd。
![a82e4f0518c2ebc537b38560f86e2702.png](https://i-blog.csdnimg.cn/blog_migrate/bab1c4bae377db8ee89e4eca8e50b58d.jpeg)
DLL工程
DLL工程采用VS2010内置的MFC共享DLL模板,在DLL工程中,我们定义并实现了一个导出方法MyAdd。这个方法的实现比较简单:接收两个整数,并返回这两个整数之和。
![90bfe967b4f61d7fa3237856a1e0f7ed.png](https://i-blog.csdnimg.cn/blog_migrate/23c5f431fc9ccdd807a2e0d95f5ff7df.jpeg)
第一种情况:主EXE工程调用DLL工程
分别编译EXE和DLL工程,执行EXE工程,可以得到以下结果:
![bf4d02c3b57fcadf33ea49e57dd9d0a8.png](https://i-blog.csdnimg.cn/blog_migrate/13c34c65fedc7341841d464fad46443a.jpeg)
在上述代码中,我们传入DLL方法了两个整数,10和20,DLL方法准确的返回了它们之和30。一切都是我们预期的。
第二种情况:DLL工程中的方法实现修改且主EXE工程不重新编译
我们将DLL工程实现代码进行修改,从计算两个整数之和修改为计算两个整数之乘积。
![da191f98d048a3ec5aa5a5df25da1c70.png](https://i-blog.csdnimg.cn/blog_migrate/dbbc753f24096125f24a9d4c9bcaf435.jpeg)
在只编译DLL工程的情况下,我们直接执行主EXE工程,看看执行结果:
![279cd6c2890f57b98bb00a9e03a22629.png](https://i-blog.csdnimg.cn/blog_migrate/a397ecc91d8edc52494036dc1eae603d.jpeg)
从执行结果来看,主EXE工程代码没有经过重新编译,但它”感知”到了DLL实现代码的变更,此场景我们认为:DLL的内部实现修改保持了其二进制的兼容性。
第三种情况:DLL工程中的方法声明修改且主EXE工程不重新编译
我们将DLL工程方法声明代码进行修改,从接收两个参数,我们修改为接收三个参数。
![65b6b610af45acf356f92ce3dbc4833a.png](https://i-blog.csdnimg.cn/blog_migrate/709798af1a58cd40aed0c1dadec6cc5b.jpeg)
在只编译DLL工程的情况下,再次执行主EXE工程,看看执行结果:
![fd3de84b72f19e895d59ebac5efc0ef4.png](https://i-blog.csdnimg.cn/blog_migrate/93ea96041bb38a9596b0e9bce4bef93e.jpeg)
我们看到,虽然DLL的参数增加了,但内部实现没有变更。但是主EXE工程在执行阶段提示找不到函数入口点,说明此时DLL工程的方法声明修改需要主EXE工程重新编译。此场景我们认为:DLL方法声明修改破坏了其二进制兼容性,任何DLL代码的方法声明的变更,其调用者必须重新编译。
结论
对于导出类C方法的DLL工程,当DLL内部实现代码变更时,DLL的调用者不需要重新编译。
对于导出类C方法的DLL工程,当DLL方法声明代码变更时,DLL的调用者需要重新编译。
![f5499dac58c91319c03e4354cccce5c5.png](https://i-blog.csdnimg.cn/blog_migrate/7393713b6c9cbd195359a5294baaf637.jpeg)