【发布时间】:2020-06-01 16:23:32
【问题描述】:
我在 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);
}
请注意,我在初始化后再次更改arr[0] = 7; 数组的条目。这将返回以下错误:System.AccessViolationException
H结果=0x80004003
Message=试图读取或写入受保护的内存。这通常表明其他内存已损坏。
来源=
堆栈跟踪:
但是,如果我离开 arr[0] = 7;,它会起作用。
所以我想知道:为什么在这种情况下初始化之后更改数组的条目会有问题?我该如何解决这个问题,即如何在初始化后更改数组的条目并仍然能够将其作为参数传递给 DLL?
【问题讨论】:
-
查看 pinvoke 示例:pinvoke.net/default.aspx/kernel32.LoadLibrary。您在 LoadLibrary 中缺少一个 Marshal。
-
@jdweng:我在示例中添加了元帅,但这还没有解决问题。不过,感谢您的评论!
-
_discon_handle 的值是多少?句柄无效或您需要运行 c# AS ADMIN。要以 ADMIN 身份运行,请创建 VS 的快捷方式。然后右键单击快捷方式并选择以管理员身份运行。
-
在 c# 中,字符串是一个类,其中每个字符是一个或两个字节。在 c 语言中,字符串是一个以 '\0' 结尾的 byte[]。所以使用 MarshalAs(UnmanagedType.LPStr) 将 c# 字符串转换为 c 语言字符串。
-
GetProcAddress 需要是 ANSI。请参阅:pinvoke.net/default.aspx/kernel32.GetProcAddress