2

I've got an unmanaged DLL that I am trying to use that makes use of some nested structs with reserved members at the end of them. I'm having an issue converting them to C#.

I've tried to strip down the code to what is essential. The ParentStruct has members for four instances of three different child structs. All of those three different child structs have void* arrays to reserve memory for future use.

I've tried just doing the Reserved values as IntPtrs, I've tried turning on unsafe code and using the fixed keyword (and changing them to ints). I've tried actually laying out the appropriate number of consecutive IntPtrs at the end of the struct. Nothing seems to work.

In some of those cases, I'll get an error message (an uninformative one that says that there was an error at a certain address on a certain thread). Most of the time, though, the application just dies without an error message. I'm sure that's because I'm messing with unmanaged memory here.

Just FYI, the actual Pinvoke has a signature something like

[DllImport("MyDll.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
internal static extern void UseStructs([In,Out] ref ParentStruct parent);

So what's the right way to declare these structs in C# so that I can use them?

typedef struct
{
    ChildStruct1           childOne;
    ChildStruct2           childTwo;
    ChildStruct2           childTwoB;
    ChildStruct3           childThree;

#if defined K_64_BIT
    /// Reserved for future implementation
    void*          Reserved[15];
#elif defined K_32_BIT
    /// Reserved for future implementation
    void*          Reserved[14];
#endif

} ParentStruct;

typedef struct
{

    bool  Valid;
    float x;
    float y;

    /// Reserved for future implementation.
    void*               Reserved[16];
} ChildStruct3;

typedef struct
{

    bool          Found;
    XYPairFloat xyPair;


    /// Reserved for future implementation.
    void*         Reserved[16];
} ChildStruct2;


typedef struct
{
    unsigned char* imageData;
    RectInt      rectInt;

#if defined QUICK_LINK_64_BIT
    /// Reserved for future implementation
    void*          Reserved[14];
#elif defined QUICK_LINK_32_BIT
    /// Reserved for future implementation
    void*          Reserved[12];
#endif

} ChildStruct1;

typedef struct
{

    int x;
    int y;
    int width;
    int height;
} RectInt;

typedef struct
{
    float x;
    float y;
} XYPairFloat;

Edit: I think I've gotten closer, in that I'm now getting an error message that is at least human readable. But it still doesn't work. I used the fixed keyword on the Reserved members and set the SizeConst part of the attribute on the member appropriately. Everything else I did was just basic pinvoke work. However, I'm getting the error:

The type definition of this field has layout information but has an invalid managed/unmanaged type combination or is unmarshalable.

in reference to the ChildStruct1 childOne member, which is the first one so I'd venture a guess it applies to the others as well. Thoughts?

Edit 2: Per Mark Heath's request, here's the actual definition I'm using for ChildStruct1:

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct ChildStruct1
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string imageData;
    public RectInt rectInt;
    [MarshalAs(UnmanagedType.LPArray, SizeConst=12)]
    public fixed int Reserved[12];
}

Edit 3: I did a little more digging. That error that I'm getting disappears if I comment out the Reserved member. Obviously it doesn't work. But that particular error is caused by how I defined that member, I guess.

9
  • You also have to be aware of alignment issues. See msdn.microsoft.com/en-us/library/… Commented Nov 27, 2012 at 17:54
  • Jim - I'm using [StructLayout(LayoutKind.Sequential)] on all of my structs in C#. I assumed that was the correct thing to do, but perhaps not? Commented Nov 27, 2012 at 17:58
  • can you post the interop structure you made for ChildStruct1? It is likely to be the way you declared the arrays. Commented Nov 27, 2012 at 18:28
  • LayoutKind.Sequential is probably right, but you also have to think about packing. See the Pack field: msdn.microsoft.com/en-us/library/…. What you use will depend on how your C++ compiler is packing things. Commented Nov 27, 2012 at 18:30
  • Mark - I've added the struct definition for ChildStruct1. Commented Nov 27, 2012 at 18:36

1 Answer 1

2

You can try changing the last value to an IntPtr array according to Essential P/Invoke

So change:

[MarshalAs(UnmanagedType.LPArray, SizeConst=12)]
public fixed int Reserved[12];

to:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public IntPtr[] Reserved;
Sign up to request clarification or add additional context in comments.

3 Comments

Doing it that way actually just causes my executable to die without even showing me an error message.
You could run the program through WinDbg to catch the exception and see where its failing.
This ended up being the right thing to use. The problem I was seeing was actually only happening under the debugger (I hadn't even gotten to running it without that yet). Turned out to be a problem with using the Visual Studio hosting process. I was tipped off by this question here on SO: stackoverflow.com/questions/4532457/…

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.