【问题标题】:BadImageFormatException on interop from DLL build with gcc on 64-bit system在 64 位系统上与 gcc 构建的 DLL 互操作时出现 BadImageFormatException
【发布时间】:2021-05-07 14:43:45
【问题描述】:

我正在开发一个 .NET 库。作为使库跨平台的任务的一部分,我决定将所有特定于平台的函数放入 C 文件并构建 DLL(对于 Windows)和 dylib(对于 macOS)。为了开始这项任务,我创建了一个简单的测试应用程序:Windows 上的控制台应用程序,它在 .NET Framework 上调用生成的 DLL 中的一个简单函数。

构建 DLL (test.dll) 的 C 文件内容:

int Foo() { return 123; }

测试程序代码:

class Program
{
    [DllImport("test")]
    public static extern int Foo();

    static void Main(string[] args)
    {
        var result = Foo();
        Console.WriteLine($"Result = {result}");
        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }
}

当我运行程序时,我得到 BadImageFormatException

如果我在 Visual Studio 中进行项目设置,我会看到:

如果我取消选中“首选 32 位”或在下拉列表中选择 x64,一切都很好,并且我看到了正确的输出:

Result = 123
Press any key to exit...

但这不是我的解决方案。该库被许多用户使用,我不想(也不能)强迫他们进行一些环境设置,比如选择目标平台。它也应该适用于 x86 和 x64。

DLL 是用 gcc 构建的:

gcc -v -c test.c
gcc -v -shared -o test.dll test.o

我的问题是如何处理问题并创建可以在任何 .NET 应用程序中定位的 DLL,而无需采取初步措施?也许可以构建具有双平台目标(不仅是 x64)的 DLL?

【问题讨论】:

    标签: c# visual-studio gcc interop


    【解决方案1】:

    我最终构建了两个版本的 DLL,32 位和 64 位。所以在代码中我们有这样的类:

    Api.cs

    namespace DualLibClassLibrary
    {
        internal abstract class Api
        {
            public abstract int Method();
        }
    }
    

    Api32.cs

    using System.Runtime.InteropServices;
    
    namespace DualLibClassLibrary
    {
        internal sealed class Api32 : Api
        {
            [DllImport("test32")]
            public static extern int Foo();
    
            public override int Method()
            {
                return Foo();
            }
        }
    }
    

    Api64.cs

    using System.Runtime.InteropServices;
    
    namespace DualLibClassLibrary
    {
        internal sealed class Api64 : Api
        {
            [DllImport("test64")]
            public static extern int Foo();
    
            public override int Method()
            {
                return Foo();
            }
        }
    }
    

    ApiProvider.cs

    using System;
    
    namespace DualLibClassLibrary
    {
        internal static class ApiProvider
        {
            private static readonly bool Is64Bit = IntPtr.Size == 8;
            private static Api _api;
    
            public static Api Api
            {
                get
                {
                    if (_api == null)
                        _api = Is64Bit ? (Api)new Api64() : new Api32();
    
                    return _api;
                }
            }
        }
    }
    

    所以如果我们想调用Method方法,我们会写:

    var result = ApiProvider.Api.Method();
    

    当然,我们需要在输出中包含以下文件:

    • test32.dll(和 dylib 等)
    • test64.dll(和 dylib 等)

    使用此系统,程序将根据当前进程是否为 64 位来选择所需的文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2013-08-29
      • 2012-06-19
      相关资源
      最近更新 更多