marshalling - 导入非托管 dll 并将指针复制到 c# 中的字节数组
问题描述
我正在尝试将一些非托管 ada 代码导入 C# 并使用 Marshal Copy 将其复制到字节数组中,但是我得到了 System.AccessViolationException。你有什么想法为什么会这样。
[DllImport(@"Interpreter.dll", EntryPoint = "ReadErrors", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.AsAny)]
public static extern void ReadErrors(out IntPtr errors);
static IntPtr _errors;
static unsafe void Main(string[] args)
{
ReadErrors(out _errors);
var managedArray = CopyToByteArrayWithMarshalCopy(_errors);
}
static byte[] CopyToByteArrayWithMarshalCopy(IntPtr errors)
{
byte[] managedArray = new byte[Marshal.SizeOf(errors)];
try
{
Marshal.Copy(errors, managedArray, 0, managedArray.Length);
}
catch
{
Marshal.FreeHGlobal(errors);
}
finally
{
Marshal.FreeHGlobal(errors);
}
return managedArray;
}
解决方案
鉴于问题中有关被调用的 Ada 子程序的信息有限,因此假设调用者必须分配字符数组(字符串缓冲区),下面的最小示例有效(基于此处的编组文档和关于构建 DLL 库的 SO 答案这里有 GNAT ):
src/foo.ads
with Interfaces.C;
package Foo is
package C renames Interfaces.C;
procedure Initialize
with Export, Convention => C;
procedure Finalize
with Export, Convention => C;
subtype Error_T is C.char_array (1 .. 8);
procedure Read_Errors_S (Error : in out Error_T)
with Export, Convention => C;
end Foo;
src/foo.adb
package body Foo is
----------------
-- Initialize --
----------------
procedure Initialize is
procedure fooinit with Import; -- Generated by binder.
begin
fooinit;
end Initialize;
--------------
-- Finalize --
--------------
procedure Finalize is
procedure foofinal with Import; -- Generated by binder.
begin
foofinal;
end Finalize;
-------------------
-- Read_Errors_S --
-------------------
procedure Read_Errors_S (Error : in out Error_T) is
begin
Error := C.To_C ("Error 1");
end Read_Errors_S;
end Foo;
foo.gpr
library project Foo is
for Library_Kind use "dynamic";
for Library_Name use "foo";
for Library_Interface use ("foo");
for Library_Auto_Init use "False";
for Library_Dir use "lib";
for Object_Dir use "obj";
for Source_Dirs use ("src");
end Foo;
lib/libfoo.def
LIBRARY LIBFOO
EXPORTS
initialize
finalize
read_errors_s
程序.cs
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApp
{
internal static class LibFoo
{
[DllImport(@"libfoo.dll",
EntryPoint = "initialize",
CallingConvention = CallingConvention.Cdecl)]
public static extern void Init();
[DllImport(@"libfoo.dll",
EntryPoint = "finalize",
CallingConvention = CallingConvention.Cdecl)]
public static extern void Final();
[DllImport(@"libfoo.dll",
EntryPoint = "read_errors_s",
CallingConvention = CallingConvention.Cdecl)]
public static extern void ReadErrors(StringBuilder error);
}
public static class Program
{
public static void Main()
{
LibFoo.Init();
// Using StringBuilder to allocate a string buffer.
var sb = new StringBuilder(8);
LibFoo.ReadErrors(sb);
Console.WriteLine(sb.ToString());
LibFoo.Final();
}
}
}
推荐阅读
- vba - OLEobjects 文本框可以可见但不可编辑吗?
- r - 大型数据集跨因子的时间序列密度图
- haskell - 如何在 CPS 中构造更高级别的 Coyoneda 类型的值?
- reactjs - 在 React 中过滤后访问过滤后的数据
- audio - TS 文件上的音频逐渐不同步
- java - 获取android屏幕/窗口大小问题
- python - python for 循环:这是做什么的?
- python - 如何将“只读”查找表传递给 numpy 以避免 GIL
- c# - 如何通过输入字段将空(整数)值发送到 SQL
- mesibo - Mesibo - Javascript 错误:d.profile 在 mesibo.js 中未定义