System.AccessViolationException при передаче массива динамически загружаемой c ++ DLL в C# - PullRequest
0 голосов
/ 17 февраля 2020

Я динамически загружаю DLL, изначально написанную на C ++, в программе C# и передаю массив в качестве аргумента, подобного следующему:

// That's only for being able to load the DLL dynamically during runtime
[DllImport(@"C:\Windows\System32\kernel32.dll", EntryPoint = "LoadLibrary")]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string dllToLoad);

[DllImport(@"C:\Windows\System32\kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[DllImport(@"C:\Windows\System32\kernel32.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:\myProject\Trivial_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; запись массива. Это возвращает следующую ошибку: System.AccessViolationException HResult = 0x80004003 Сообщение = Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. Source = StackTrace:

Однако, если я оставлю arr[0] = 7;, это сработает.

Поэтому мне интересно: почему c проблематично изменить запись массива после инициализации в этом контексте? И как я могу исправить эту проблему, т. Е. Как изменить записи массива после его инициализации и при этом сохранить его в качестве аргумента для DLL?

1 Ответ

0 голосов
/ 18 февраля 2020

Вам необходимо преобразовать массив из управляемой памяти в неуправляемую память. Попробуйте следовать

       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;
        }
...