C# System.AccessViolationException将数组移交给动态加载的c++;C语言中的动态链接库# < >我动态加载一个在C++程序中用C++编写的DLL,并把数组交给这样的一个参数: // 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); }

C# System.AccessViolationException将数组移交给动态加载的c++;C语言中的动态链接库# < >我动态加载一个在C++程序中用C++编写的DLL,并把数组交给这样的一个参数: // 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); },c#,c++,arrays,dll,pinvoke,C#,C++,Arrays,Dll,Pinvoke,请注意,我在初始化后再次更改arr[0]=7数组的一个条目。这将返回以下错误:System.AccessViolationException HResult=0x80004003 消息=尝试读取或写入受保护内存。这通常表示其他内存已损坏。 来源= 堆栈跟踪: 但是,如果我离开arr[0]=7走开,它工作了 所以我想知道:为什么在这个上下文中初始化之后更改数组的条目会有问题?如何解决这个问题,即如何在初始化后更改数组的条目,并且仍然能够将其作为参数传递给DLL?您需要将数组从托管内存转换为非托管

请注意,我在初始化后再次更改
arr[0]=7数组的一个条目。这将返回以下错误:System.AccessViolationException
HResult=0x80004003
消息=尝试读取或写入受保护内存。这通常表示其他内存已损坏。
来源=
堆栈跟踪:

但是,如果我离开
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;
        }

请参阅pinvoke示例:。LoadLibrary中缺少封送处理。@jdweng:我添加了示例中的封送处理,但这并没有解决问题。不过,谢谢你的评论!_discon_handle的值是多少?要么句柄无效,要么需要以管理员身份运行c#。要以管理员身份运行,请创建VS的快捷方式。然后右键单击快捷方式并选择以管理员身份运行。在c#中,字符串是一个类,其中每个字符都是一个或两个字节。在c语言中,字符串是以“\0”结尾的字节[]。因此,使用Marshallas(UnmanagedType.LPStr)将c#字符串转换为c语言字符串。GetProcAddress需要是ANSI。请参阅:这似乎还不是解决方案,因为我现在在
Marshal.StructureToPtr(data,arrPtr,true)行中获得异常
System.AccessViolationException
而不是与DLL调用
\u discon(arrPtr)
(这是后面的一个)在同一行中。您是否使用最新发布的代码?我对代码进行了更新,并测试了现在发布的内容,没有出现异常。我再次测试了您的代码。似乎如果我在打开VisualStudio后运行一次,它就会工作。如果我再次运行它,我会再次收到异常
System.AccessViolationException:'尝试读取或写入受保护内存。这通常表示其他内存已损坏。
它还会在以后的运行中引发此异常。我怀疑返回值有问题,因为它只运行一次。函数不返回任何内容,那么为什么有:[return:marshallas(UnmanagedType.U4)]IntPtr是4个字节,看起来不错。函数是否返回值?这种奇怪的行为甚至在discon(arr)时发生被注释掉。该函数不返回任何值,但会更改
arr
的值,该值将用作“输出”。