2014-10-12 37 views
2

我正在嘗試使用P/Invoke Interop Assistant在C#中調用C++ Dll。大多數頭的轉換很好,但我有這個麻煩:我該如何聲明一個指向P/Invoke結構的指針?

#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'「

如果我嘗試unsaf Ë定義:

[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:不能取的地址,獲取的大小,或宣佈一個指向託管類型

+0

將C#中的stSlmBulkRecord_t聲明爲'struct'或'class'嗎? – 2014-10-12 04:06:35

+0

stSlmBulkRecord_t未在C#中聲明,只有tagSlmBulkRecords是一個如上所示的結構。 – parsley72 2014-10-12 05:23:55

+0

這裏沒有明顯的不安全需要 – 2014-10-12 07:32:22

回答

2

如果真想想與本機代碼互操作,可以用fixed運營商:

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

請注意,fixed運算符和C#中的指針類型需要unsafe的能力。而且您可能需要使用正確的指針類型替換IntPtr以獲得更多的類型安全性(雖然有一種將指針轉換爲IntPtr的方法)。

另一種方法是通過Marshal class的方法。

編輯。下面是修改後的不安全定義你的搞笑命名的工會結構的一個樣本:

[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關心的人S)。

關於用Marshal創建結構數組:原生內存池沒有structure array這樣的概念;它所關心的只是字節。所以,你可以,例如,使用Marshal.AllocHGlobal method

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); 

EDIT 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; 
} 
+0

當你說「你可能想用適當的指針類型替換'IntPtr'以獲得更多的類型安全性」,這是如何完成的?或者,我如何使用編組來創建一個結構數組? – parsley72 2014-10-12 05:48:43

+0

我試過了不安全的定義,但是我得到了「錯誤CS0208:無法獲取地址,獲取大小或者聲明指向託管類型的指針」 – parsley72 2014-10-12 06:09:24

+0

@ parsley72,請在您的問題中顯示您的'tagTimeHistory'的定義。我敢打賭,這是'class'而不是'struct'。 – ForNeVeR 2014-10-12 06:11:08

相關問題