2

I have to call an unmanaged function from C# and must provide an array of coordinates (doubles) to it. How does the marshalling work for this case correctly?

On the unmanaged side:

typedef struct dPoint3dTag
{
  double x, y, z;
} dPoint3d;

void UnmanagedModifyGeometry(char *strFeaId, dPoint3d *pnts, int iNumPnts);

I defined a managed Structure for DPoint3d on the managed side:

[StructLayout(LayoutKind.Sequential)]
public struct DPoint3d
{
// Constructor
public DPoint3d(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}

public double x, y, z;
}

I'm trying to call the unmanaged function from C# in this way:

// Import of the unmanaged function
[DllImport("Unmanaged.dll")]
public static extern void UnmanagedModifyGeometry([MarshalAs(UnmanagedType.LPStr)] string strFeaId, DPoint3d[] pnts, int iNumPnts);

// Using the unmanaged function from C#
// Allocating points
DPoint3d[] pnts = new DPoint3d[iPntCnt];
String strFeaId = "4711";

// After filling in the points call the unmanaged function
UnmanagedModifyGeometry(strFeaId, pnts, iPntCnt);

Is this workflow correct?

Regards tomtorell

1 Answer 1

1

First of all on the unmanaged side, char* is a modifiable string. You should use const here to indicate that the data flows from caller to callee. And it makes sense to do the same for the other parameters:

void UnmanagedModifyGeometry(
    const char *strFeaId, 
    const dPoint3d *pnts, 
    const int iNumPnts
);

Now it is clear to all how the data flows.

On the managed side, there is one obvious problem with the declaration which is that you don't specify the calling convention. The default is stdcall, but your unmanaged code will be cdecl, assuming that the declaration in the question is accurate.

The struct declarations that you show match perfectly. There is nothing more to say on that subject.

You can also make use of the default marshalling to simplify the p/invoke. I'd write it like this:

[DllImport("Unmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void UnmanagedModifyGeometry(
    string strFeaId, 
    [In] DPoint3d[] pnts, 
    int iNumPnts
);

And call it like this:

DPoint3d[] pnts = new DPoint3d[...]; // supply appropriate value for array length
// populate pnts
UnmanagedModifyGeometry("4711", pnts, pnts.Length);
Sign up to request clarification or add additional context in comments.

8 Comments

+1 True problem here is only wrong calling convention (but I'd still add attributes to make explicit that iNumPnts is number of elements in pnts, frankly speaking I don't know if marshaler will ever use it but it's an extra-check - if used - or documentation - if unused).
@AdrianoRepetti UnmanagedType.LPArray is the default here. The SizeParamIndex can be used to allow the marshaller to marshal only part of the array. However, DPoint3d[] is blittable so it is pinned by the marshaller anyway. It wouldn't hurt to include SizeParamIndex but I also don't think it really hurts to omit it.
I agree it doesn't hurt to omit it, I just wonder if there are (or there will) benefits to include it. SizeParamIndex shouldn't be used to tell marshaler that one parameter carries the size of the array? Something that - in theory if used - will generate an error (managed side, not access violation on unmanaged code) if I do unmanagedFunction(myArray, myArray.Length + 1)?
@AdrianoRepetti All it does it control how the marshaller marshals the array. If it is not specified, then the length of the supplied array is used. If it is specified, then the value of the other param is used. In this case the array is blittable and it has no impact at all because the marshaller pins rather than marshals.
@AdrianoRepetti There may well be runtime checking also. Your example of unmanagedFunction(myArray, myArray.Length + 1) would be worth checking out.
|

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.