[英]Pinvoke struct translation from C++
以下是一些经过验证的C ++:
typedef struct
{
PVOID buffer;
UINT32 length;
} DATA_BUFFER;
typedef struct
{
DATA_BUFFER TxBuf [1];
DATA_BUFFER RxBuf [1];
} JVM_COMM_BUFFER;
UINT32 SendAndRecv(
IN JHI_HANDLE handle,
IN CHAR* AppId,
INOUT JVM_COMM_BUFFER* pComm
);
以下是我尝试将其移植到C#的尝试:
[StructLayout(LayoutKind.Sequential)]
public struct DATA_BUFFER
{
public byte[] buffer;
public uint length;
}
[StructLayout(LayoutKind.Sequential)]
public struct JVM_COMM_BUFFER
{
public DATA_BUFFER TxBuf;
public DATA_BUFFER RxBuf;
}
[DllImport("jhi.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern UInt32 SendAndRecv(IntPtr handle, string AppId, ref JVM_COMM_BUFFER pComm);
封送处理不会在C#中引发异常,但是对于C ++和C#版本,结果是不同的。 对我缺少的东西有任何想法吗?
问题可能出在您的第一个结构中。 C ++定义包括一个指向数据缓冲区的指针,但Marshaller无法将其直接转换为.NET byte[]
(或者,如果将其转换为另一个方向,它可能会将byte[]
转换为无效的指针,因此您的非法参数是错误)。 相反,您可以分两个步骤手动执行此操作:
[StructLayout(LayoutKind.Sequential)]
public struct DATA_BUFFER
{
public IntPtr buffer;
public uint length;
}
然后使用Marshal
手动读取缓冲区(这只是我对Marshal
API的记忆中的一个快速示例):
var txBufBytes = new byte[pComm.TxBuf.length];
Marshal.Copy(pComm.TxBuff.buffer, 0, pComm.TxBuf.length);
除此之外,正如注释中提到的CharSet.Ansi
如果您的本机代码采用非Unicode /宽字符,则可能需要将CharSet
设置为CharSet.Ansi
。
最后,第二个结构的C ++定义似乎定义了单元素数组,该数组实际上可能是指针,而不是将结构存储在内存中。 如果是这种情况,您可能必须替换定义以对Interop使用IntPtr
,然后使用Marshal.PtrToStructure
获取实际结构。
通过比较C ++中的sizeof(...)
和C#中的Marshal.SizeOf(...)
来获得结构定义,您至少应该比较结构大小是否相同。
鉴于您在注释中所说的,您应该能够使用我上面描述的DATA_BUFFER
修改以及用于JVM_COMM_BUFFER
的原始结构定义
[StructLayout(LayoutKind.Sequential)]
struct JVM_COMM_BUFFER
{
public DATA_BUFFER TxBuf;
public DATA_BUFFER RxBuf;
}
结合对DllImport
的轻微修改
[DllImport("jhi.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern UInt32 SendAndRecv(IntPtr handle, string AppId, [In, Out] ref JVM_COMM_BUFFER pComm);
CharSet.Ansi
对于确保将.NET字符串正确地编组为ansi字符串非常重要(假设您的本机C函数不希望使用wchar_t
字符串类型)。 可能不需要[In, Out]
属性,但可能会提示编组如何正确控制该参数。
如果JVM_COMM_BUFFER
确实是INOUT
,并且在调用该函数之前预先填充了数据,则可能需要确保数据全部有效。 您正在调用的函数可能具有有关其参数期望值的文档。 但是,此处的定义应根据您提供的C ++定义正确地编组。
问题是仅分配内存和分配固定对象之间的区别。 一旦将其切换到固定对象,则除了缓冲区字段之外,没有任何IntPtrs的签名就可以正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.