【发布时间】:2020-04-14 12:21:45
【问题描述】:
我有一个旧版 C-dll 来访问硬件设备。 dll 使用包含结构数组的结构作为函数参数。而且我很难让它与 C# 一起工作(在不安全模式下这没关系,因为这里的访问速度是一个问题)。
旧版 C-dll 的 DeviceDll.h 的原始声明如下所示:
typedef struct tag_RESULT_JUDGEMENT
{
short nJudgementResult;
} struc_RESULT_JUDGEMENT;
typedef struct tag_RESULT_FORMULA
{
float fFormulaResult[3];
float fAnalogResult;
} struc_RESULT_FORMULA;
typedef struct tag_RESULT_SCRIPT
{
short nScriptNo;
float fTime;
short nFormulaCount;
struc_RESULT_FORMULA sFormula[32];
short nJudgementCount;
struc_RESULT_JUDGEMENT sJudgement[8];
} struc_RESULT_SCRIPT;
WORD PASCAL GetResult(LPCTSTR pDeviceCode, struc_RESULT_SCRIPT_NO_LIST* pList, struc_RESULT_SCRIPT* pResult[]);
在 C# 中声明 C-dll 函数的方式如下:
[DllImport("ExternalDevice.dll")]
public unsafe static extern int GetResult(StringBuilder pDeviceCode, struc_RESULT_SCRIPT_NO_LIST* pList, struc_RESULT_SCRIPT **ppResult);
以及我要访问的结构,我以一种不幸的方式声明了一个错误:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct struc_RESULT_SCRIPT {
[FieldOffset(0)]
public Int16 nScriptNo;
[FieldOffset(2)]
public float fTime;
[FieldOffset(6)]
public Int16 iFormulaCount;
[FieldOffset(8)
public fixed struc_RESULT_FORMULA[32] oFormula;
}
错误:固定大小的缓冲区必须是“bool”、“Byte”、. . .或“双”
有没有办法在结构中声明一个固定的结构数组,以便之后我可以使用结构类型变量作为调用旧版 DLL 的参数?
到目前为止我所尝试的:
避免结构中的结构数组(相当笨拙但有效)
[StructLayout(LayoutKind.Explicit)]
public unsafe struct struc_RESULT_SCRIPT {
[FieldOffset(0)]
public Int16 nScriptNo;
[FieldOffset(2)]
public float fTime;
[FieldOffset(6)]
public Int16 iFormulaCount;
[FieldOffset(8)
public struc_RESULT_FORMULA oFormula01;
[FieldOffset(8 + 16)
public struc_RESULT_FORMULA oFormula02;
. . .
[FieldOffset(8 + 31*16)
public struc_RESULT_FORMULA oFormula32;
}
. . .
struc_RESULT_SCRIPT** ppResult; //local variable => allocated on the stack => so it's already fixed
. . .
int iRv = GetResult(sbMpmIp, &oScriptList, ppResult);
struc_RESULT_FORMULA oFormulaResult = ppResult[0]->oFormula01;
这是可行的 - 但访问 oFormula01 ... oFormula32 以获取 32 个结构变量是相当笨拙的。我强烈希望将结果作为数组获取,以便我可以像 oFormula = arrayFormula[xx]; 一样访问它在 for - 循环中。
有没有办法在 C# 结构中声明一个不安全的固定结构数组 - 或可行的解决方法?
非常感谢您!
【问题讨论】:
-
不发布结构声明是一个相当糟糕的主意。只有一种情况您必须使用固定缓冲区,不是这样。所以不要,使用 ByValArray。
-
@HansPassant:我按照您的建议使用 ByValArray 和 LayoutKind.Sequential - 例如: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public struct_RESULT_FORMULA[] sFormula;这似乎运作良好。您能否解释一下我必须使用固定缓冲区的一种情况?