我正在尝试在 .NET 中使用 C++ DLL(实现 EMI 协议的第三方库,具有可用的源代码)。我已经成功地完成了编组、调用函数并让一切正常。
当我想从 IntPtr 编组回到 .NET Struct 时会出现问题,这里是代码(按照建议修改 - 删除了“ref”并更改了 AllocHGlobal 以仅分配 emiStruct 的大小):
private EMI emiStruct;
private IntPtr emiIntPtr;
emiIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(emiStruct));
Marshal.StructureToPtr(emiStruct, emiIntPtr, false);
EMIStruct.Error result = emi_init(emiIntPtr, hostname, portNumber, password, shortNumber, windowSize, throughput);
Marshal.PtrToStructure(emiIntPtr, emiStruct);
最后一行 (PtrToStructure) 导致异常“尝试读取或写入受保护的内存。这通常表明其他内存已损坏”。
此外,我可以看到调试输出:
A first chance exception of type 'System.AccessViolationException' occurred in mscorlib.dll
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0xc3fffff8.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x01fffff7.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x00001f1d.
我认为问题出在指针emiIntPtr的内存分配中。虽然,当我运行代码时,连接到服务器时出现问题(例如找不到服务器),随后对 Struct emiStruct 的编组正确完成(没有例外)。仅当连接成功建立并且服务器发送响应时才会出现此问题。
此外,我使用我尝试在 .NET 中使用的同一个 DLL 库编写了一个 C++ 示例应用程序,并且这个应用程序(当我编译它时)运行良好 - 这意味着 C++ DLL 应该没问题并且不会导致崩溃。
此外,我发现了一些提示来检查/取消选中项目编译器的几个属性(使用 JIT,为 x86 cpu 编译它等),不幸的是,这些都没有帮助。
您对问题可能出在哪里或如何在 .NET 中进行正确的 IntPtr 初始化以及 IntPtr 和 Struct 之间的映射有任何建议吗?
感谢大家的回复:
在这里,我添加了 emi_init 函数的 C++ 标头:
FUNC( init)( EMI* emi, /* out */
const char* hostname, /* in */
unsigned short port, /* in */
const char* password, /* in */
const char* origin_addr, /* in */
int window_sz, /* in */
int throughput); /* in */
这是 C# emi_init 声明(我已按照建议删除了 emiPtr 的“ref”属性):
[System.Runtime.InteropServices.DllImport("emi.dll", EntryPoint = "_emi_init")]
public static extern EMIStruct.Error emi_init(
System.IntPtr emiPtr,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string hostname,
ushort port,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string origin_addr,
int window_sz, int throughput);
但是,仍然得到同样的例外。