我如何定位特定版本的 C++ 运行?

发布于 2024-07-26 09:44:53 字数 599 浏览 7 评论 0原文

我们有一个非常大的项目,主要用 C# 编写,其中有一些小但重要的组件用 C++ 编写。 我们将 .NET 2.0 的 RTM 定为最低要求版本。 到目前为止,为了满足此要求,我们已确保构建箱上仅具有 .NET 2.0 的 RTM,以便 C++ 片段与该版本链接。

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

不幸的是,当配置者准备在 4 月 1 日做某事时,我们公司的 IT 部门大力推动所有内容都得到修补和更新,结果 3.5 SP1 之前的所有内容都安装在构建箱上。 我们尝试卸载所有内容,这种情况以前也发生过,但现在我们无法满足最低要求,因为在该特定机器上构建的任何内容都需要 .NET 2.0 SP1。

由于盒子似乎被灌满了,我们不能只是卸载有问题的版本,有没有什么方法可以构建程序集并明确告诉它们使用 .NET 2.0 的 RTM(即 v2.0.50727.42)? 我看过一些涉及使用清单的页面,但我无法弄清楚如何实际实现正确的清单并将其放入程序集中。 我的专业知识是管理领域,所以我对此有点茫然。

谁能解释一下如何使这些程序集针对 .NET 2.0 RTM SxS 程序集?

谢谢!

We have a very large project mostly written in C# that has some small, but important, components written in C++. We target the RTM of .NET 2.0 as the minimum required version. So far, in order to meet this requirement we've made sure to have only the RTM of .NET 2.0 on our build box so that the C++ pieces link against that version.

Update: The C++ assembly that is causing the issue is a mixed-mode C++ assembly being loaded into a managed process.

Unfortunately when the confiker was set to do something on April 1st, our corporate IT made a huge push to get everything patched and up to date, and as a result everything up through 3.5 SP1 got installed on the build box. We've tried uninstalling everything, which has happened before, but now we are unable to meet our minimum requirements as anything built on that particular box requires .NET 2.0 SP1.

Since the box seems to be hosed in that we can't just uninstall the offending versions, is there any way to build the assemblies and explicitly tell them to use the RTM of .NET 2.0 (which is v2.0.50727.42)? I've seen pages that refer to using a manifest, but I can't figure out how to actually implement a proper manifest and get it into the assemblies. My expertise is in the managed world, so I'm at a bit of a loss on this.

Can anyone explain how I can make these assemblies target the .NET 2.0 RTM SxS assemblies?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

楠木可依 2024-08-02 09:44:53

虽然我很确定克里斯托弗的答案和代码示例(谢谢你,克里斯托弗!)是一个更优雅的解决方案的一部分,但我们在枪口下将其推出,并找到了一个非常相似但不同的解决方案。

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

<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>

接下来,您必须在“配置属性 -> ”下将“生成清单”选项设置为“否”。 链接器-> 清单文件,然后将“配置属性 ->”下的“嵌入清单”选项设置为“否” 清单工具 -> 输入和输出。

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

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 的方法,但目前来说这是可行的。 如果有人对如何清除任何现有依赖项有任何额外的意见,那就太好了。

谢谢!

While I'm pretty sure that Christopher's answer and code sample (thank you, Christopher!) is part of a more elegant solution, we were under the gun to get this out the door and found a very similar, but different, solution.

The first step is to create a manifest for the assembly:

<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>

Next you have to set the 'Generate Manifest' option to 'No' under Configuration Properties -> Linker -> Manifest File, and set the 'Embed Manifest' option to 'No' under Configuration Properties -> Manifest Tool -> Input and Output.

Finally, to get your new manifest into the assembly add the following command to the project's post-build step:

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

Once built we can open the dll in Visual Studio to view the manifest under RT_MANIFEST and confirm that it has our manifest!

When I put Christopher's code in the stdafx.h it ended up adding it as an additional dependency...the manifest was still looking for v8.0.50727.762. The manifest it generated looked like this:

<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>

I could not track down another switch that would remove or clear existing dependencies. I like Christopher's approach better than a post-build step, but for now this works. If anyone has any additional input on how to clear out any existing dependencies that'd be great.

Thanks!

爱要勇敢去追 2024-08-02 09:44:53

