[英]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.