【问题标题】:Converting member of a structure to an IntPtr将结构的成员转换为 IntPtr
【发布时间】:2020-05-23 22:35:39
【问题描述】:

我正在为以下 c++ 函数编写绑定:

AvailableNodes(void* handle, Node** headNode)

Connect(void* handle, char* nodeId)

AvailableNodes 函数将使用下面的Struct 返回节点列表:

typedef struct Node
{
    struct Node    *nextNode;
    unsigned long   nodeID;
    char            data[256];
} Node;

创建必要的绑定后,我在C# 中得到了以下结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Node
{
    public ulong id;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public char[] data;
    public IntPtr nextNode;
}

要继续前进,我必须将指向Node.data 的指针作为Connect 函数的参数发送,但是,在编组之后(使用Marshal.PtrToStructure),如果我尝试发送它,我会得到@987654330 @ 代替。

有什么想法吗?

【问题讨论】:

  • c# 结构和 c++ 结构的大小必须完全相同。 C++ 有一个属性 struct Node *nextNode;这不在 c# 结构中。您想在内存中按顺序创建一个具有 X 个节点的内存块。不是链接列表。
  • C# 不接受自引用结构。但这里的主要问题是将指向Node.data 的指针发送回本机dll。
  • 为什么需要链表?为什么不是节点数组?在 C# 中创建链表会很困难。您需要在非托管内存中有 IntPtr。
  • @jdweng 我唯一得到的是一个 dll 及其头文件。
  • 如果你只返回 Node** headNode 那么链接列表不是问题。仅当您尝试在 c# 中创建链接列表时。但是 Node** headNode 并不意味着链接列表。它是一个链接列表数组。

标签: c# interop marshalling


【解决方案1】:

试试这样的代码。我更改了 nextNode 在结构中的顺序,因此 c++ 和 c# 结构的顺序相同。我假设在根目录中有一个节点数组和一个节点链接列表。我还假设节点是从 c++ 返回的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("Connect", CallingConvention = CallingConvention.Cdecl)]
        static void Connect(out uint handle, [MarshalAs(UnmanagedType.AnsiBStr)] string nodeId);

        [DllImport("AvailableNodes", CallingConvention = CallingConvention.Cdecl)]
        static void AvailableNodes(uint handle, out IntPtr headNode);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct Node
        {
            public IntPtr nextNode;
            [MarshalAs(UnmanagedType.U4)]
            public uint id;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] data;

        }

        static void Main(string[] args)
        {
            string id = "abc";
            uint handle = 0;
            Connect(out handle, id);

            IntPtr ptr = IntPtr.Zero;
            AvailableNodes(handle, out ptr);

            List<List<Node>> nodes = null;
            List<Node> listNode;

            //enumerate through array of nodes
            while (ptr != IntPtr.Zero)
            {
                listNode = new List<Node>();
                if (nodes == null) nodes = new List<List<Node>>();
                nodes.Add(listNode);
                Node newNode = (Node)Marshal.PtrToStructure(ptr, typeof(Node));
                listNode.Add(newNode);
                // enumerate through link list
                while (newNode.nextNode != IntPtr.Zero)
                {
                    newNode = (Node)Marshal.PtrToStructure(ptr, typeof(Node));
                    listNode.Add(newNode);
                }
                ptr += 4;  //I think 4 is correct since a ptr is 4 bytes
            }
        }
    }
}

【讨论】:

  • AnsiBStr 在这里是错误的。该参数不需要注释。结构的数据字段需要是byte[]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-10
  • 2021-08-05
相关资源
最近更新 更多