以前的帖子说到c++函数的参数是char**,这种函数在C#中用什么方式接收(用ref IntPtr[]),但其实根据这个帖子中所说,哪方分配内存,对于另一方函数参数的类型形式是不同的,所以本次说如果返回值是char**/int**等怎么处理呢?
char **arr;
int arrlen,arrcol;
template<class T>
void make2DArray(T** &ptr, int rows, int cols)
{
//创建二维数组,先创建行指针
ptr = new T*[rows];
//再为每一行分配空间
for (int i = 0; i < rows; i++)
{
ptr[i] = new T[cols];
}
}
void alloc2D()
{
arrlen = 3;
arrcol = 2;
arr = new char*[arrlen];//分配3个元素的数组空间,每个元素是char*指针元素
for (int i = 0; i <= arrlen; i++)
{
arr[i] = new char[arrcol*(i+1)+1]; //其实不同行可以长度不同
}
}
void* returnpptr(int* len) //C++分配内存,返回**给C#
{
alloc2D();
*len = 3;
for (int i = 0; i < arrlen; i++)
{
for (int j = 0; j <= arrcol*(i + 1)+1; j++)
{
if (j == arrcol*(i + 1)+1)
arr[i][j] = 0;
else
arr[i][j] = (char)(0x31 + i + j % 5);
}
}
return arr;
}
[DllImport("dllfordebugdemo.dll", EntryPoint = "returnpptr", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr returnpptr(ref int len);
private void button7_Click(object sender, EventArgs e)
{
int len =0;
IntPtr p = returnpptr(ref len);
IntPtr[] ps = new IntPtr[len];
for(int i =0;i<len;i++)
{
ps[i] = Marshal.ReadIntPtr(p + Marshal.SizeOf(typeof(IntPtr)) * i);
Console.WriteLine(Marshal.PtrToStringAnsi(ps[i]));
}
}
显示如下:
123
23456
3456734
如果C++返回的是int**,实验如下:
int** ppcol;
int* p1;
int reflen;
void* returnpptrint(int* len)
{
reflen = 1;
*len = reflen;
arrcol = 2;
p1 = &arrcol;
if (ppcol == NULL)
{
ppcol = &p1;
}
return ppcol;
}
[DllImport("dllfordebugdemo.dll", EntryPoint = "returnpptrint", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr returnpptrint(ref int len);
private void button7_Click(object sender, EventArgs e)
{
int len =0;
IntPtr p = returnpptrint(ref len);
IntPtr[] ps = new IntPtr[len];
int[] lens = new int[len];
for (int i = 0; i < len; i++)
{
ps[i] = Marshal.ReadIntPtr(p + Marshal.SizeOf(typeof(IntPtr)) * i);
Marshal.Copy(ps[i],lens,0,1);
Console.WriteLine("lens[i]=" + lens[i]);
}
}
显示:
lens[i]=2
总结:
C#无法接收C++返回值的char**/int**,只能先强转为void*,然后在C#中public static extern IntPtr fun(...),实际使用时二级指针的行数,并且通过IntPtr[]数组和Marshal.ReadIntPtr(基址+偏址),再用Marshal.Copy或PtrToString...方式获取最终值。
到目前为止:三级指针不管是参数还是返回值形式,都不成功(估计还是以后有时间再做实验)。
上面统一以c# IntPtr接收C++的void*(实际是char**/int**强转而来),虽然实验成功,但换种思维方式,c++中还是char**/int** fun(...),而c#中以IntPtr fun(...)可不可以呢?
[DllImport("dllfordebugdemo.dll", EntryPoint = "returnpptr", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr returnpptr(ref int len);
private void button7_Click(object sender, EventArgs e)
{
int len =0;
IntPtr p = returnpptr(ref len);
IntPtr[] ps = new IntPtr[len];
for (int i = 0; i < len; i++)
{
ps[i] = Marshal.ReadIntPtr(p + Marshal.SizeOf(typeof(IntPtr)) * i);
Console.WriteLine(Marshal.PtrToStringAnsi(ps[i]));
}
}
void** returnpptr(int* len) //C++分配内存,返回**给C#
{
alloc2D();
*len = 3;
for (int i = 0; i < arrlen; i++)
{
for (int j = 0; j <= arrcol*(i + 1)+1; j++)
{
if (j == arrcol*(i + 1)+1)
arr[i][j] = 0;
else
arr[i][j] = (char)(0x31 + i + j % 5);
}
}
return (void**)arr;
}
或者将返回值改为实际的char**:
char** returnpptr(int* len) //C++分配内存,返回**给C#
{
alloc2D();
*len = 3;
for (int i = 0; i < arrlen; i++)
{
for (int j = 0; j <= arrcol*(i + 1)+1; j++)
{
if (j == arrcol*(i + 1)+1)
arr[i][j] = 0;
else
arr[i][j] = (char)(0x31 + i + j % 5);
}
}
return (arr;
}
C#中还是IntPtr returnpptr(ref int len),最终实验也是成功的。