当我们兴冲冲把自己写的小程序传给朋友,亦或是正式发布产品到用户手中,时常会遇到“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”。
这么个提示实在是让人有点气馁啊,那么怎么解决呢,是什么导致这个问题呢?
(注意,本文不涉及msvc7.x,因为这个版本的两个主要产品我接触很少)
首先,静态链接所有库是不会遇到这个问题的,但不是所有情况下我们都能静态链接所有库,特别是存在MFC扩展dll的时候,以及使用了没有static lib的第三方库的时候(这些库可能要求动态链接msvcrt)。
msvc6时代没这个问题,因为程序不能运行会提示缺少xxx.dll,这样很容易解决,只需要把必要的dll和软件一起发布就可以了(这个需要注意dll作者的再发布许可协议)。
msvc8,msvc9引入了所谓的程序集概念(注意不是.net那个意义的程序集,但是借助于这个概念)使用winsxs来避免dll hell,但是(嗯,大家都怕这个但是)却引入了另一个问题:版本匹配。
假设下列场景:
1 我们编译环境是msvc8或者msvc9,并且始终安装最新的补丁
2 发布给用户编译出来的binary和msvc8/msvc8sp1/msvc9/msvc9sp1 redist
3 运行失败
这实在是令人倍感挫折,为什么不行了呢?问题的根源在menifest,如果我们打开binary随带的menifest,并且检查相关dll的版本号,会发现版本号远高于msvc redist里面的,这将导致系统拒绝加载dll,表面现象就是
“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”。
结论:编译环境的补丁会将编译环境的头文件升级,导致默认配置编译出来的binary需求更高级的版本号。
解决办法:
msvc8:定义 _USE_RTM_VERSION 宏,这将强制编译出使用msvc8 rtm版本号的bingary。
msvc9:取消定义 _BIND_TO_CURRENT_VCLIBS_VERSION 宏,这将编译出使用msvc9 rtm版本号的bingary。
这样,使用标准的msvc8/msvc8sp1/msvc9/msvc9sp1 redist即可。
msvc10微软取消了之前的设计,回归了msvc6的做法,于是正确的发布应该是下面这样
静态链接:这个兼容问题最少,但是无法享受系统补丁带来的安全和改进。
动态链接:可以依赖系统目录下的msvcrt dll,这样系统打补丁就会自动享受系统更新带来的改进。也可以把msvcrt和自己的binary放在一起,这样便享受不到系统更新。
补充说明:有极少数用户报告即便拷贝msvcrt100.dll之类的文件到系统目录或者binary目录,也无法运行,我无法重现,不知道具体原因。