日期:2014-05-18  浏览次数:20993 次

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里面的函数传递参数?出现“尝试读取或写入受保护的内存,这通常指示其他的内存已破坏”。
请问如何平台调用来传递这些复杂的结构体?

------解决方案--------------------
你的代码有两个问题:
1、intImage.data=new IntPtr[bmp.Width]; 这个要改成 intImage.data=Marshal.AllocHGlobal(bmp.Width); 

2、intImintImage.bufage.data[i]= Marshal.UnsafeAddrOfPinnedArrayElement(buffer,i*bmp.Height); 
Marshal.UnsafeAddrOfPinnedArrayElement 这个方法要求:该数组在被传递给此方法之前必须使用 GCHandle 固定。
buffer 这个数组! 要用 GCHandle.Alloc 这个方法