在C#中调用c结构。无法封送'***'类型的字段'***'

时间:2017-07-28 09:20:41

标签: c# pinvoke

我得到了一个名为Clib2CS的c项目,它有两个文件,分别是Clib2CS.c和Clib2CS.h。

Clib2CS.h如下:

__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如下:

#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);
 }

这个c项目生成一个Clib2CS.dll,它将在一个c-sharp项目中调用。 c#项目只包含一个名为Program.cs的文件。

Progarm.cs如下:

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);
        }
    }
}
}

运行它,我收到此错误:

  

未处理的异常:System.TypeLoadException:无法编组字段'left'       键入'ConsoleApplication1.BTnode':此类型没有编组支持。

那么,我们如何从c#优雅地调用DLL的c结构?

1 个答案:

答案 0 :(得分:0)

你太近了 我建议你用它来进行字符串转换。

String managedString = Marshal.PtrToStringAnsi((IntPtr) (char *) myUnmanagedString);

您必须知道char*c#中的c不同,c中的字符位于1个字节中,而c#中的字符位于2个字节中所以指针不一样。

你的问题有点小。

  1. 第一种方法是像第一次尝试那样进行编组。

  2. 第二种方法是创建CLI C++ DLL使用您的库或DLL代码,就像在此C项目中一样,因为它是C++所以它很容易使用您的C代码和C#两者都是因为其处理托管代码和非托管代码的性质,因此它会像普通的.net dll一样只需将其添加为引用,这样我就可以了建议查看本文以获取更多信息: