簡體   English   中英

如何聲明一個指向P / Invoke結構的指針?

[英]How can I declare a pointer to a struct for P/Invoke?

我正在嘗試使用P / Invoke Interop Assistant在C#中調用C ++ Dll。 大多數頭文件都可以很好地轉換,但是我遇到了麻煩:

#define FULLOCTAVE_BINS                12
#define THIRDOCTAVE_BINS               36

typedef struct tagTimeHistory
{
    UINT m_nAction;
    int m_nFlag;
    int m_nRecordNum; 
    int m_nTimeStamp;
    int m_nMiscStartIndex;
    float m_pfTHFloatVals[256]; // Number of valid values given by m_nNumFloatVals in Settings.
    float m_pfTH11OBAVals[4][FULLOCTAVE_BINS];  // 0-4 spectra given by m_nNumOBA11Vals in Settings
    float m_pfTH13OBAVals[4][THIRDOCTAVE_BINS]; // 0-4 spectra given by m_nNumOBA13Vals in Settings
    float m_fDuration;
} stTimeHistory_t;

typedef struct tagSlmBulkRecords
{
    int nRecType;
    union
    {
        stTimeHistory_t *m_ThRecs;
        stInterval_t    *m_Interval;
        stExceedence_t  *m_Exceedences;
        stRunRecord_t   *m_RunRecord;
        stSpeechData_t  *m_VoiceRecord;
        stSpeechData_t  *m_AudioRecord;
    };
} stSlmBulkRecord_t;

這將被轉換為:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
public struct Anonymous_d2bf9406_c664_4664_9196_800cc23f445a {

    /// stTimeHistory_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_ThRecs;

    /// stInterval_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_Interval;

    /// stExceedence_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_Exceedences;

    /// stRunRecord_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_RunRecord;

    /// stSpeechData_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_VoiceRecord;

    /// stSpeechData_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_AudioRecord;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct tagSlmBulkRecords {

    /// int
    public int nRecType;

    /// Anonymous_d2bf9406_c664_4664_9196_800cc23f445a
    public Anonymous_d2bf9406_c664_4664_9196_800cc23f445a Union1;
}

但是,當m_ThRecs只是System.IntPtr時,該如何使用? 有什么方法可以明確地聲明它是指向stTimeHistory_t的指針? 我要移植到C#的C ++代碼是這樣使用的:

stSlmBulkRecord_t   bulkRecord;
bulkRecord.m_ThRecs = new stTimeHistory_t[dataCounts.m_nNumTH];

但是如果我在C#中嘗試這樣做:

tagSlmBulkRecords bulkRecord;
bulkRecord.Union1.m_ThRecs = new tagTimeHistory[dataCounts.m_nNumTH];

我得到:

錯誤1無法將類型'SlmTest.Program.tagTimeHistory []'隱式轉換為'SlmTest.Program.tagTimeHistory'“

如果我嘗試一個不安全的定義:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct tagTimeHistory
{
    /// UINT->unsigned int
    public uint m_nAction;

    /// int
    public int m_nFlag;

    /// int
    public int m_nRecordNum;

    /// int
    public int m_nTimeStamp;

    /// int
    public int m_nMiscStartIndex;

    /// float[256]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 256, ArraySubType = System.Runtime.InteropServices.UnmanagedType.R4)]
    public float[] m_pfTHFloatVals;

    /// float[48]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 48, ArraySubType = System.Runtime.InteropServices.UnmanagedType.R4)]
    public float[] m_pfTH11OBAVals;

    /// float[144]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 144, ArraySubType = System.Runtime.InteropServices.UnmanagedType.R4)]
    public float[] m_pfTH13OBAVals;

    /// float
    public float m_fDuration;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
public unsafe struct Anonymous_d2bf9406_c664_4664_9196_800cc23f445a
{
    /// stTimeHistory_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public tagTimeHistory *m_ThRecs;
    /// stInterval_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr *m_Interval;
    /// stExceedence_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_Exceedences;
    /// stRunRecord_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_RunRecord;
    /// stSpeechData_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_VoiceRecord;
    /// stSpeechData_t*
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public System.IntPtr m_AudioRecord;
}

我得到:

錯誤CS0208:無法獲取其地址,獲取其大小或聲明一個指向托管類型的指針

如果您確實想與本機代碼互操作,則可以使用fixed運算符:

var array = new tagTimeHistory[dataCounts.m_nNumTH];
fixed (tagTimeHistory* ptr = array)
{
    // do anything with the raw pointer
}

請注意,C#中的fixed運算符和指針類型需要unsafe功能。 而且,您可能希望用適當的指針類型替換IntPtr ,以提高類型安全性(盡管有一種方法可以將指針轉換為IntPtr並返回)。

另一種這樣做的方法是通過Marshal的方法。

編輯。 這是您的有趣的命名聯合結構的修訂的不安全定義的示例:

[StructLayout(LayoutKind.Explicit)]
public unsafe struct Anonymous_d2bf9406_c664_4664_9196_800cc23f445a
{
    [FieldOffset(0)]
    public stTimeHistory_t* m_ThRecs;

    [FieldOffset(0)]
    public stInterval_t* m_Interval;

    [FieldOffset(0)]
    public stExceedence_t* m_Exceedences;

    [FieldOffset(0)]
    public stRunRecord_t* m_RunRecord;

    [FieldOffset(0)]
    public stSpeechData_t* m_VoiceRecord;

    [FieldOffset(0)]
    public stSpeechData_t* m_AudioRecord;
}

您應該在代碼中定義所有結構,例如stTimeHistory_t (或用通用IntPtr替換不需要的結構)。

關於用Marshal創建結構數組:本機內存池沒有structure array這樣的概念; 它只關心字節。 因此,例如,您可以使用Marshal.AllocHGlobal方法

IntPtr myPtr = Marshal.AllocHGlobal(Marshal.SizeOf<tagTimeHistory>() * dataCounts.m_nNumTH);
// ... write something to an array, use it
// And don't forget to free it to prevent memory leaks!
Marshal.FreeHGlobal(myPtr);

編輯2.關於“無法獲取其地址,獲取其大小或聲明一個指向托管類型的指針”錯誤-您的定義不是完全不受托管的。 不安全的定義和使用封送處理邏輯的定義並不總是相等的。 在這里它認為您的類是“托管的”,因為其中包含數組引用。 嘗試固定數組:

[StructLayout(LayoutKind.Sequential)]
public unsafe struct tagTimeHistory
{
    public uint m_nAction;
    public int m_nFlag;
    public int m_nRecordNum;
    public int m_nTimeStamp;
    public int m_nMiscStartIndex;
    public fixed float m_pfTHFloatVals[256];
    public fixed float m_pfTH11OBAVals[48];
    public fixed float m_pfTH13OBAVals[144];
    public float m_fDuration;
}

暫無
暫無

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

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