系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException

System.AccessViolationException when handing an array over to a dynamically loaded c++ DLL in C#

本文关键字:c++DLL 加载 AccessViolationException 动态 数组 系统      更新时间:2023-10-16

我正在一个C#程序中动态加载一个最初用C++编写的DLL,并将一个数组作为参数移交,如下所示:

// That's only for being able to load the DLL dynamically during runtime
[DllImport(@"C:WindowsSystem32kernel32.dll", EntryPoint = "LoadLibrary")]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string dllToLoad);
[DllImport(@"C:WindowsSystem32kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport(@"C:WindowsSystem32kernel32.dll", EntryPoint = "FreeLibrary")]
public static extern bool FreeLibrary(IntPtr hModule);
// Delegate with function signature for the DISCON function
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U4)]
delegate void DisconDelegate(float[] arr);
static void Main(string[] args){
// Load DLL
IntPtr _dllhandle = IntPtr.Zero;
DisconDelegate _discon = null;
string dllPath = @"D:myProjectTrivial_discon.dll";
_dllhandle = LoadLibrary(dllPath);
var discon_handle = GetProcAddress(_dllhandle, "DISCON");
_discon = (DisconDelegate)Marshal.GetDelegateForFunctionPointer(discon_handle, typeof(DisconDelegate));
// create the array and change it after its initialization
float[] arr = new float[] { 5, 6, 7 };
arr[0] = 7;
_discon(arr);
}

请注意,初始化后我再次使用arr[0] = 7;作为数组的一个条目进行更改。这将返回以下错误:系统。AccessViolationExceptionHResult=0x80004003消息=试图读取或写入受保护的内存。这通常表示其他内存已损坏。来源=StackTrace:

但是,如果我不使用arr[0] = 7;,它会起作用。

所以我想知道:为什么在这种情况下初始化后更改数组的条目会有问题?我该如何解决这个问题,即如何在初始化后更改数组的条目,并且仍然能够将其作为参数移交给DLL?

您需要将数组从托管内存转换为非托管内存。尝试以下

static void Main(string[] args)
{
Data data = new Data();
data.arr = new float[] { 5, 6, 7 };
IntPtr arrPtr = Marshal.AllocHGlobal(data.arr.Length * sizeof(float));
Marshal.StructureToPtr(data, arrPtr, true);
}
[StructLayout(LayoutKind.Sequential)]
public struct Data
{
public float[] arr;
}