轻松解决manifest problem

 

 

"manifest" 是vc8以来的一个新东西,这个东西似乎给我们带来了无尽的烦恼,本机生成的dll,放到别的机器运行时,即时带上dll,也总是弹出莫名其妙的异常:“应用程序正常初始化失败”,即便是调试启动,也发现根本就无法进入程序代码,在弹出异常对话框后断下,看Output,“'XXX.exe': Loaded 'C:\Documents and Settings\zhaiyongqiang\桌面\XXX\Debug\XXX.exe', Symbols loaded.

'XXX.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', Symbols loaded (source information stripped).

'XXX.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', Symbols loaded (source information stripped).

SXS: Unable to resolve storage root for assembly directory x86_Microsoft.VC90.DebugMFC_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_c94a3a24 in 2 tries

SXS: RtlGetAssemblyStorageRoot() unable to resolve storage map entry.  Status = 0xc0150004

SXS: Unable to resolve storage root for assembly directory x86_Microsoft.VC90.DebugMFC_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_c94a3a24 in 2 tries

SXS: RtlGetAssemblyStorageRoot() unable to resolve storage map entry.  Status = 0xc0150004”,

这说明在Kernel32.dll出了问题,根本还没有进入应用程序的执行代码。再看调用堆栈, 

=》!ntdll.dll!_KeFastSystemCallRet@0() 

     !ntdll.dll!NtRaiseHardError@24() + 0xc bytes

     !_LdrpInitializationFailure@4() + 0x2d bytes

     !__LdrpInitialize@12() + 0x26b8d bytes

     !_KiUserApcDispatcher@20() + 07 bytes 

 

注意,需要安装symbols才能看到这些信息

 

这说明在加载dll的时候出了问题--这就是vs2005以后非常恶心的manifest问题,通常是未打SP1补丁时编译的程序,在打了SP1补丁的机器无法运行,或者是使用了Debug编译的程序,在另一台机器上即便安装了vcredist也会异常。。。

 

这个时候我们用depends工具查看PE文件的时候 ,会发现import dll异常,通常是 MSVCR80D.dll MFC90D.dll等。

 

最近有一朋友运行我给的一个vc9编译的程序,debug的,我把WinSxS下的 

x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_597c3456

x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_f863c71f

x86_Microsoft.VC90.DebugMFC_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_2a62a75b 

x86_Microsoft.VC90.DebugMFC_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_c94a3a24

复制给他仍然不行,后来连Manifest文件夹复制给他,就可以了。

 

“本以为已经完美解决了这个问题”,不曾想,3天以后,公司要外出演示的一个demo也遇到了这个问题,并且有一个dll是debug的,装了.net framework3.5,vc9 redist仍然不管用,我如法炮制,并且连Policy文件夹也复制上了,于是立竿见影解决了问题。演示回来,带来的是坏消息,那些winsxs的文件无法覆盖对方机器,被系统保护阻挡了。。。于是乎在众目睽睽之下出了洋相。。。总结的教训是,不能乱用山寨方法解决这个问题。

 

查阅MSDN “About Isolated Applications and Side-by-side Assemblies”一节,

 Isolated applications and side-by-side assemblies provide a solution that reduces DLL versioning conflicts. They enable applications to safely share assemblies. For more information, see Shared Assemblies.“

 

这是vs2005 以后由编译器和xp 系统共同作用制作的一个防止”dll hell“的一个解决方案。也许确实可以防止错误dll带来的系统崩溃危险,但是却也造成了用户程序频频异常的噩梦。

 

咒骂没有用,还是接受这个现实吧,虽然牺牲了用户程序的健壮性,却也带来了系统的稳定性。好吧,现在跟我来解决这个噩梦吧(不要在用山寨方法):

 

最可行的方法是用  vc2005 或者vc2008 自带的“Setup and Deployment” project type 创建一个发布程序,并且附带“Merge Module”,这个Merge Module就是要安装到 WinSxS正确位置的必须的dll,比如DebugCRT,DebugMFC 等等。

 

创建了Setup项目后,选择菜单 Project/Add/Merge Module 会弹出一个文件打开对话框,目录指向 “C:\Program Files\Common Files\Merge Modules”,

选定 DebugCRT,DebugMFC等你所需要的那些VC RUNTIME就可以了,安装的时候就会把这些dll安装到WinSxS正确位置上,这是系统服务就不会产生那个直接copy的保护异常了。

 

我们会发现,安装一些游戏的时候会最后弹出一个 vc2005 redist安装来,其实这个做法很傻。。。而且看起来傻子还不少,哈哈。本来vc 安装可以自动来做这些事情。

 

另外,如果你要做更复杂的发布程序,也可以用Install Shield 10.5,也可以解决这些问题,不过用起来有些复杂,在Object 标签里就可以添加这些东西,并且可以自动检查依赖,添加到安装文件列表里去。 

 

更多的细节可以查阅 MSDN 中的 “Side-by-side Assembly” 和 “Merge Module” 等相关章节。


下载VC9_x86Runtime_SP1(30729) 

 

 

 

 

     

      

posted on 2010-01-07 23:42  cgwolver  阅读(3732)  评论(1编辑  收藏  举报

导航