C#如何调用C++的DLL的结构体数组指针

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#如何调用C++的DLL的结构体数组指针相关的知识,希望对你有一定的参考价值。

C接口

struct PointVec3f//储存XYZ的坐标值.
float xValue;
float yValue;
float zValue;
;
extern "C" __declspec(dllimport) void getPointCloud(PointVec3f *points, int pointNum);

C#定义
public struct PointVec3f

[MarshalAs(UnmanagedType.R4)]
public float xValue;
[MarshalAs(UnmanagedType.R4)]
public float yValue;
[MarshalAs(UnmanagedType.R4)]
public float zValue;
;
PointVec3f[] points =new PointVec3f[NUM]; //points结构体数组的值我已经获取到了,想请问怎么传指针到PointVec3f *points中!Ref的方法试过了,不行!有没有其他方法,急!!
要求:1.写出C#引用接口函数的定义。
2.写出points传值给getPointCloud(PointVec3f *points, int pointNum)的过程。
可以的有分加哦!!

参考技术A 调用方法:
1、添加引用
右击项目-添加引用-浏览 找到本地的dll文件
2、using 该dll文件里面代码的名称空间
然后就可以调用dll文件里面的类(test)和方法(add)了
例如:
using aa.test
namespace conslole1

class Program

static void Main(string[] args)

Test test1=new Test();
test1.add(1, 2);


参考技术B 定义接口
[DllImport("dll文件名", CallingConvention = CallingConvention.Cdecl)]
public static extern void getPointCloud(ref PointVec3f points, int pointNum);

直接调用:
PointVec3f points;
getPointCloud( ref points, num);追问

这是C#调用C++接口,这样行不通的,试了REF传值不行,值不能传送到DLL中的函数中!只能用指针!

本回答被提问者和网友采纳
参考技术C unsafe代码块 就可以使用取地址符号&了

C#和C C++调用dll变量转换问题,双指针?

C结构体定义:
typedef struct _IntImage

int height; //图像的高
int width; //宽
int **data; //data:图像二维指针,用法为char** data = new char*[height];
//for (int i=0; i < height; i++)
//data[i] = &(buf[i*width]);
int *buf; //buf:图像数据区,按行存储,buf[0] —buf[width*height]
int variance;
int label;
int bFlip;

