I get a c project named Clib2CS with two files which are Clib2CS.c and Clib2CS.h.
Clib2CS.h is as following:
__declspec(dllexport) typedef struct BTreeNode {
int value;
struct BTreeNode* left;
struct BTreeNode* right;
}BTnode;
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen);
__declspec(dllexport) void bulidTree(BTnode* root, int value);
Clib2CS.c is as following:
#include "Clib2CS.h"
#include <stdio.h>
#include <stdlib.h>
unsigned unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen)
{
return 42;
}
void bulidTree(BTnode* root, int value) {
if (root == NULL) {
BTnode* node = (BTnode*)malloc(sizeof(BTnode));
node->value = value;
}
if (value < root->value) bulidTree(root->left, value);
else bulidTree(root->right, value);
}
This c project generates a Clib2CS.dll which will be called in a c-sharp project. The c# project contains only one file named Program.cs.
Progarm.cs is as following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
[StructLayout(LayoutKind.Sequential)]
public class BTnode {
public int value;
[MarshalAs(UnmanagedType.LPStruct)]
public BTnode left;
[MarshalAs(UnmanagedType.LPStruct)]
public BTnode right;
}
class Program
{
[DllImport("Clib2CS.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe static extern UInt32 ConnectSession(UInt32 handle, char* publickey, char publicKeyLen);
[DllImport("Clib2CS.dll", CharSet = CharSet.Auto)]
unsafe static extern void bulidTree([In, Out, MarshalAs(UnmanagedType.LPStruct)] BTnode root, int value);
public unsafe static UInt32 GetConnectSession(UInt32 handle, string publickey, char publicKeyLen) {
// "Convert" string to char*
char* pubKey;
fixed (char* bptr = publickey) {
pubKey = (char*)bptr;
}
return ConnectSession(handle, pubKey, publicKeyLen);
}
static void Main(string[] args)
{
UInt32 ret = GetConnectSession((UInt32)1, "helloworld", 'c');
Console.WriteLine("####################: {0}", ret);
BTnode root = new BTnode();
root.value = 666;
Console.WriteLine("value of root is : {0}", root.value);
int[] vec = { 4, 5, 6, 7, 8, 9 };
foreach (int item in vec) {
bulidTree(root, item);
}
Console.WriteLine("----------------------------------------------");
for (; root != null; root = root.right) {
Console.WriteLine("the tree node is: {0}", root.value);
}
}
}
}
Run it, and I get this error:
Unhandled Exception:System.TypeLoadException: Cannot marshal field 'left' of type 'ConsoleApplication1.BTnode': There is no marshaling support for this type.
so, how do we invoke c struct of DLL from c# gracefully?