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

0

I am dynamically loading a DLL originally written in C++ in a C# program and hand over an array as an argument like this:

// 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);
}

Note that I change after the initialization once again with arr[0] = 7; an entry of the array. This returns the following error: System.AccessViolationException HResult=0x80004003 Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Source= StackTrace:

However, if I leave arr[0] = 7; away, it works.

So I am wondering: Why is it problematic to change an entry of the array after the initialization in this context? And how can I fix this problem, i.e., how to change the entries of an array after its initialization and still being able to hand it over as an argument to the DLL?

c#
c++
arrays
dll
pinvoke
asked on Stack Overflow Feb 17, 2020 by hugo99 • edited Feb 18, 2020 by Mr.C64

1 Answer

-2

You need to convert the array from managed memory to unmanaged memory. Try following

       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;
        }
answered on Stack Overflow Feb 18, 2020 by jdweng

User contributions licensed under CC BY-SA 3.0