zoukankan      html  css  js  c++  java
  • VC编写的程序不能在其他机器上运行的解决方案

    有的时候,你在Visual C++上面经过好几个月的辛勤努力,终于将程序编写完成并且测试完毕,然而当你试图在客户的发布机上运行刚写好的程序时,有可能会碰到类似下面的错误,操作系统告诉你“由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题”:

    一般情况下,这个问题都是由于程序不能找到所需要的C运行库(CRT)而引起的。

    Windows XP SP2以后,Windows引入了Side-by-Side执行的概念,这个概念本来是.NET提出来的,但是Windows后来将这个概念集成到操作系统层面上来了。大家都应该知道Dll Hell的问题,为了解决Dll Hell的问题,Side-By-Side提出不同版本的dll文件可以同时存在于同一个系统里面,而且依赖于不同版本dll的应用程序在运行的时候可以使用到它当初被编译生成的dll。前面的话,有点绕,举个例子:

    1.         假定你编写了一个C++程序A,是使用MFC 8.0(这个版本是随着Visual Studio 2005)发布的。

    2.         之后你的机器升级了Visual Studio的版本,从2005升级到20082008MFC库是9.0版本的,这个时候你的操作系统里面安装了两个版本的MFC,分别是8.09.0

    3.         你在Visual Studio 2008编写了另外一个C++程序BB依赖与MFC 9.0

    4.         如果你运行程序A的话,操作系统会将MFC 8.0加载到A的进程里面。

    5.         如果你这时同时运行程序B,操作系统会将MFC 9.0加载到B的进程里面。这就是Side-by-side的执行概念。

    操作系统之所以能够这样做,是因为它在加载程序AB之前,除了查看PE格式里面AB所依赖的Dll信息,都会查看ABmanifest文件。Manifest文件保存了Windows可执行文件(包括exedll文件)要运行起来的环境设置信息,文件名一般是可执行文件的文件全名加上.manifest。例如notepad.exemanifest文件就应该是notepad.exe.manifest。例外有的程序将manifest文件直接嵌入到可执行文件的资源里面了,这也就是为什么有的时候你看不到程序的manifest文件的原因。通常来说,一个manifest文件的内容如下(test.exe.manifest文件):

    <?xml version='1.0' encoding='UTF-8' standalone='yes'?>

    <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>

     <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">

        <security>

          <requestedPrivileges>

            <requestedExecutionLevel level='asInvoker' uiAccess='false' />

          </requestedPrivileges>

        </security>

     </trustInfo>

     <dependency>

        <dependentAssembly>

          <assemblyIdentity type='win32' name='Microsoft.VC90.DebugCRT' version='9.0.21022.8'

                            processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />

        </dependentAssembly>

     </dependency>

    </assembly>

    上面的例子里面,就说明这个程序依赖于CRT 9.0,而且是调试版的,CPU架构是32位的CPU。对于将manifest文件嵌入到资源文件的程序我们也有办法看到manifest的信息。

    1.         一种是使用mt.exeVisual Studio自带的manifest处理程序):

    mt -inputresource:test.exe;#1 /out:test.manifest

    2.         另外一种是使用dumpbin程序将整个exe的内容打印到一个文件,然后用文本编辑器打开,搜索Assem字符串样式就能找到manifest信息:

     

    解决方案

    知道了程序依赖于具体哪一个dll以后,你可以将所依赖的dll拷贝到程序的安装文件夹里面,以CRT库绑定失败为例,介绍解决步骤:

    1.         从上例中我们知道程序依赖的Microsoft.VC90.DebugCRT库,版本号是9.0.21022.8,需要32位机器版本的CRT。这个依赖项一般是因为你的程序是调试版,所以Visual Studio在编译的时候,将调试版的CRT加入程序的依赖项。

    2.         Visual Studio的安装文件夹里面将D:"Program Files"Microsoft Visual Studio 9.0"VC"redist"Debug_NonRedist"x86中的Microsoft.VC90.DebugCRT整个文件夹拷贝到应用程序所在的文件夹里面,注意:

    a)         如果你的程序依赖的是32位的CRT,则要拷贝x86文件夹里面的Microsoft.VC90.DebugCRT文件夹,如果是先x64程序,则要拷贝x64文件夹里面。

    b)         你需要确定Microsoft.VC90.DebugCRT文件夹里面的Microsoft.VC90.DebugCRT.manifest文件里面保存的版本信息而你程序依赖的版本信息匹配,Microsoft.VC90.DebugCRT.manifest里面的版本信息大版本号一定要一致,小版本号一定要等于或者大于你程序依赖的CRT的小版本号。比如上例中,我们的程序是依赖于CRT 9.0.21022.8,而我们的Microsoft.VC90.DebugCRT.manifest的版本是9.0.30729.1,这样是可以的;而8.0.30729.1就会有问题。如果大版本号一样,小版本号不一致的话,一个比较简单的方案就是修改程序的manifest文件,使其互相匹配就可以了。

    3.         如果你的程序不是依赖调试版本的CRT,而是release版本的CRT,直接去微软的官方网站下载一个crt redist包安装上就可以了。

  • 相关阅读:
    NTP on FreeBSD 12.1
    Set proxy server on FreeBSD 12.1
    win32 disk imager使用后u盘容量恢复
    How to install Google Chrome Browser on Kali Linux
    Set NTP Service and timezone on Kali Linux
    Set static IP address and DNS on FreeBSD
    github博客标题显示不了可能是标题包含 特殊符号比如 : (冒号)
    server certificate verification failed. CAfile: none CRLfile: none
    删除文件和目录(彻底的)
    如何在Curl中使用Socks5代理
  • 原文地址:https://www.cnblogs.com/killmyday/p/1394596.html
Copyright © 2011-2022 走看看