从C#调用C ++函数 - 结构,指针,函数指针

时间:2013-05-13 12:04:14

标签: c# c++ .net dll interop

我目前正在尝试将C ++ DLL集成到我们的C#应用​​程序中,但我无法确定调用其中一种方法的正确方法。

C ++方法定义:

typedef struct ImageDataAndInfo
{ 
    unsigned char* PicBuffer;     //image buffer 
    long lPicSize;    //image data length 
    int iPicType;     // iPicType, 0: bmp, 1: tiff, 2: jpeg 
} ImageDataAndInfo,*PImageDataAndInfo; 

typedef  ImageAndScanError    (__stdcall * ReadPictureData)(PImageDataAndInfo PicF1,
    PImageDataAndInfo PicR1, 
    PImageDataAndInfo PicF2,
    PImageDataAndInfo PicR2,  
    PImageDataAndInfo PicF3,
    PImageDataAndInfo PicR3,  
    BOOL bSourceBMPSave);

typedef  void    (__stdcall * FreeImageDataBuffer)(PImageDataAndInfo pImageDataAndInfo);

C ++示例代码:

ImageDataAndInfo F1,F2,F3,R1,R2,R3;
F1.lPicSize=0;
F2.lPicSize=0;
F3.lPicSize=0;
R1.lPicSize=0;
R2.lPicSize=0;
R3.lPicSize=0;

int bResult;
bResult=ReadPictureData(&F1,&R1,&F2,&R2,&F3,&R3,TRUE);

f_FreeImageDataBuffer(&F1);
...
f_FreeImageDataBuffer(&R3);

我的C#转换:

[StructLayout(LayoutKind.Sequential)]
public struct PImageDataAndInfo
{
    [MarshalAs(UnmanagedType.ByValArray)]
    public byte[] PicBuffer;        //image buffer 

    public int lPicSize;            //image data length 
    public int iPicType;            // iPicType, 0: bmp, 1: tiff, 2: jpeg 
}

[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi)]
public static extern ImageAndScanError ReadPictureData(
    out PImageDataAndInfo PicF1,
    out PImageDataAndInfo PicR1,
    out PImageDataAndInfo PicF2,
    out PImageDataAndInfo PicR2,
    out PImageDataAndInfo PicF3,
    out PImageDataAndInfo PicR3,
    bool bSourceBMPSave);

PImageDataAndInfo PicF1 = new PImageDataAndInfo();
...
PImageDataAndInfo PicR3 = new PImageDataAndInfo();

ReadPictureData(
    out PicF1,
    out PicR1,
    out PicF2,
    out PicR2,
    out PicF3,
    out PicR3,
    false);

如果我使用PicBuffer指定[MarshalAs(UnmanagedType.ByValArray, SizeConst = 99999)]的默认值,我在lPicSize中没有收到值,如果我没有指定默认值,我会得到一个lPicSize中的值,但它不是PicBuffer的正确值。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:3)

本机DLL为缓冲区分配内存,并在结构的PicBuffer字段中返回非托管指针。所以你的结构声明是错误的。您需要将字节数组声明为指针。

[StructLayout(LayoutKind.Sequential)]
public struct ImageDataAndInfo
{
    public IntPtr PicBuffer;       
    public int lPicSize;           
    public int iPicType;           
}

您必须调用Marshal.Copy将缓冲区的内容复制到字节数组。例如:

// call ReadPictureData
byte[] buffer = new byte[PicF1.lPicSize];
Marshal.Copy(PicF1.PicBuffer, buffer, 0, PicF1.lPicSize);

确保在复制完所有缓冲区后调用FreeImageDataBuffer。否则,您将泄漏本机DLL分配的内存。


请注意,在C ++代码中,ImageDataAndInfo是结构,PImageDataAndInfo是指向结构的指针。所以你的C#结构应该命名为ImageDataAndInfo

此外,您不需要使用new来创建结构的新实例。只需声明它们:

ImageDataAndInfo PicF1;
ImageDataAndInfo PicF2;
// etc.