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

2024-04-06

我正在尝试使用P/Invoke 互操作助手 http://clrinterop.codeplex.com/releases/view/14120在 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];

I get:

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

I get:

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


If you really想要与本机代码互操作,可以使用fixed操作员:

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

注意fixedC# 中的运算符和指针类型需要unsafe能力。你可能想更换IntPtr具有适当的指针类型以提高类型安全性(尽管有一种方法可以将指针转换为IntPtrs 并返回)。

执行相同操作的另一种方法是通过以下方法Marshal class http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal(v=vs.110).aspx.

EDIT.这是修订后的示例unsafe你有趣的命名联合结构的定义:

[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在你的代码中(或者用通用的替换你不关心的代码)IntPtrs).

关于结构数组的创建Marshal:本机内存池没有这样的概念structure array;它只关心字节。例如,您可以使用Marshal.AllocHGlobal method http://msdn.microsoft.com/en-us/library/s69bkh17(v=vs.110).aspx:

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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何为 P/Invoke 声明指向结构的指针? 的相关文章

  • 锁定 ASP.NET 应用程序变量

    我在 ASP NET 应用程序中使用第三方 Web 服务 对第 3 方 Web 服务的调用必须同步 但 ASP NET 显然是多线程的 并且可能会发出多个页面请求 从而导致对第 3 方 Web 服务的同时调用 对 Web 服务的调用封装在自
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • MFC CList 支持复制分配吗?

    我在 MSVC 中查找了 CList 定义afxtempl h http www cppdoc com example mfc classdoc MFC AFXTEMPL H html并记录在MSDN http msdn microsoft
  • 异常堆栈跟踪不显示抛出异常的位置

    通常 当我抛出异常 捕获它并打印出堆栈跟踪时 我会看到抛出异常的调用 导致该异常的调用 导致该异常的调用that 依此类推回到整个程序的根 现在它只向我显示异常所在的调用caught 而不是它所在的地方thrown 我不明白是什么改变导致了
  • 在 ASP.NET MVC 中将模型从视图传递到控制器

    我正在 ASP NET MVC 中开发我的第一个应用程序 但遇到了一个我无法解决的问题 即使在阅读了整个互联网之后也是如此 因此 我有几个使用视图模型创建的视图 它们是报告 这些视图模型是根据用户选择标准填充的 我正在尝试构建一种接受模型并
  • C# 编译器数字文字

    有谁知道 C 编译器数字文字修饰符的完整列表 默认情况下 声明 0 使其成为 Int32 声明 0 0 使其成为 Double 我可以在末尾使用文字修饰符 f 来确保某些内容被视为 Single 例如像这样 var x 0 x is Int
  • 在 C# 中何时使用 ArrayList 而不是 array[]?

    我经常使用一个ArrayList而不是 正常 array 当我使用时 我感觉好像我在作弊 或懒惰 ArrayList 什么时候可以使用ArrayList在数组上 数组是强类型的 并且可以很好地用作参数 如果您知道集合的长度并且它是固定的 则
  • 通过 C# Mailkit / Mimekit 发送电子邮件,但出现服务器证书错误

    Visual Studio 2015 中的 0 代码 1 我正在使用 Mailkit 最新版本 1 18 1 1 从我自己的电子邮件服务器发送电子邮件 2 电子邮件服务器具有不受信任的自签名证书 3 我在代码中添加了以下两行 以忽略服务器证
  • 如何使用递归查找数字中的最小元素 [C]

    好的 所以我正在准备我的 C 考试 当谈到递归时我有点卡住了我是大学一年级的学生 这对我来说似乎有点困难 练习要求在给定的数字中使用递归函数我需要找到最小的元素 例如 52873 是 2 程序需要打印 2 include
  • Xamarin - SignalR 挂在连接上

    我正在尝试将我的 Xamarin 应用程序连接到托管在 Azure 上的 SignalR 后端 我遇到的问题是每次我在 HubConnection 上调用 StartAsync 时 它都会挂起客户端并且请求永远不会完成 我尝试通过应用程序进
  • 为什么不能调用带有 auto& 参数的 const mutable lambda?

    include
  • 使用 OleDbCommandBuilder 时访问 SQL 语法错误

    我要在 C 中使用 OleDbDataAdapter 在 Access 数据库中插入数据 但收到错误消息INSERT INTO 命令中的语法错误 BackgroundWorker worker new BackgroundWorker Ol
  • C++ 到 C# 事件处理

    所以我有我的C WinForm 应用程序 我从中调用我的C CLI MFC dll图书馆 但也有一些events在我的 C 库上 甚至此事件也发生在该库的本机 非 CLI 部分 我需要从我的 C 应用程序调用一些代码 并获取一些有关此事件的
  • EnumDisplayDevices 与 WMI Win32_DesktopMonitor,如何检测活动监视器?

    对于我当前的 C 项目 我需要为在大量计算机上连接并处于活动状态的每个监视器检测一个唯一的字符串 研究指出了两种选择 使用 WMI 并查询 Win32 DesktopMonitor 以获取所有活动监视器 使用 PNPDeviceID 来唯一
  • 为什么 f(i = -1, i = -1) 是未定义的行为?

    我正在读关于违反评估顺序 http en cppreference com w cpp language eval order 他们举了一个令我困惑的例子 1 如果标量对象上的副作用相对于同一标量对象上的另一个副作用是无序的 则行为未定义
  • 从 NumPy 数组到 Mat 的 C++ 转换 (OpenCV)

    我正在围绕 ArUco 增强现实库 基于 OpenCV 编写一个薄包装器 我试图构建的界面非常简单 Python 将图像传递给 C 代码 C 代码检测标记并将其位置和其他信息作为字典元组返回给 Python 但是 我不知道如何在 Pytho
  • 无法识别解决方案文件夹中的 Visual Studio 2017 Nuget.config

    我在使用 Visual Studio 2017 时遇到问题 新的解决方案不断引用 C Users yopa AppData Roaming NuGet Nuget config 中意外位置的 Nuget config 文件 我已将 nuge
  • 将 char 绑定到枚举类型

    我有一段与此非常相似的代码 class someclass public enum Section START MID END vector section Full void ex for int i 0 i section
  • 使用 C# 动态创建按钮并按预定义的顺序放置它们

    NET 4 5 C 创建 Windows 窗体 我想动态创建和添加按钮并为其分配单击事件 但希望它们以特定的方式动态放置 就像图像一样 我的问题是如何以上述方式动态放置按钮 即 4x4 格式 一行 4 个按钮 4 列 但行数不受限制 是否可
  • 嵌入式二进制资源 - 如何枚举嵌入的图像文件?

    我按照中的说明进行操作这本书 http www apress com book view 9781430225492 关于资源等的章节 我不太明白的是 如何替换它 images Add new BitmapImage new Uri Ima

随机推荐