是的。 在您的项目属性中,有一个页面指示运行时。 有一个下拉菜单列出了所有可用的运行时。 选择适合您的一款。
(对于 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

除了,您应该找到 .Net 的正确值,而不是 MFC。 DLL。

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

否则您将需要将所有构建时文件复制到您当前的框,然后根据您的构建类型调整包含和库路径。 也许这是一个比其价值更令人头痛的问题。

Yes. In your project properties, there is a page that indicates the runtime. There is a drop down that lists all of the runtimes available. Choose the one that is appropriate for you.
(For VS 2008: Right click on the project -> properties, Compile tab, Advanced Compiler Settings button -> Target framework)

We do this right now. We would like to move to VS 2008, but we are doing it incrementally. So right now we have a VS 2008 solution, but all the projects still target .Net 2.0. Thus, when we compile and deploy, we don't need the .Net 3.5 stuff installed on our test boxes.

UPDATE:

To force a native program to link to specific versions of .dlls, you probably want to use something like this:

#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

Except, that instead of MFC, you should find the correct values for the .Net .DLLs.

It is reasonable to believe that you cannot have .Net 2.0 SP1 and .Net 2.0 on the same box. So getting this to work on that box is likely going to be really, really painful. It is probably better to spin up a new build VM that you can install the old, unpatched .Net framework on (if you can even get a hold of it anymore.)

Otherwise you will need to copy all the build-time files over to your current box, and then make adjustments to the include and library paths based on your build type. Probably this is a much bigger headache than it's worth.

柏林苍穹下 2024-08-02 09:44:53

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

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

Linker-> 清单文件选项

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

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

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

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

在清单工具选项中,“输出清单文件”和“清单资源文件”会自动填充,即使在我清除它们之后也是如此。

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

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

John really put me on the right track to solve the same problem. I am making a slight change to an old VS2005 C++ (non-CLR) project. My development machine has all the updates so VS2005 was creating references to the latest versions of the MFC80 and MSVCx80 DLLs and the executable wouldn't run on the target machines becuase those versions were not available and I do not have the option to update those machines. So I need to control the assmelby dependencies in the manifest which is embedded in the executable file. This seems to be about the same problem John is working on. Starting with his additional information, this is what worked for me.

In the ProjectDir create program.exe.debug.manifest and program.exe.release.manifest files with the appropriate assembly reference information. Do not add these to the project or the linker with try to include both of them in every build. Then set the project properties as follows:

Linker-> Manifest File options

  • Generate Manifest: No
  • Manifest File: blank
  • Additional Manifest Dependencies: blank
  • Allow Isolation: Yes

Manifest Tools->Input and Output options

  • Additional Manifest Files: $(ProjectDir)$(TargetFileName).$(ConfigurationName).manifest
  • Input Resource Manifests: blank
  • Embed Manifest: Yes
  • Output Manifest File: (filled in automatically)
  • Manifest Resource File: (filled in automatically)
  • Generate Catalog Files: No
  • Dependency Information File: $(IntDir)\mt.dep (filled in automatically)

From my testing, it appears that this does not generate any other manifest files and embeds your hand coded manifest information into the EXE as RT_MANIFTEST resource #1.

In the Manifest Tool options, “Output Manifest File” and “Manifest Resource File” were filled in automatically, even after I cleared them.

This seems to allow me to control the assembly dependencies and get the executable to run on the target machines. The added benefit is that I did not have to use the post-build step which is being used for other purposes. By manipulating the Linker and Manifest Tool options, it is possible to get the same result.

Sorry I couldn't updoad screen shots, but I am a new user and images are not allowed yet.

梦醒时光 2024-08-02 09:44:53

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

祝你好运!
特里

I know this is a hack, but i've resorted to generating the manifest externally, and modifying it with notepad. In a pinch, it's done the trick for me. In my case, i was looking to have a VC++ 2005 app point to a .762 CRT.

Good Luck!
Terry

温馨耳语 2024-08-02 09:44:53

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

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

John's answer works for us. In Visual C++ 2005, the compiler generates manifests that include both 762 and 4053 versions of MFC and CRT. We deleted the 4053 version from the manifest, and went to the manual step described above. (Internally code will actually grab 4053 as it's a recognized security fix over 762, but the spec is necessary or linking will just fail.)

Ted's blog (tedwvc.wordpress.com) posting gave us the hint, but his solution didn't work out for us. This approach here works.

尬尬 2024-08-02 09:44:53

我认为您需要 CorBindToRuntime。 这将允许您指定 C++ 加载的 CLR 版本。

Methinks you want CorBindToRuntime. This will allow you to specify the version of the CLR your C++ loads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文