- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在(成功地)使用以下 pinvoke 签名在 c# 中调用 Windows FilterSendMessage 函数:
[DllImport("fltlib.dll")]
public static extern IntPtr FilterSendMessage(
IntPtr hPort,
IntPtr inBuffer,
UInt32 inBufferSize,
IntPtr outBuffer,
UInt32 outBufferSize,
out UInt32 bytesReturned);
outBuffer 参数填充了任意数量的结构(一个接一个地打包),在 C 中定义为:
typedef struct _BAH_RECORD {
int evt
int len;
WCHAR name[1];
} BAH_RECORD, *PBAH_RECORD;
name 字段被分配了一个可变长度的、以 null 结尾的 unicode 字符串。 len 字段描述了结构的总大小(以字节为单位)(包括名称字符串)。我相信在事物的非托管方面处理结构的方式没有任何问题。
当我尝试将 outBuffer 编码为 BAH_RECORD 结构的实例时,我的问题出现了,在 c# 中定义为:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct BAH_RECORD
{
public UInt32 evt;
public UInt32 len;
public string name;
}
IntPtr outBuffer = Marshal.AllocHGlobal(OUT_BUFFER_SIZE);
hResult = Win32.FilterSendMessage(hPortHandle, inBuffer, IN_BUFFER_SIZE, outBuffer, OUT_BUFFER_SIZE, out bytesReturned);
BAH_RECORD bah = (BAH_RECORD)Marshal.PtrToStructure(outBuffer, typeof(BAH_RECORD));
<snip>
如果我尝试打印/查看/显示 bah.name,我得到的是垃圾...
为了确认 outBuffer 确实包含有效数据,我在 c# 中做了一些粗略的指针 hackery 来遍历它,调用 Marshal.ReadInt32 两次(覆盖前 2 个结构字段),然后 Marshal.ReadByte 几次以填充一个 byte[] 然后我将其用作 Encoding.Unicode.GetString() 的参数...字符串输出正常,所以它肯定在那里,我似乎无法让编码器正确处理它(如果可以的话?)
感谢任何帮助
史蒂夫
最佳答案
问题是 C# BAH_RECORD 结构中的“名称”字符串被编码为指向字符串 (WCHAR*) 的指针,但在 C 端它是一个内联 WCHAR 缓冲区。因此,当您编码结构时,运行时会将缓冲区的前四个字节作为指针读取,然后尝试读取它指向的字符串。
不幸的是,运行时无法自动编码结构内可变大小的缓冲区,因此您将需要使用手动编码(或如您所说的“指针黑客”)。但是当您将指针指向缓冲区时,您不需要单独读取字节然后将它们转换为字符串 - 只需调用 Marshal.PtrToStringUni。
关于c# - 如何在 C# 中编码打包结构的非托管缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/506231/
我是一名优秀的程序员,十分优秀!