0

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?

3
  • @HansPassant Surely easier just to pin the array? Commented Mar 28, 2014 at 21:37
  • It is. Perhaps a warning to the OP that his C code should not store pointer is appropriate. Sine waves take time to be played back ;) Commented Mar 28, 2014 at 21:41
  • @Hans These look like they are processed into a single value which is returned Commented Mar 28, 2014 at 21:56

1 Answer 1

1

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();
}
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.