4

我们有一个非常大的项目,主要是用 C# 编写的,其中有一些用 C++ 编写的小而重要的组件。我们将 .NET 2.0 的 RTM 定位为所需的最低版本。到目前为止,为了满足这个要求,我们确保在我们的构建框中只有 .NET 2.0 的 RTM,以便 C++ 片段链接到该版本。

更新:导致问题的 C++ 程序集是将混合模式 C++ 程序集加载到托管进程中。

不幸的是,当 confiker 准备在 4 月 1 日做某事时,我们的公司 IT 大力推动所有内容都被打上补丁和更新,结果直到 3.5 SP1 的所有内容都安装在构建盒上。我们已经尝试卸载之前发生的所有内容,但现在我们无法满足我们的最低要求,因为在该特定机器上构建的任何内容都需要 .NET 2.0 SP1。

由于盒子似乎已经被冲洗掉了,我们不能只卸载有问题的版本,有没有办法构建程序集并明确告诉他们使用 .NET 2.0(即 v2.0.50727.42)的 RTM?我已经看到有关使用清单的页面,但我无法弄清楚如何实际实现正确的清单并将其放入程序集中。我的专长是管理世界,所以我对此有点茫然。

谁能解释我如何使这些程序集以 .NET 2.0 RTM SxS 程序集为目标?

谢谢!

4

6 回答 6

8

虽然我很确定 Christopher 的答案和代码示例(谢谢,Christopher!)是一个更优雅的解决方案的一部分,但我们迫不及待地想把它排除在外,并找到了一个非常相似但不同的解决方案。

第一步是为程序集创建清单:

<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.DebugCRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
</assembly>

接下来,您必须在 Configuration Properties -> Linker -> Manifest File 下将“Generate Manifest”选项设置为“No”,并在 Configuration Properties -> Manifest Tool -> Input and Output 下将“Embed Manifest”选项设置为“No” .

最后,要将您的新清单添加到程序集中,请将以下命令添加到项目的构建后步骤:

mt.exe /manifest "$(ProjectDir)cppassembly.dll.manifest" /outputresource:"$(TargetDir)\cppassembly.dll";#2 -out:"$(TargetDir)\cppassembly.dll.manifest"

构建完成后,我们可以在 Visual Studio 中打开 dll 以查看 RT_MANIFEST 下的清单并确认它有我们的清单!

当我将 Christopher 的代码放入 stdafx.h 时,它最终将其添加为附加依赖项……清单仍在寻找 v8.0.50727.762。它生成的清单如下所示:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50608.0" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

我无法找到另一个可以删除或清除现有依赖项的开关。我更喜欢 Christopher 的方法,而不是构建后的步骤,但现在这可行。如果有人对如何清除任何现有的依赖项有任何额外的意见,那就太好了。

谢谢!

于 2009-07-07T15:40:48.420 回答
3

是的。在您的项目属性中,有一个页面指示运行时。有一个下拉列表列出了所有可用的运行时。选择适合您的那一款。(对于 VS 2008:右键单击项目 -> 属性,编译选项卡,高级编译器设置按钮 -> 目标框架)

我们现在就这样做。我们想迁移到 VS 2008,但我们正在逐步进行。所以现在我们有一个 VS 2008 解决方案,但所有项目仍然以 .Net 2.0 为目标。因此,当我们编译和部署时,我们不需要在我们的测试盒上安装 .Net 3.5 的东西。

更新:

要强制本机程序链接到特定版本的 .dll,您可能需要使用以下内容:

#pragma message ("Explicit link to generate a manifest entry for MFC.")

#if defined (_DEBUG)

#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.VC80.DebugMFC' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'\"")

#else

#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.VC80.MFC' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'\"")

#endif

除了 MFC 之外,您应该找到 .Net .DLL 的正确值。

有理由相信您不能在同一个盒子上安装 .Net 2.0 SP1 和 .Net 2.0。所以让这个在那个盒子上工作可能会非常非常痛苦。启动一个新的构建 VM 可能会更好,您可以在其上安装旧的、未打补丁的 .Net 框架(如果您甚至可以再掌握它的话。)

否则,您需要将所有构建时文件复制到当前框,然后根据您的构建类型调整包含和库路径。可能这比它的价值更令人头疼。

于 2009-07-06T15:34:03.700 回答
3

约翰真的让我走上了解决同样问题的正确轨道。我正在对旧的 VS2005 C++(非 CLR)项目进行轻微更改。我的开发机器具有所有更新,因此 VS2005 正在创建对 MFC80 和 MSVCx80 DLL 的最新版本的引用,并且可执行文件不会在目标机器上运行,因为这些版本不可用并且我没有更新这些机器的选项. 所以我需要控制嵌入在可执行文件中的清单中的 assmelby 依赖项。这似乎与约翰正在解决的问题相同。从他的附加信息开始,这对我有用。

在 ProjectDir 中创建带有相应程序集参考信息的program.exe.debug.manifestprogram.exe.release.manifest文件。不要将它们添加到项目或链接器中,并尝试在每个构建中都包含它们。然后设置项目属性如下:

链接器-> 清单文件选项

  • 生成清单:否
  • 清单文件:空白
  • 附加清单依赖项:空白
  • 允许隔离:是

清单工具->输入和输出选项

  • 附加清单文件:$(ProjectDir)$(TargetFileName).$(ConfigurationName).manifest
  • 输入资源清单:空白
  • 嵌入清单:是
  • 输出清单文件:(自动填写)
  • 清单资源文件:(自动填写)
  • 生成目录文件:否
  • 依赖信息文件:$(IntDir)\mt.dep(自动填写)

根据我的测试,这似乎不会生成任何其他清单文件,并将您手动编码的清单信息作为 RT_MANIFTEST 资源 #1 嵌入到 EXE 中。

在 Manifest Tool 选项中,“<strong>Output Manifest File”和“<strong>Manifest Resource File”即使在我清除它们之后也会自动填写。

这似乎允许我控制程序集依赖项并让可执行文件在目标机器上运行。额外的好处是我不必使用用于其他目的的构建后步骤。通过操作链接器和清单工具选项,可以获得相同的结果。

抱歉,我无法上传屏幕截图,但我是新用户,目前还不允许使用图片。

于 2011-07-08T21:42:28.607 回答
1

我知道这是一个 hack,但我已经求助于在外部生成清单,并用记事本修改它。在紧要关头,它为我解决了问题。就我而言,我希望有一个 VC++ 2005 应用程序指向 .762 CRT。

祝你好运!特里

于 2009-08-20T07:26:59.797 回答
1

约翰的回答对我们有用。在 Visual C++ 2005 中,编译器生成包括 762 和 4053 版本的 MFC 和 CRT 的清单。我们从清单中删除了 4053 版本,然后转到上述手动步骤。(内部代码实际上会抓取 4053,因为它是 762 上公认的安全修复程序,但规范是必要的,否则链接将失败。)

Ted 的博客 (tedwvc.wordpress.com) 帖子给了我们提示,但他的解决方案对我们不起作用。这种方法在这里有效。

于 2009-09-10T19:16:04.130 回答
0

我想你想要CorBindToRuntime。这将允许您指定 C++ 加载的 CLR 的版本。

于 2009-07-06T15:47:32.073 回答