Converting member of a structure to an IntPtr

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

Answers (1)

jdweng
jdweng

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

Related Questions