使用 P/invoke 而不使用 Assembly.Load 或类似的调用托管 C# 库
Call a managed C# library with P/invoke without Assembly.Load or similar
我已经找了好几天了,但我只找到了如何使用 P/Invoke 从 C# 调用 unmanaged 库。我需要做不同的事情:我正在寻找使用 P/Invoke 从另一个调用 managed 程序集(或使用其他东西,avoiding 调用 Assembly.Load
、Assembly.LoadFrom
等)主要是由于 CoreRT/NativeAOT 限制(参见 here)。
基本上,使用 CoreRT/NativeAOT 的想法是由于生成本机可执行文件,这会提高我的应用程序的安全性,因为普通反编译器无法使用它(IDA 和使用 ASM 的聪明开发人员除外)知识,但它们更难获得)。考虑到 CoreRT/NativeAOT 不能(it can,但 .NET 团队现在不想...)使用任何 .NET Interop 方法加载外部程序集(Assembly.Load
, Assembly.LoadFrom
, 等)但它可以使用 DllImport
,我想调用一个外部程序集,如果不使用任何这些程序集加载方法,我不太关心它是否被反编译。
是的,我知道我可以用 CoreRT 本身编写一个包装器或其他东西来生成本机库并从应用程序中使用 P/Invoke 调用它,但在 Entity Framework 的情况下它不会由于 Reflection.Emit
,无法编译。
这里的理想解决方案是了解如何在不使用程序集的情况下从另一个 C# app/assembly 调用任何 .NET 程序集 (DLL)。Load/LoadFrom/LoadFromStream/etc。使用其他方法,可以是 P/Invoke(可以吗?)或其他方法。
解决方案
感谢@ChristianHeld 建议使用 .NET 5.0 的本机导出(还要感谢 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-generated 二进制文件一起使用)。解决方法是编辑 launch.json
文件并在 configurations -> program
.
中将 .dll
更改为 .exe
此外,请记住也复制 .NET dll。发布时好像只复制了原生库(后缀为NE),但它本身不会工作,因为它只是一个包装器。它也需要真正的 .NET dll 位于同一文件夹中。
调试体验不是很好,因为当您调试方法时,它似乎使用了不同的、不存在的源文件,因此您单步执行时的行号不匹配。它是可调试的,但您将针对 ghost/offset 行进行调试。
我已经找了好几天了,但我只找到了如何使用 P/Invoke 从 C# 调用 unmanaged 库。我需要做不同的事情:我正在寻找使用 P/Invoke 从另一个调用 managed 程序集(或使用其他东西,avoiding 调用 Assembly.Load
、Assembly.LoadFrom
等)主要是由于 CoreRT/NativeAOT 限制(参见 here)。
基本上,使用 CoreRT/NativeAOT 的想法是由于生成本机可执行文件,这会提高我的应用程序的安全性,因为普通反编译器无法使用它(IDA 和使用 ASM 的聪明开发人员除外)知识,但它们更难获得)。考虑到 CoreRT/NativeAOT 不能(it can,但 .NET 团队现在不想...)使用任何 .NET Interop 方法加载外部程序集(Assembly.Load
, Assembly.LoadFrom
, 等)但它可以使用 DllImport
,我想调用一个外部程序集,如果不使用任何这些程序集加载方法,我不太关心它是否被反编译。
是的,我知道我可以用 CoreRT 本身编写一个包装器或其他东西来生成本机库并从应用程序中使用 P/Invoke 调用它,但在 Entity Framework 的情况下它不会由于 Reflection.Emit
,无法编译。
这里的理想解决方案是了解如何在不使用程序集的情况下从另一个 C# app/assembly 调用任何 .NET 程序集 (DLL)。Load/LoadFrom/LoadFromStream/etc。使用其他方法,可以是 P/Invoke(可以吗?)或其他方法。
解决方案
感谢@ChristianHeld 建议使用 .NET 5.0 的本机导出(还要感谢 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-generated 二进制文件一起使用)。解决方法是编辑 launch.json
文件并在 configurations -> program
.
.dll
更改为 .exe
此外,请记住也复制 .NET dll。发布时好像只复制了原生库(后缀为NE),但它本身不会工作,因为它只是一个包装器。它也需要真正的 .NET dll 位于同一文件夹中。
调试体验不是很好,因为当您调试方法时,它似乎使用了不同的、不存在的源文件,因此您单步执行时的行号不匹配。它是可调试的,但您将针对 ghost/offset 行进行调试。