如何解决导入非托管dll并将指针复制到c#中的字节数组
我试图将一些非托管的ada代码导入C#并使用元帅复制将其复制到字节数组中,但是我遇到了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,managedArray.Length);
}
catch
{
Marshal.FreeHGlobal(errors);
}
finally
{
Marshal.FreeHGlobal(errors);
}
return managedArray;
}
解决方法
鉴于问题中有关被调用的Ada子程序的信息有限,因此假设调用者必须分配字符数组(字符串缓冲区),则下面的最小示例有效(基于封送文档here和用GNAT here构建DLL库的SO答案:
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
Program.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();
}
}
}
,
结果证明,我只需要将字节数组传递给函数调用并将其封送为LPArray。
[DllImport("Interpreter.dll",EntryPoint = "ReadErrors",CallingConvention = CallingConvention.Cdecl,SetLastError = true)]
public static extern void ReadErrors([Out,MarshalAs(UnmanagedType.LPArray)] byte [] errors);
class Program
{
static void Main(string[] args)
{
byte[] errors = new byte[8];
ReadErrors(errors);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。