C# 编组结构数组以从C调用非托管函数#

C# 编组结构数组以从C调用非托管函数#,c#,pinvoke,marshalling,C#,Pinvoke,Marshalling,我必须从C#调用一个非托管函数,并且必须为它提供一个坐标数组(双精度)。在这种情况下,编组是如何正确工作的 在非托管端: typedef struct dPoint3dTag { double x, y, z; } dPoint3d; void UnmanagedModifyGeometry(char *strFeaId, dPoint3d *pnts, int iNumPnts); [StructLayout(LayoutKind.Sequential)] public struct

我必须从C#调用一个非托管函数,并且必须为它提供一个坐标数组(双精度)。在这种情况下,编组是如何正确工作的

在非托管端:

typedef struct dPoint3dTag
{
  double x, y, z;
} dPoint3d;

void UnmanagedModifyGeometry(char *strFeaId, dPoint3d *pnts, int iNumPnts);
[StructLayout(LayoutKind.Sequential)]
public struct DPoint3d
{
// Constructor
public DPoint3d(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}

public double x, y, z;
}
我在托管端为DPoint3d定义了托管结构:

typedef struct dPoint3dTag
{
  double x, y, z;
} dPoint3d;

void UnmanagedModifyGeometry(char *strFeaId, dPoint3d *pnts, int iNumPnts);
[StructLayout(LayoutKind.Sequential)]
public struct DPoint3d
{
// Constructor
public DPoint3d(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}

public double x, y, z;
}
我试图通过以下方式从C#调用非托管函数:

// Import of the unmanaged function
[DllImport("Unmanaged.dll")]
public static extern void UnmanagedModifyGeometry([MarshalAs(UnmanagedType.LPStr)] string strFeaId, DPoint3d[] pnts, int iNumPnts);

// Using the unmanaged function from C#
// Allocating points
DPoint3d[] pnts = new DPoint3d[iPntCnt];
String strFeaId = "4711";

// After filling in the points call the unmanaged function
UnmanagedModifyGeometry(strFeaId, pnts, iPntCnt);
这个工作流程正确吗

问候
tomtorell

首先,在非托管端,
char*
是一个可修改的字符串。您应该在这里使用
const
来指示数据从调用者流向被调用者。对其他参数也可以这样做:

void UnmanagedModifyGeometry(
    const char *strFeaId, 
    const dPoint3d *pnts, 
    const int iNumPnts
);
现在大家都清楚了数据是如何流动的

在托管端,声明有一个明显的问题,即您没有指定调用约定。默认值是stdcall,但假设问题中的声明是准确的,则非托管代码将是cdecl

显示的结构声明完全匹配。关于那个问题,没有什么可说的了

您还可以使用默认编组来简化p/invoke。我会这样写:

[DllImport("Unmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void UnmanagedModifyGeometry(
    string strFeaId, 
    [In] DPoint3d[] pnts, 
    int iNumPnts
);
DPoint3d[] pnts = new DPoint3d[...]; // supply appropriate value for array length
// populate pnts
UnmanagedModifyGeometry("4711", pnts, pnts.Length);
这样称呼它:

[DllImport("Unmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void UnmanagedModifyGeometry(
    string strFeaId, 
    [In] DPoint3d[] pnts, 
    int iNumPnts
);
DPoint3d[] pnts = new DPoint3d[...]; // supply appropriate value for array length
// populate pnts
UnmanagedModifyGeometry("4711", pnts, pnts.Length);

+这里真正的问题只是错误的调用约定(但我仍然会添加属性,以明确说明
iNumPnts
pnts
中的元素数,坦率地说,我不知道封送员是否会使用它,但如果使用它,则是额外的检查;如果未使用,则是文档).@AdrianoRepetti
UnmanagedType.LPArray
是此处的默认值。
SizeParamIndex
可用于允许封送器仅封送数组的一部分。但是,
DPoint3d[]
是可空袭的,因此它无论如何都会被封送员固定。包含
SizeParamIndex
不会有什么坏处,但我也不认为省略它真的有什么坏处。我同意省略它不会有什么坏处,我只是想知道包含它是否有(或将有)好处
SizeParamIndex
不应该用来告诉封送拆收器一个参数携带数组的大小?如果我执行
unmanagedFunction(myArray,myArray.Length+1)
?@AdrianoRepetti All it does它控制封送器封送数组的方式,则理论上如果使用,将生成错误(托管端,而不是非托管代码上的访问冲突)。如果未指定,则使用提供的数组的长度。如果已指定,则使用另一个参数的值。在这种情况下,数组是可空袭的,它没有任何影响,因为封送器是固定的,而不是封送器。谢谢!我以为这是一个运行时检查!