将结构的成员转换为 IntPtr
Converting member of a structure to an IntPtr
我正在为以下 C++ 函数编写绑定:
AvailableNodes(void* handle, Node** headNode)
Connect(void* handle, char* nodeId)
AvailableNodes 函数将 return 使用以下 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
),如果我尝试发送它,我得到一个 Access violation
相反。
有什么想法吗?
试试这样的代码。我更改了 nextNode 在结构中的顺序,因此 c++ 和 c# 结构的顺序相同。我假设在根目录下有一个节点数组和一个 link 节点列表。我还假设节点是从 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
}
}
}
}
我正在为以下 C++ 函数编写绑定:
AvailableNodes(void* handle, Node** headNode)
Connect(void* handle, char* nodeId)
AvailableNodes 函数将 return 使用以下 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
),如果我尝试发送它,我得到一个 Access violation
相反。
有什么想法吗?
试试这样的代码。我更改了 nextNode 在结构中的顺序,因此 c++ 和 c# 结构的顺序相同。我假设在根目录下有一个节点数组和一个 link 节点列表。我还假设节点是从 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
}
}
}
}