2

I'm using an external C library that comes with a C# wrapper file containing a struct like (among many other things):

[StructLayout(LayoutKind.Sequential, Pack = 8)]
unsafe public struct Data
{
    public fixed double Values[3];
};

I can get the values by adding an additional method to that struct:

public double[] CopyFixedDoubleArray()
{
    double[] result = new double[3];
    fixed (double* pDst = result)
    {
        fixed (double* pSrc = Values)
        {
            double* pd = pDst;
            double* ps = pSrc;
            for (int i = 0; i < result.Length; i++)
            {
                *pd = *ps;
                pd++; ps++;
            }
        }
    }
    return result;
}

But this is not what I want because I don't want to touch the wrapper file (to avoid having to keep the external file in our SCM repository). Whatever I try to do to get the values from outside that struct results in the following error:

Fixed size buffers can only be accessed through locals or fields

What I've tried:

  • double a = data.Values[2];
  • double a; unsafe { a = data.Values[2]; }
  • double a; fixed (double* p = data.Values) { a = p[2]; }
  • fixed (double a = data.Values[2]) { /* use a */ }

Is there any way to get around this?

5
  • Show us the code that would call CopyFixedDoubleArray() if struct Data contained the CopyFixedDoubleArray() method. Commented Feb 16, 2015 at 16:53
  • double a = data.CopyFixedDoubleArray()[2]; for example Commented Feb 16, 2015 at 17:01
  • So, Data data2 = data; double a; unsafe { a = data2.Values[2]; } does not work? Commented Feb 16, 2015 at 17:06
  • Nope, results in that error Commented Feb 16, 2015 at 17:13
  • 2
    Hmmm, let's wait for the C# gurus. Commented Feb 16, 2015 at 17:18

2 Answers 2

2

Suddenly the word 'extension method' crossed my mind. And yes, I have it working:

public static double[] CopyFixedDoubleArray(this Data data)
{
    unsafe
    {
        return new[] { data.Values[0], data.Values[1], data.Values[2] };
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

That's just bizarre. The extension method works, although the same method on the struct does not. I wonder why. Btw, saved my day, thank you for sharing!
0

Rather than patch your code up, have you considered shoving this over to the marshaller? That's its entire purpose: to assist with native interop while letting you write pure managed code.

You'd have to declare your struct like this:

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Data
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public double[] Values;
};

When this structure is filled by the marshaller (through either a direct function call through a pointer, or from mapping the struct on top of a byte buffer) it will allocate the proper array and copy its contents over. This makes your entire function obsolete, but if you really wanted to you could simply use Array.Copy (or the Linq equivalent).

Notice there's no more unsafe modifier. You can run this in a partially trusted environment with no issues!

2 Comments

Yes that's also how I would have written the wrapper. But this is not the case here as it comes from 3rd-party
Fair enough, just as long as you're aware the option exists!

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.