gpt4 book ai didi

c# - 为 'Any CPU' 构建 p4api.net.dll

转载 作者:行者123 更新时间:2023-11-30 12:24:46 24 4
gpt4 key购买 nike

本周早些时候,我在尝试使用 p4api.net.dll 时遇到了第一个 BadImageFormatException。结果证明我的假设是我只能使用它的 64 位版本,而 p4bridge.dll 是不正确的!

在我的调查中,我注意到我有一个警告:

警告 MSB3270:正在构建的项目“MSIL”的处理器架构与引用“p4api.net,Version=2014.3.100.9144,Culture=neutral,PublicKeyToken=f6b9b9d036c873e1”的处理器架构不匹配, 处理器架构=AMD64", "AMD64"

我了解到这意味着我使用的 .dll 被指定为使用 64 位,而不是使用 Any-CPU 构建。

虽然我们可以将项目更改为专门针对 x64 的项目,但有人要求我调查是否仍然有可能使其尽可能与平台无关。我对必须处理这种依赖关系的 p4api.net 仍然是新手,但我的理解是,如果我可以将 p4api.net.dll 构建为“任何 CPU”,警告就会消失,我只需要做一些魔术来确保根据我在项目中定义的 CurrentPlatform 使用正确的 p4bridge.dll。

我下载并编译了 p4api.net 源代码并尝试指定任何 CPU,但没有成功。现在它说架构是为 x86 设置的,但我仍然收到类似的 MSB3270 错误 - 现在为 x86。但是,我在 p4api.net 解决方案中没有收到这样的警告,因此它似乎没有任何我知道的平台依赖性。但是,如果我在 p4api.net.dll 上使用 CorFlags.exe,它肯定会提供特定于平台的 PE/32BIT 标志。

所以我的问题是:

  • 有谁知道是否有可能为任何 CPU 构建 p4api.net?
  • 如果做不到这一点,我必须做些什么来检查存在哪些(如果有的话)平台依赖性会阻止我为任何 CPU 构建 p4api.net.dll?

如果以上问题的答案是否定的,我可能会有新的问题,但当我到达那里时会穿过那座桥! :)

在此先感谢您的帮助/想法。

最佳答案

我现在没有代码,但我可以向您描述我是如何解决这个问题的。问题是,虽然 p4api.net 库在设置为以任何 CPU 为目标时编译得很好,但底层 native C++ 库 (p4bridge.dll) 是以 x86 或 x64 为目标的,并且没有办法在一个架构中为两种架构编译它动态链接库。因此,我必须变聪明!

为了完成这项工作,我将两个版本的 p4bridge.dll 添加到 p4api.net 项目,将它们重命名为 p4bridge86.dll 和 p4bridge64.dll,并将它们标记为包含在程序集资源中。接下来,我在 p4api.net 库中编写了一个静态函数,用于确定机器正在运行的体系结构,获取正确的 p4bridge.dll 资源,将其保存到当前正在执行的 p4api.net.dll 旁边的磁盘中,最后P/在提取的 p4bridge.dll 上调用 Windows LoadLibrary 函数。

难题的最后一部分是确保您编写的这个函数在实例化 p4api.net 中的任何类型之前运行,因为此时加载程序将看到引用 p4bridge.dll 的类型并尝试从磁盘加载它,如果你从来没有运行过提取函数,它就不会存在,你会抛出一个异常。为了解决这个问题,我不得不对 .NET 有所了解:我下载了 Einar Egilsson 的神奇小工具 InjectModuleInitializer并在运行该工具的 p4api.net 项目上设置一个构建后步骤,并让它插入指令以调用我在执行模块中的任何其他代码之前编写的静态提取器/加载器函数。

通过此设置,我有一个为任何 CPU 编译的 p4api.net 程序集,但可以自动处理 x86 和 x64 架构所需的 native p4bridge.dll 必须单独存在的事实。

当我稍后回家时,我会看到有关添加源代码的信息,这些源代码准确地显示了我是如何编写提取和加载函数的,以及任何其他可能需要更清晰的内容。抱歉,这个答案是在您最初提出问题后一年多才出现的,但是几天前我也需要找出解决此问题的方法,并且由于我设法做到了,所以我认为值得与可能遇到此问题的任何人分享 future 很复杂的问题!

编辑:下面是提取和加载正确的 p4bridge.dll 的类的实现。它只会在未提取 DLL 或找到的 DLL 无法加载时提取 DLL(因为出于某种原因,它可能是错误的体系结构)。此外,p4bridge.dll 的大小为几兆字节,每次加载 p4api.net 时执行不必要的 IO 没有多大意义!

internal static class P4BridgeLoader
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);

private static void ExtractResource(string resourceName, string outPath)
{
using (System.IO.Stream dllStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
try
{
// Copy the assembly to the temporary file
using (System.IO.Stream outFile = System.IO.File.Create(outPath))
{
dllStream.CopyTo(outFile);
}
}
catch
{
}
}
}

/// <summary>
/// Loads the correct version of p4bridge.dll, based on the bit with of the current architecture.
/// Note that this is called by the module initializer, which gets called just after this module
/// is loaded but before any other code inside it is executed.
/// </summary>
internal static void LoadP4BridgeDLL()
{
// Figure out where we are going to put the p4bridge.dll once we've extracted it
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string assemblyPath = Uri.UnescapeDataString(uri.Path);
string assemblyDir = Path.GetDirectoryName(assemblyPath);
string dllPath = Path.Combine(assemblyDir, "p4bridge.dll");

// Extract the correct architecture version of p4bridge.dll from our assembly's resources
string resourceName = Environment.Is64BitProcess ? "Perforce.P4.p4bridge64.dll" : "Perforce.P4.p4bridge86.dll";

// If the dll already exists, then we shouldn't have to try extracting it again unless it fails to load
if (System.IO.File.Exists(dllPath))
{
// Attempt to load the DLL
if (LoadLibrary(dllPath) != IntPtr.Zero)
return;
}

// DLL either wasn't already extracted, or failed to load. Try again!
ExtractResource(resourceName, dllPath);

// Attempt to load the DLL
IntPtr h = LoadLibrary(dllPath);
System.Diagnostics.Debug.Assert(h != IntPtr.Zero, "Unable to load library " + dllPath);
}
}

下面是用于挂接到 .net 模块初始化程序的命令行。请注意,/k:MyKey.snk 参数允许程序集在修改后进行强签名。

InjectModuleInitializer.exe /k:MyKey.snk /m:Perforce.P4.P4BridgeLoader::LoadP4BridgeDLL p4api.net.dll

关于c# - 为 'Any CPU' 构建 p4api.net.dll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32893481/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com