问题描述
我有一个从 C# 应用程序调用的 C DLL。我能够成功地从 DLL 接收结构,但我在将数据发送到 DLL 中时遇到了发送相同的结构的问题。这是我所拥有的:
C# 应用程序结构:
public class MatrixClass
{
private double[,] cells;
[StructLayout(LayoutKind.Sequential)]
public struct Matrix
{
public IntPtr cells;
public int cellRows;
public int cellColumns;
}
}
C DLL 结构:
typedef struct
{
double **cells;
int cellRows;
int cellColumns;
} Matrix;
这是我的 C DLL 中的示例函数,我需要从中接收结构:
void GetMatrixCell(Matrix *MatrixIn,int nRow,int nColumn,double *value)
{
*value = 0.0;
int nColIndex = nColumn - 1;
int nRowIndex = nRow - 1;
*value = MatrixIn->cells[nRowIndex][nColIndex];
}
我怎么称呼它:
[DllImport(matrixDLL,CallingConvention = CallingConvention.Cdecl)]
static extern int GetMatrixCell(Matrix mIn,int
nColumn,ref double value);
public double GetCell(int Row,int Column)
{
double result = 0.0;
int stride = Rows * sizeof(double);
IntPtr p = Marshal.AllocHGlobal(Rows * stride);
Matrix mIn = MatrixtoDLL(this,Rows,Columns,p,stride); //this = MatrixClass
GetMatrixCell(mIn,Row,Column,ref result);
Marshal.FreeHGlobal(p);
return result;
}
MatrixtoDll 函数来自上面:
public static Matrix MatrixtoDLL(MatrixClass input,int rows,int columns,IntPtr p,int stride)
{
Matrix toReturn = new Matrix ();
toReturn.cellColumns = columns;
toReturn.cellRows = rows;
for (int i = 0; i < columns; i++) //rows
{
double[] temp = new double[rows];
for (int x = 0; x < rows; x++)
temp[x] = input.cells[i,x]; //[columns,rows]
Marshal.copy(temp,p + stride * i,rows);
}
toReturn.cells = p;
return toReturn;
}
我在想我的 MatrixtoDLL 是我需要重新思考的地方吗?或者我需要以另一种方式发送数据。就像我上面提到的,我可以成功地将数据(单元格)作为 IntPtr 接收并将其转换为二维数组,但程序不喜欢他们尝试发送结构的方式。提前致谢!
编辑:这是我得到的未处理异常: mscorlib.dll 中发生类型为“System.Reflection.TargetInvocationException”的未处理异常 附加信息:调用的目标已抛出异常。
解决方法
您的 P/Invoke 函数定义不正确。应该是
[DllImport(matrixDLL,CallingConvention = CallingConvention.Cdecl)]
static extern void GetMatrixCell(in Matrix mIn,int nRow,int nColumn,ref double value);
此外,Matrix.cells
应该是一个指向一维数组的指针数组的指针,换句话说,一个锯齿状数组。
我们可以为此使用GCHandle
,这也避免了不必要的复制
private double[][] cells;
[StructLayout(LayoutKind.Sequential)]
public struct Matrix
{
public IntPtr[] cells;
public int cellRows;
public int cellColumns;
}
public double GetCell(int Row,int Column)
{
double result = 0.0;
Matrix mIn = new Matrix
{
cellColumns = Columns,cellRows = Rows,};
var handles = new GCHandle[this.cells.Length];
try
{
for (var i = 0; i < this.cells.Length; i++)
handles[i] = GCHandle.Alloc(this.cells[i],GCHandleType.Pinned);
mIn.cells = handles.Select(h => h.AddrOfPinnedObject()).ToArray();
GetMatrixCell(mIn,Row,Column,ref result);
}
finally
{
foreach (var h in handles)
if(h.IsAlllocated)
h.Free();
}
return result;
}
我必须说,我不清楚 Matrix.cellColumns
和 cellRows
的重点。 C 函数似乎没有使用它。