1

I have a legacy C-dll to access a Hardware Device. The dll uses structures containing structure Arrays as function arguments. And I am having a hard time to get this working together with C# (in unsafe mode which is ok since access Speed is an issue here).

The original declaration from DeviceDll.h of the legacy C-dll Looks like:

    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[]);

Declaring the C-dll functions in C# is done in the following way:

[DllImport("ExternalDevice.dll")]   
public unsafe static extern int GetResult(StringBuilder pDeviceCode, struc_RESULT_SCRIPT_NO_LIST* pList, struc_RESULT_SCRIPT **ppResult);

and the structure which I want to access I have declared in a way which unfortunatly gives an error:

[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;
}

Error: Buffer of a fixed size must be of "bool", "Byte", . . . or "double"

Is there a way to declare a fixed structure Array within a structure so that I can use a structure-type variable afterwards as an Argument for calling the legacy DLL ?

What I have tried so far:

Avoiding a structure Array within a structure (rather clumsy but working)

    [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;

This is working - but accessing oFormula01 … oFormula32 for 32 structure-variables is rather clumsy. I would strongly prefer to get the result as an Array so that I can Access it like oFormula = arrayFormula[xx]; within a for - loop.

Is there a way to declare an unsafe, fixed structure Array within a structure in C# - or a feasable work-around ?

Thank you very much in advance!

2
  • 1
    Not posting the struct declaration was a rather bad idea. There is only one scenario where you must use a fixed buffer, this isn't it. So don't, use ByValArray. Commented Apr 14, 2020 at 22:06
  • @HansPassant: I followed your advice using ByValArray together with LayoutKind.Sequential - like for example: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public struct_RESULT_FORMULA[] sFormula; and this seems to be working well. Could you please explain the one scenarion where I have to use a fixed buffer ? Commented Apr 16, 2020 at 15:18

1 Answer 1

0

According to the documentation for fixed sized buffers there is no way use structs in them.

The best option seem to do as you have done and declare 1..n fields. The anwer to this related question suggest the same thing. If the problem is simply not being able to loop over the fields, then consider adding a iterator block, like:

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

An alternative would be a large switch statement/expression if you need random indexing.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.