我刚刚加入了这个网站,这是我在这里发布的第一篇文章。 我真的可以帮助从我的C#应用程序调用非托管DLL函数。我一直在寻找,并找到了各种类似的问题,但没有任何东西非常符合我的需要。
我需要调用的函数是:
int DevConfig(struct A *a, int b, unsigned int c, BOOL *d);
其中A定义为:
struct A
{
double f[4];
unsigned int df[4];
unsigned int dfn[4];
double *dc[4];
float dg[4];
float g;
UCHAR gs;
};
我对如何在C#中处理这个问题感到困惑和困惑。我想我需要做这样的事情,但我知道这不太正确:
[StructLayout(LayoutKind.Sequential)]
public struct A
{
public double[] f = new double[4];
public uint[] df = new uint[4];
public uint[] dfn = new uint[4];
public double[,] dc = new uint[4,256];
public float[] dg = new float[4];
public float g;
public byte gs;
}
[DllImport("DevControl.dll")]
static extern int DevConfig (ref A a, int b, uint c, bool[] d);
我认为这是正确的方法,但我对双精度指针数组(double * dc [4])以及指向布尔数组(BOOL * d)的指针感到困惑。 请有人帮我解决这个问题吗?
使用更多信息进行修改: 在此函数的情况下,数据从C#流向DLL。也就是说,C#分配内存。 我正在考虑如下指定dc,除非以另一种方式更容易:
double[,] dc = new double[4, 256];
这个数组的大小总是4 x 256.不知怎的,我需要将它编组到结构的IntPtr []字段中?
对于bool数组:
bool[] d = new bool[8];
此数组的长度可能会有所不同,但不一定总是为8(但DLL通过其中一个传入的参数知道它的长度)。
答案 0 :(得分:3)
结构需要如下所示:
public struct A
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public double[];
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public uint[] df;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public uint[] dfn;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public IntPtr[] dc;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public float[] dg;
public float g;
public byte gs;
}
关键是这些数组内联存储在结构中,因此必须使用UnmanagedType.ByValArray
进行编组。
函数声明应为:
[DllImport("DevControl.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int DevConfig (ref A a, int b, uint c, bool[] d);
这假设最终参数是一个数组而不是指向单个布尔值的指针。只有你知道。还要注意调用约定。如上所述,您的非托管函数为cdecl
。你需要在p / invoke中指定它。
现在,您将面临的问题是结构中的2D数组dc
。处理它的唯一方法是手动分配和编组非托管内存。您无法使用double[,]
,因为它不会映射到double*[]
。因此,您需要IntPtr[]
然后使用Marshal
类来完成工作。究竟如何做到这一切都无法从这个问题中看出来。它没有指定谁分配内存。
您在更新中声明要在C#中分配双数组以传递给非托管代码。一些示例代码:
IntPtr[] CreateUnmanagedArrays(double[][] arr)
{
IntPtr[] result = new IntPtr[arr.Length];
for (int i=0; i<arr.Length; i++)
{
result[i] = Marshal.AllocCoTaskMem(arr[i].Length*sizeof(double));
Marshal.Copy(arr[i], 0, result[i], arr[i].Length);
}
return result;
}
void DestroyUnmanagedArrays(IntPtr[] arr)
{
for (int i=0; i<arr.Length; i++)
{
Marshal.FreeCoTaskMem(arr[i]);
arr[i] = IntPtr.Zero;
}
}
答案 1 :(得分:2)
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct A
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.R8)]
public double[] f;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U4)]
public uint[] df;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U4)]
public uint[] dfn;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.SysUInt)]
public System.IntPtr[] dc;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.R4)]
public float[] dg;
public float g;
public byte gs;
}
[DllImportAttribute("DevControl.dll", EntryPoint = "DevConfig")]
public static extern int DevConfig(ref A a, int b, uint c, ref int d);