簡體   English   中英

如何在C#中封送打包結構的非托管緩沖區

[英]How to marshal unmanaged buffer of packed structs in c#

我正在(成功)使用以下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;

名稱字段分配了一個可變長度,以空字符結尾的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#中做了一些粗略的指針駭客操作以逐步執行它,兩次調用Marshal.ReadInt32(以覆蓋前兩個結構字段),然后再調用Marshal.ReadByte幾次以填充一個字節。 []然后將其用作Encoding.Unicode.GetString()的參數...字符串可以很好地顯示,所以它肯定在其中,我只是似乎無法讓編組器正確處理它(即使它能夠?)

任何幫助表示贊賞

史蒂夫

問題是您的C#BAH_RECORD結構中的“名稱”字符串被封送為指向字符串(WCHAR *)的指針,但在C端,它是一個內聯WCHAR緩沖區。 因此,在編組結構時,運行時將讀取緩沖區的前四個字節作為指針,然后嘗試讀取其指向的字符串。

不幸的是,運行時無法自動封送結構內部的可變大小的緩沖區,因此您將需要使用手動封送處理(或您所說的“指針黑客”)。 但是,當您將指針前進到指向緩沖區的位置時,您無需逐個讀取字節,然后將它們轉換為字符串-只需調用Marshal.PtrToStringUni。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM