【问题标题】:Call a managed C# library with P/invoke without Assembly.Load or similar使用没有 Assembly.Load 或类似的 P/invoke 调用托管 C# 库
【发布时间】:2020-11-26 18:23:39
【问题描述】:

我已经找了好几天了,但我发现的只是如何使用 P/Invoke 从 C# 调用 unmanaged 库。我需要采取不同的做法:我希望使用 P/Invoke 从另一个程序集调用 托管 程序集(或使用其他方法,避免 调用 Assembly.LoadAssembly.LoadFrom 等)基本上是由于 CoreRT/NativeAOT 限制(请参阅here)。

基本上,使用 CoreRT/NativeAOT 的想法是由于原生可执行文件生成,这将提高我的应用程序的安全性,因为常见的反编译器无法使用它(除了 IDA 和具有 ASM 知识的聪明开发人员,但他们'更难得到)。考虑到 CoreRT/NativeAOT 不能(it can,但 .NET 团队现在不想......)使用任何 .NET 互操作方法(Assembly.LoadAssembly.LoadFrom 等)加载外部程序集。 ) 但它可以使用DllImport,我想调用一个外部程序集,如果不使用任何这些程序集加载方法,它是否被反编译我并不在意。

是的,我知道我可以用 CoreRT 本身编写一个包装器或其他东西来生成一个本机库并使用应用程序中的 P/Invoke 调用它,但是对于由于 Reflection.Emit 而无法编译的实体框架来说,这是不可能的。

这里的理想解决方案是了解如何在不使用 Assembly.Load/LoadFrom/LoadFromStream/etc 的情况下从另一个 C# 应用程序/程序集调用任何 .NET 程序集 (DLL)。使用其他方法,可以是 P/Invoke(可以吗?)或其他方法。

【问题讨论】:

  • 您的问题没有任何代码,看起来就像 MS github 存储库之一中的讨论
  • 不确定是否有帮助:.NET 5 最近宣布了一些关于原生导出的消息:devblogs.microsoft.com/dotnet/announcing-net-5-0/…
  • @PavelAnikhouski 它不需要任何代码,AFAIK。当没有已知的方法(我知道)来做我想做的事情时,我可以显示什么样的代码? MS 的存储库不允许在他们的 github 上提出问题,因为“他们不在那里提供技术支持”,此外,当我问这个问题时,我得到了一个指向我刚刚放在它说他们不会支持的问题的链接。我拒绝接受这样一个固定的答案,因为我确信我想要实现的目标是可能的。我只是不知道怎么做,这就是我在这里问的原因。
  • @ChristianHeld 非常感谢该链接,我一直在使用 .NET 5 并一直在适应最新的变化。我认为 Native Exports 可能是我正在寻找的。我会做一个测试,如果它有效,我会用一些代码来回答我自己的问题。谢谢!
  • @DARKGuy 我很高兴我的评论为您指明了解决方案,这对我来说已经足够了:)。这是你如何弄清楚它是如何工作的,所以请发布你的解决方案作为答案。

标签: c# .net-core pinvoke .net-assembly corert


【解决方案1】:

解决方案

感谢 @ChristianHeld 建议使用 .NET 5.0 的 Native Exports(还要感谢 Aaron Robinson 的代码。我是这样工作的:

.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    ADD THIS -> <EnableDynamicLoading>true</EnableDynamicLoading>
    ADD THIS -> <DnneAddGeneratedBinaryToProject>true</DnneAddGeneratedBinaryToProject>
  </PropertyGroup>

  <ItemGroup>
    ADD THIS -> <PackageReference Include="DNNE" Version="1.*" />
  </ItemGroup>

</Project>

.NET 代码库(已剥离):

[UnmanagedCallersOnlyAttribute]
public static void Init()
{
    // ... Some code here...
}

调用者 .NET 代码(示例):

class Program
{
    const string LIBNAME = @"LibraryNE.dll";
    [DllImport(LIBNAME)] public static extern void Init();

    static void Main(string[] args)
    {
        Init();
    }
}

重要提示: 使用 VSCode (F5) 运行时,它可能会这样说:

Failed to initialize context for config: C:\Project\Library.runtimeconfig.json. Error code: 0x80008092

忽略这一点,因为这似乎是因为 VSCode 使用 dotnet.exe 调试应用程序,忽略了每个程序集的 runtimeconfig.json(不知何故,它抛出了 LibHostInvalidArgs。不知道为什么)。

如果您直接执行应用程序的 .EXE,它将起作用(只需将其与 CoreRT/NativeAOT 生成的二进制文件一起使用)。解决此问题的方法是编辑您的 launch.json 文件并在 configurations -&gt; program 中将 .dll 更改为 .exe

另外,请记住也要复制 .NET dll。好像发布的时候只复制原生库(以NE为后缀),但它本身并不能工作,因为它只是一个包装器。它也需要真正的 .NET dll 在同一个文件夹中。

调试体验不是很好,因为当您调试该方法时,它似乎使用不同的、不存在的源文件,因此单步执行时的行号不匹配。它是可调试的,但您将针对幻影/偏移线这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多