IntImage;
我在C#里定义结构体为:
[DllImport("FaceLib.dll", EntryPoint = "saveIntImage", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int saveIntImage(string filename, ref IntImage intImg);
[StructLayout(LayoutKind.Sequential)]
public unsafe struct IntImage

[MarshalAs(UnmanagedType.I4)]
public int height;
[MarshalAs(UnmanagedType.I4)]
public int width;
[MarshalAs(UnmanagedType.ByValArray)]
public IntPtr[] data;
[MarshalAs(UnmanagedType.SysUInt)]
public IntPtr buf;
[MarshalAs(UnmanagedType.I4)]
public int variance;
[MarshalAs(UnmanagedType.I4)]
public int label;
[MarshalAs(UnmanagedType.I4)]
public int bFlip;

不知道定义的是否正确?关键是int** data和int* buf两项的定义我不太清除怎么处理。我用了IntPtr buf指向图像存储的缓冲区,IntPtr [] data指向每行数据的首地址。
C里面的调用函数:
int setIntImage(IntImage* img, int value);

我在c#里面由一个由Bitmap图像转换为上述格式定义的图像的函数:
public static void Convert_to_IntImage2(ref IntImage intImage, Bitmap bmp)

int i = 0, j = 0, m = 0, n = 0, k = 0;
intImage.height = bmp.Height;
intImage.width = bmp.Width;

Color c = new Color();
int size = (intImage.width) * (intImage.height);
byte[] buffer = new byte[size];
for (i = 0; i < bmp.Width; i++)
for (j = 0; j < bmp.Height; j++)

c = bmp.GetPixel(i, j);
buffer[m] = (byte)((39 * c.R + 11 * c.G + 50 * c.B) / 100);
m++;

intImage.buf = Marshal.AllocHGlobal(size);
Marshal.Copy(buffer,0,intImage.buf,size);

intImage.data=new IntPtr[bmp.Width];
for (i = 0; i < bmp.Width; i++)

intImage.data[i]= Marshal.UnsafeAddrOfPinnedArrayElement(buffer,i*bmp.Height); //获取指定数组指定索引处的地址




在该转换函数里面,不知道结构体中的buf和data如何分配空间和赋值?才能使得给c里面的函数传递参数?出现“尝试读取或写入受保护的内存,这通常指示其他的内存已破坏”。
请问如何平台调用来传递这些复杂的结构体?
此问题来源于:http://q.cnblogs.com/q/2813/。我也遇到类似问题,baidu和google了很多方法, 都未能解决

[DllImport("FaceLib.dll", EntryPoint = "saveIntImage", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int saveIntImage(string filename, IntImage* intImg);
[StructLayout(LayoutKind.Sequential)]
public unsafe struct IntImage

    public int height;
    public int width;
    public int** data;
    public int* buf;
    public int variance;
    public int label;
    public int bFlip;
    ~IntImage()
    
        if (data == (int**) 0)
            Marshal.FreeCoTaskMem(new IntPtr(data));
        if (buf == (int*) 0)
            Marshal.FreeCoTaskMem(new IntPtr(buf));
    

public static void Convert_to_IntImage2(ref IntImage intImage, Bitmap bmp)

    intImage.height = bmp.Height;
    intImage.width = bmp.Width;
    Color c = new Color();
    int size = (intImage.width) * (intImage.height);
    byte[] buffer = new byte[size];
    int m = 0;
    for (int i = 0; i < bmp.Width; i++)
        for (int j = 0; j < bmp.Height; j++)
        
            c = bmp.GetPixel(i, j);
            buffer[m] = (byte)((39 * c.R + 11 * c.G + 50 * c.B) / 100);
            m++;
        
    unsafe
    
        intImage.buf = (int*) Marshal.AllocCoTaskMem(size * sizeof(int)).ToPointer();
        int* pDst = intImage.buf;
        fixed (byte* pBuf = &buffer[0])
        
            for (int i = 0; i < size; ++i)
                pDst[i] = pBuf[i];
        
        intImage.data = (int**)Marshal.AllocCoTaskMem(bmp.Width * sizeof(int*)).ToPointer();
        int** pData = intImage.data;
        int bmpHeight = bmp.Height;
        for (int i = 0; i < bmp.Width; i++)
        
            pData[i] = &pDst[i * bmpHeight];
        
    

试试看这样


如果不行,尝试从kernel32.dll导入GetProcessHeap, HeapAlloc, HeapFree这三个函数来分配和释放内存。

我没有你那个dll,所以代码其实我没有测试,也许里面包含你需要自己调试的错误

释放内存我写在析构函数里面,但是对于结构体……析构函数这东西真的可以用吗其实我不太清楚。或许你应该显式释放它们。

指针的地方我给直接改成指针了,而不是IntPtr

原来分配的代码有问题,一个长度为x的int数组占用的内存并不是x而是x * sizeof(int),其实就是4x。所以你分配的内存其实不够那个数组使用。

看你c语言的函数声明,没有WINAPI或CALLBACK或APIENTRY之类的修饰,有可能不是stdcall,我给改成cdecl了。参数也直接使用指针了。


其实C#是可以用指针的,直接用指针就好了嘛…………

追问

C#的指针 intptr? 其实原来的问题是这样的:
c++ dll中 :
struct int cout; char **attr;a_t;
void check(a_t *a) (*a)=malloc(10); ...... 结构体中有**做为二维数组,结构体指针做为函数形参。
我在C#中**用intptr,或stringbuffer都不行,在网上也找了一些方法用intptr的话,这个函数是可以执行成功的。但使用这个结构体时,就引不出内容了。

追答

C#中unsafe代码直接用指针啊,语法和C++一样,星号打上去。二级指针就打两个星号,C++中int**在C#中也还是int**,取地址就是用&,具体参考我写的代码
引不出内容是什么情况?我函数声明是参考你的,然后也没那个dll来测试。如果不行,那么更直接一点不要用ref IntImage,直接写IntImage*,要调用的时候用fixed把IntImage对象锁在托管堆上拿指针然后送进去

参考技术A 可惜没时间,没细看你的东西,只略扫过;
参考“C#混合编程”、“调用约定”两个主题应该可以解决你的问题追问

使用unsafe不安全代码?

参考技术B 顶楼上!!!!

以上是关于C#如何调用C++的DLL的结构体数组指针的主要内容,如果未能解决你的问题,请参考以下文章

C#引用c++DLL结构体数组注意事项(数据发送与接收时)

c# 调用c dll void 指针类型转化问题

c#调用Delphi DLL参数为结构体数组

C#和C++传递结构体

C#和C C++调用dll变量转换问题,双指针?

C++结构体指针数组如何分配空间,用new