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

编程入门 行业动态 更新时间:2024-10-27 08:24:05
本文介绍了如何为P/Invoke声明指向结构的指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在尝试使用 P/调用Interop助手来调用C ++ Dll在C#中.大部分标头都可以很好地转换,但是我遇到了麻烦:

I'm trying to use P/Invoke Interop Assistant to call a C++ Dll in C#. 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;

这将被转换为:

[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 ++代码是这样使用的:

But how do I use m_ThRecs when it's just a System.IntPtr? Is there some way of explicitly declaring it to be a pointer to stTimeHistory_t? The C++ code I'm porting to C# uses it like this:

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

但是如果我在C#中尝试这样做:

but if I try this in C#:

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

我得到:

错误1无法将类型'SlmTest.Program.tagTimeHistory []'隐式转换为'SlmTest.Program.tagTimeHistory'"

Error 1 Cannot implicitly convert type 'SlmTest.Program.tagTimeHistory[]' to '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; }

我得到:

错误CS0208:无法获取其地址,获取其大小或声明一个指向托管类型的指针

error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type

推荐答案

如果您真的要与本机代码互操作,则可以使用fixed运算符:

If you really want to interoperate with the native code, you can use the fixed operator:

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

请注意,C#中的fixed运算符和指针类型需要unsafe功能.并且您可能希望用适当的指针类型替换IntPtr,以提高类型安全性(尽管有一种将指针转换为IntPtr s并返回的方法).

Note that fixed operator and pointer types in C# requires unsafe capability. And you may want to replace IntPtrs with the proper pointer types for more type safety (although there is a method for converting pointers to IntPtrs and back).

执行此操作的另一种方法是通过 Marshal类.

Another way of doing the same is through the methods of Marshal class.

编辑.这是您的有趣的已命名联合结构的修订版不安全定义的示例:

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

您应在代码中定义所有结构,例如stTimeHistory_t(或将不需要的结构替换为通用的IntPtr).

You should define all structures such as stTimeHistory_t in your code (or replace the ones you don't care with generic IntPtrs).

关于使用Marshal创建结构数组:本机内存池没有structure array这样的概念;它只关心字节.因此,例如,您可以使用 Marshal.AllocHGlobal方法:

And regarding creation of structure array with Marshal: native memory pool have no such concept as structure array; all it care is only bytes. So you may, for example, use the 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);

编辑2.关于无法获取其地址,获取其大小或声明一个指向托管类型的指针"错误-您的定义并非完全不受托管.不安全的定义和使用封送处理逻辑的定义并不总是相等的.在这里它认为您的类是托管的",因为其中包含数组引用.尝试固定数组:

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

更多推荐

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

本文发布于:2023-06-10 16:29:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/615054.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:指针   何为   声明   结构   Invoke

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!