首页 > 解决方案 > 使用结构中不安全的固定大小的结构数组使用 C# 访问旧版 C-dll

问题描述

我有一个旧版 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# 的结构中声明一个不安全的固定结构数组 - 或可行的解决方法?

非常感谢您!

标签: c#arraysstructurefixed

解决方案


根据固定大小缓冲区的文档,无法在其中使用结构。

最好的选择似乎与您所做的一样并声明 1..n 字段。对这个相关问题的回答暗示了同样的事情。如果问题只是无法遍历字段,请考虑添加一个迭代器块,例如:

public IEnumerable<struc_RESULT_FORMULA> GetResultFormulas(){
    yield return oFormula01;
    ...
    yield return oFormula32;
}

如果您需要随机索引,另一种选择是大型 switch 语句/表达式。


推荐阅读