Marshalling complex C# struct to C DLL. Error marshalling and unmarshalling. RRS feed

  • Question

  • SO here is my problem. I have a tree structure with several level with complex data type. But here is the simple snippet of code that I prototype and it is not working. The problem is my internal structure YStruct in X has datatype of UINT32 and all the other are UINT16 for simplicity and it seems marshalling and unmarshalling is having issue. One can see the result in console. 
    I have a structure in C# and it when passed to unmanaged code, some of the parameters get changed. And when I get the result back i do not get the required result. In fact the structure is messed up and I get garbage data.

    Here is the C dll code


    typedef unsigned short word;

    typedef unsigned __int64 qword;

    typedef unsigned long dword ;

    typedef unsigned char byte;

    typedef struct

      word a;
      word b;
       word c;
        YStruct y;
       word d;
       word e;
       word f;

    } X;

    typedef struct
      dword g;
    } YStruct;


    #include "DLLCode.h"

    #include "string.h";

    #include "stdio.h";

    #pragma pack(1)   

    extern "C" 


      __declspec(dllexport) void UpdateCalRecord(void* rec)


    X* calRec = (X*) rec;

          printf("*******************************Input to C Code******************\n");

            printf("U2: b = %d \n",calRec->b);

    printf("U2: c= %d \n", calRec->c);

      printf("*******************************Input to C Code Ended******************\n");

    calRec->e = 999;
    calRec->b = 444;
    calRec->f = 55555;
    calRec->a = 6;

    calRec->d = 0xD;
    calRec->c = 22222;
    calRec->y.g = 30;
    printf("*******************************C Code parameters set******************\n");
    printf("U2: a= %d\n", calRec->a); 
    printf("U2: b= %d \n",calRec->b);
    printf("U2: c= %d \n", calRec->c);
    printf("U4: g= %d \n",calRec->g);
    printf("U2: d: %d\n", calRec->d);
    printf("U2: e= %d \n",calRec->e);
    printf("U2: f= %d \n",calRec->f);
    printf("*****************************C code parameter end************************\n");

    Here is the C# code::
    ************************************ C# code****************************************

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Runtime.InteropServices;

    class Program
            [DllImport("Win32DLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
            public extern static void UpdateCalRecord(ref X rec);

            static void Main(string[] args)
                X record = new X();
                record.a = 2;

                record.b = 111;
             //   record.y.g = 20;
                record.c = 40;
                Console.WriteLine("**********************Before API call********************");

                Console.WriteLine("b: " + record.b);
                Console.WriteLine("c: " + record.c);
                UpdateCalRecord(ref record);
                Console.WriteLine("******************After API call*****************");
                Console.WriteLine("U2: a: " + record.a);
                Console.WriteLine("U2: b: " + record.b);
                Console.WriteLine("U2: c: " + record.c);
                Console.WriteLine("U4: g: " + record.y.g);
                Console.WriteLine("U2: d: " + record.d);
                Console.WriteLine("U2: e: " + record.e);
                Console.WriteLine("U2: f: " + record.f);


            [StructLayout(LayoutKind.Sequential, Pack=1)]

            public struct X

                 public UInt16 a;

                public UInt16 b;

                public UInt16 c;

               public YStruct y;

                public UInt16 d;
                public UInt16 e;


                public UInt16 f;


         public struct YStruct


                    public UInt32 f;




    • Edited by callnadeem Thursday, October 10, 2013 7:36 PM Typo in YStruct it is UINt32
    Thursday, October 10, 2013 4:33 PM

All replies

  • Since YStruct includes a dword, which is a 32-bit value, fix the marshaling definition. Use for example UnmanagedType.U4 and UInt32.

    Show the wrong results displayed on your console.

    • Edited by Viorel_MVP Thursday, October 10, 2013 7:23 PM
    Thursday, October 10, 2013 7:22 PM
  • We found this issue is resolved when we remove struct layout or change Pack to 0 or 4 in managed code. Dont know why though even in unmanged code we set the "pragma Pack(1)".

    However we now run into union problem.

    So our YStruct in C# looks like this now

    public struct YStruct 


         public Z z;


         public UInt32 f;



            public struct Z
                public UInt16 m;

                public UInt16 n;
                public UInt64 p;

                public UInt64 q;
                public UInt64 r;
                public UInt64 s;


    And in the C code it looks like 

     typedef struct


         word m;



             word n;

             qword p;

             qword q;

              qword r;

               qword s;



    So here what I did I set the value of the one of the union to a number say 100 before calling the unamanged code. Once the unmanged code is invoked i check the value union value it is changed to 0. Again I set that value to say 500 in unmanged code, but when the method from unmanaged code return I get 100 so the value did not changed for the union.

    I do not know what I am doing wrong here. 


    Thursday, October 10, 2013 8:02 PM