为什么在使用 .NET 6.0 时会出现 EntryPointNotFoundException 错误,而在使用 4.7.1 时却不会?

Why do I get an EntryPointNotFoundException error when using .NET 6.0, but not when using 4.7.1?

我正在使用 C++ 创建 DLL 并使用 C# 导入它。我编译 DLL 没有问题,从 .NET 4.7.1 调用它时它工作正常。但是,当我尝试从 .NET 6.0 调用它时,出现 EntryPointNotFoundException 错误:

Unhandled exception. System.EntryPointNotFoundException: 
Unable to find an entry point named 'E' in DLL 'test.dll'.
   at Program.E(int a, int b)
   at Program.Main(String[] args) in G:\C++\Test\Program.cs:line 6

Test.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!--<TargetFramework>net4.7.1</TargetFramework>-->
    <TargetFramework>net6.0</TargetFramework>
    <OutputType>Exe</OutputType>
    <Configuration>Debug</Configuration>
  </PropertyGroup>
</Project>

Test.cpp

extern "C"__declspec(dllexport) int E(int a, int b)
{
   return x + y;
}

Program.cs

public class Program
{
    [DllImport("test.dll")] public static extern int E(int a, int b);
    public static void Main(string [] args)
    {
        float r = E(11, 26);
        System.Console.WriteLine(r);
    }
}

我的编译器标志如下:

g++ -shared -o test.dll Test.cpp -Wl,--out-implib,test.dll 

研究:

因为很明显这是 .NET 6 的问题,所以我使用 Google:

进行了一些特定的搜索

我可以使用您使用 Visual Studio 2022 描述的设置在本地重现该问题。

初步说明 1: 所有 .NET 东西的命名可能会非常混乱:“.NET”不是“.NET Framework”。而“.NET Core”就是“.NET”的前身。大致。见 documentation and or this post.

前言2:.NET Core和.NET中的主要程序代码驻留在一个dll文件中,需要使用dotnet myProject.dll执行。从 .NET Core 3.0 开始,创建了一个额外的 exe 文件,它简单地包装了该命令。另一方面,.NET Framework 直接生成 exe 文件。比较例如 or this post.

您的问题:您的问题现在如下:首先,您通过 g++ 创建 test.dll。然后构建 Test.csproj 文件,对于 .NET 6,该文件不仅会生成 Test.exe,还会生成 Test.dll。由于 Windows' 文件系统不区分大小写,因此构建 csproj 文件 会覆盖 您自己的 g++ test.dll 文件。因此,结果 Test.dll 是完全不同的东西。尝试执行 Test.exe 将尝试从 dll 中导入函数 E,但由于 dll 已被替换,该函数已不存在。另一方面,如果在构建 csproj 后用 g++ test.dll 替换 Test.dll 会导致 Test.exe 不再工作(因为,如上所述,Test.exe并不真正包含您的代码,而是调用 Test.dll,它不再包含正确的 .NET 代码)。

另一方面,对于 .NET Framework,不会出现此问题,因为构建 Test.csproj 文件只会生成一个 Test.exe 而不会影响您的 g++ test.dll

解决方法:最简单的解决方法是给自己的g++生成的dll起个不同的名字,例如test2.dll,并将其导入到 C# 项目中。或者为 C# 项目(或者更确切地说,它的输出)选择一个不同的名称。 另一种解决方案是发布您的 .NET 6 项目 self-contained,使其仅包含一个 exe 文件。查看 documentation or post.