简体   繁体   中英

Marshal a variable-size array of structures nested within a structure

I need to pass a structure containing an array of structures that is of an unknown length at compile-time.

I've found examples of how to Marshal variable-size arrays of primitives with Marshal.Copy and fixed-size arrays of structures using an IntPtr[] array and Marshal.StructureToPtr, but that uses MarshalAs(UnamangedType.ByValArray) in the structure definition which requires the SizeConst parameter.

Here's a sample of what I'm trying to do. In the C dll I have a structure with a sine wave defintion

typedef struct sinWave
{
    double amp;         /*  sine wave amplitude     */
    double t;           /*  time                    */
    double period;      /*  oscilation period       */
    double omega;       /*  phase angle             */
} sinWave;

and a structure that can hold multiple waves

typedef struct sinWaveAdd
{
    sinWave *waves;     /*  array of sine waves     */
    int len;            /*  length of the array     */
} sinWaveAdd;

This gets used in wave superposition function with the following prototype

__declspec( dllexport ) double calculateMult( sinWaveAdd *in )

In c# I have a sinWave struct that works well on its own

[StructLayout(LayoutKind.Sequential)]
public class sinWaveStruct
{
    public double amp;      /*  sine wave amplitude */
    public double t;        /*  time                */
    public double period;   /*  oscillation period  */
    public double omega;    /*  phase angle         */
}

public sinWaveStruct(double ampP, double tP, double periodP, double omegaP)
{
    amp = ampP;
    t = tP;
    period = periodP;
    omega = omegaP;
}
}

but I don't really know how to construct the larger structure

[StructLayout(LayoutKind.Sequential)]
public class sinWaveAddClass
{
    public IntPtr waves;        /*  array of sinWaveStruct waves    */
    public int len;             /*  length of array */
}

since I need the number of waves to not be constant.

Is there a way to Marshal the waves array to sinWaveStruct[], IntPtr, or IntPtr[] without having a constant size array?

I'd declare the structures as struct . That makes them value types rather than reference types. Important when you want to make arrays of them. Especially as sinWave is blittable.

public struct sinWaveStruct
{
    public double amp;      /*  sine wave amplitude */
    public double t;        /*  time                */
    public double period;   /*  oscillation period  */
    public double omega;    /*  phase angle         */
}

public struct sinWaveAdd
{
    public IntPtr waves;        /*  array of sinWaveStruct waves    */
    public int len;             /*  length of array */
}

The function you import is:

[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
public static extern double calculateMult(ref sinWaveAdd in);

So then create and populate an array of sinWaveAdd :

sinWaveStruct[] arr = new sinWaveStruct[len];
// populate arr

Then pin the array and obtain its address:

GCHandle arrHandle = GCHandle.Alloc(arr, GCHandleType.Pinned);
try
{
    sinWaveAdd in;
    in.waves = arrHandle.AddrOfPinnedObject();
    in.len = len;
    double retval = calculateMult(ref in);
}
finally
{
    arrHandle.Free();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM