none
Pointer to structure with array of structures RRS feed

  • Question

  •  

    Hi,

     

    I'm having issues with the following interop code:

     

    I'm wrapping the following function:

     

    typedef int     (__stdcall *GetBlah)(Blah*  blah,BlahString* symbol/*=0*/);

     

    "Blah" is defined as the same structure like in the corresponding header file

     

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 248)]

    internal struct Blah

    {

    [FieldOffset(0)]

    internal ushort A;

    [FieldOffset(2)]

    internal byte B;

    [FieldOffset(3)]

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]

    internal ManagedStructure[] Items;

    };

     

    The problem I'm having is that "GetBlah" expects a pointer to a "Blah" instance but when I try to instantiate a new "Blah" instance and create a pointer I get:

     

    "Cannot take the address of, get the size of, or declare a pointer to a managed type"

     

    So, how can I pass a pointer to that function when I'm not able to create a pointer of that structure?

     

    Thanks,

     

    Tom

     

     

    Thursday, April 10, 2008 4:17 PM

Answers

  • You'd let the P/Invoke marshaler automatically pass a pointer by declaring the function pointer like this:

        private delegate void GetBlah(ref Blah blah, string symbol);

    There is a show-stopper problem with your declaration of the Blah structure though.  The marshaler won't allow you to declare the Items array at offset 3.  You'll get a TypeLoadException as soon as you try to reference the type.  The normal offset for this member would be 4, unless you used #pragma pack(1) in the native code.

    If you can't modify the native code, you'll have to marshal the structure yourself.  Something like this:

        private delegate void GetBlah(IntPtr blah, string symbol);
    ...
          IntPtr blahPtr = Marshal.AllocHGlobal(248);
          blahImpl(blahPtr, "nobugz");
          BlahManaged myBlah = new BlahManaged();
          myBlah.A = (ushort)Marshal.ReadInt16(blahPtr, 0);
          myBlah.B = Marshal.ReadByte(blahPtr, 2);
          myBlah.Items = new ManagedStructure[12];
          for (int ix = 0; ix < 12; ++ix) {
            // As above for members of ManagedStructure.  For example:
            myBlah.Items[ix].field1 = Marshal.ReadInt32(blahPtr, 3 + ix * Marshal.SizeOf(typeof(ManagedStructure)));
          }
          Marshal.FreeHGlobal(blahPtr);

    Also check the actual size of unmanaged Blah structure.  248 can't be right if the array starts at offset 3.
    Sunday, April 13, 2008 3:06 PM
    Moderator

All replies

  • If you declare the struct in an unsafe context, you can create a pointer to it, take its address, and do all the usual pointer stuff. You can search MSDN for the C# unsafe keyword. Here's a link to a tutorial on unsafe code http://msdn2.microsoft.com/en-us/library/aa288474(VS.71).aspx.

    Hope this is helpful!

    Mark

     

    Saturday, April 12, 2008 5:19 AM
  •  

    Hi Mark,

     

    unfortunately this is not the issue here as the whole class is marked as unsafe.

    The issue is that I have an array of managed structures in the "Blah" structure. If I remove:

     

    [FieldOffset(3)]

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]

    internal ManagedStructure[] Items;

     

    ... from the struct, I declare a pointer to the "Blah" struct just fine.

     

    Regards,

     

    Tom

     

    Saturday, April 12, 2008 4:14 PM
  • You'd let the P/Invoke marshaler automatically pass a pointer by declaring the function pointer like this:

        private delegate void GetBlah(ref Blah blah, string symbol);

    There is a show-stopper problem with your declaration of the Blah structure though.  The marshaler won't allow you to declare the Items array at offset 3.  You'll get a TypeLoadException as soon as you try to reference the type.  The normal offset for this member would be 4, unless you used #pragma pack(1) in the native code.

    If you can't modify the native code, you'll have to marshal the structure yourself.  Something like this:

        private delegate void GetBlah(IntPtr blah, string symbol);
    ...
          IntPtr blahPtr = Marshal.AllocHGlobal(248);
          blahImpl(blahPtr, "nobugz");
          BlahManaged myBlah = new BlahManaged();
          myBlah.A = (ushort)Marshal.ReadInt16(blahPtr, 0);
          myBlah.B = Marshal.ReadByte(blahPtr, 2);
          myBlah.Items = new ManagedStructure[12];
          for (int ix = 0; ix < 12; ++ix) {
            // As above for members of ManagedStructure.  For example:
            myBlah.Items[ix].field1 = Marshal.ReadInt32(blahPtr, 3 + ix * Marshal.SizeOf(typeof(ManagedStructure)));
          }
          Marshal.FreeHGlobal(blahPtr);

    Also check the actual size of unmanaged Blah structure.  248 can't be right if the array starts at offset 3.
    Sunday, April 13, 2008 3:06 PM
    Moderator
  • Thanks nobugz, private delegate void GetBlah(ref Blah blah, string symbol); worked perfectly.

    The offset was actually at 8, I just screwed it up in the sample I posted here.

    Sunday, April 13, 2008 11:20 PM