简体   繁体   English

如何声明一个指向P / Invoke结构的指针?

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

I'm trying to use P/Invoke Interop Assistant to call a C++ Dll in C#. 我正在尝试使用P / Invoke Interop Assistant在C#中调用C ++ Dll。 Most of the header is converted fine but I'm having trouble with this: 大多数头文件都可以很好地转换,但是我遇到了麻烦:

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

This is being converted to: 这将被转换为:

[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;
}

But how do I use m_ThRecs when it's just a System.IntPtr? 但是,当m_ThRecs只是System.IntPtr时,该如何使用? Is there some way of explicitly declaring it to be a pointer to stTimeHistory_t? 有什么方法可以明确地声明它是指向stTimeHistory_t的指针? The C++ code I'm porting to C# uses it like this: 我要移植到C#的C ++代码是这样使用的:

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

but if I try this in C#: 但是如果我在C#中尝试这样做:

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

I get: 我得到:

Error 1 Cannot implicitly convert type 'SlmTest.Program.tagTimeHistory[]' to 'SlmTest.Program.tagTimeHistory'" 错误1无法将类型'SlmTest.Program.tagTimeHistory []'隐式转换为'SlmTest.Program.tagTimeHistory'“

If I try an unsafe definition: 如果我尝试一个不安全的定义:

[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;
}

I get: 我得到:

error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type 错误CS0208:无法获取其地址,获取其大小或声明一个指向托管类型的指针

If you really want to interoperate with the native code, you can use the fixed operator: 如果您确实想与本机代码互操作,则可以使用fixed运算符:

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

Note that fixed operator and pointer types in C# requires unsafe capability. 请注意,C#中的fixed运算符和指针类型需要unsafe功能。 And you may want to replace IntPtr s with the proper pointer types for more type safety (although there is a method for converting pointers to IntPtr s and back). 而且,您可能希望用适当的指针类型替换IntPtr ,以提高类型安全性(尽管有一种方法可以将指针转换为IntPtr并返回)。

Another way of doing the same is through the methods of Marshal class . 另一种这样做的方法是通过Marshal的方法。

EDIT. 编辑。 Here is a sample of the revised unsafe definition of your funny named union structure: 这是您的有趣的命名联合结构的修订的不安全定义的示例:

[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;
}

You should define all structures such as stTimeHistory_t in your code (or replace the ones you don't care with generic IntPtr s). 您应该在代码中定义所有结构,例如stTimeHistory_t (或用通用IntPtr替换不需要的结构)。

And regarding creation of structure array with Marshal : native memory pool have no such concept as structure array ; 关于用Marshal创建结构数组:本机内存池没有structure array这样的概念; all it care is only bytes. 它只关心字节。 So you may, for example, use the Marshal.AllocHGlobal method : 因此,例如,您可以使用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);

EDIT 2. Regarding the "Cannot take the address of, get the size of, or declare a pointer to a managed type" error - your definition is not fully unmanaged. 编辑2.关于“无法获取其地址,获取其大小或声明一个指向托管类型的指针”错误-您的定义不是完全不受托管的。 Unsafe definitions and the ones using the marshaling logic are not always equal; 不安全的定义和使用封送处理逻辑的定义并不总是相等的。 here it thinks your class is "managed" because of array references in it. 在这里它认为您的类是“托管的”,因为其中包含数组引用。 Try fixed arrays: 尝试固定数组:

[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