Reputation: 4423
I am writing bindings for following c++ functions:
AvailableNodes(void* handle, Node** headNode)
Connect(void* handle, char* nodeId)
The AvailableNodes function will return a list of nodes using the Struct
bellow:
typedef struct Node
{
struct Node *nextNode;
unsigned long nodeID;
char data[256];
} Node;
After creating the necessary bindings I ended up with the following struct in C#
:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Node
{
public ulong id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] data;
public IntPtr nextNode;
}
To move forward, I have to send a pointer to Node.data
as a parameter to the Connect
function, however, after marshalling (using Marshal.PtrToStructure
), if I try to send it, I get an Access violation
instead.
Any ideas?
Upvotes: 1
Views: 451
Reputation: 34433
Try code like this. I changed the order of where nextNode is in structure so the c++ and c# structures are in the same order. I assumed that there is an array of Nodes at root and a link list of Nodes. I also assumed the Nodes were being returned from 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
}
}
}
}
Upvotes: 2