Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. C#
  4. Marshaling the structure array member of Structure in C#

Marshaling the structure array member of Structure in C#

Scheduled Pinned Locked Moved C#
helpquestioncsharpdata-structures
14 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Heath Stewart

    Marshalling nested structs is not supported in the .NET Framework. Instead, you need to marshal them as IntPtrs using Marshal.StructureToPtr and back using Marshal.PtrToStructure:

    [StructLayout(LayoutKind.Sequential)]
    public struct FirstStruct
    {
    [MarshalAs(UnmanagedType.R4)] public double XSpeed;
    [MarshalAs(UnmanagedType.SysInt)] public IntPtr DRate;
    [MarshalAs(UnmanagedType.SysUInt)] public IntPtr RotCtrl;
     
    // ctor added for convenience and example.
    public FirstStruct(double XSpeed, long DRate, long RotCtrl)
    {
    this.XSpeed = XSpeed;
    this.DRate = new IntPtr(DRate);
    this.RotCtrl = new IntPtr(RotCtrl);
    }
    }
     
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    public struct SecondStruct : IDisposable
    {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=20)] public string Model;
    [MarshalAs(UnmanagedType.SysUInt)] public IntPtr SuptText;
    public IntPtr CurSpd;
    public IntPtr MaxRdSpd;
    [MarshalAs(UnmanagedType.SysUInt)] public IntPtr cNumSpd;
    public IntPtr CrwWrd;
    public IntPtr DWrd;
     
    // ctor added for convenience and example.
    public SecondStruct(string Model, long SuptText, FirstStruct CurSpd,
    FirstStruct MaxRdSpd, long cNumSpd, FirstStruct[] CrwWrd,
    FirstStruct[] DWrd)
    {
    if (CrwWrd == null || DWrd == null)
    throw new ArgumentNullException(CrwWrd == null ? "CrwWrd" : "DWrd");
    if (CrwWrd.Length > 40) throw new ArgumentException("Error", "CrwWrd");
    if (DWrd.Length > 20) throw new ArgumentException("Error", "DWrd");
     
    this.Model = Model;
    this.SuptText = new IntPtr(SuptText);
    this.cNumSpd = new IntPtr(cNumSpd);
     
    // Get the address of the structs and arrays.
    GCHandle handle = GCHandle.Alloc(CurSpd);
    this.CurSpd = handle.AddrOfPinnedObject();
    handle = GCHandle.Alloc(MaxRdSpd);
    this.MaxRdSpd = handle.AddrOfPinnedObject();
    handle = GCHandle.Alloc(CrwWrd);
    this.CrwWrd = handle.AddrOfPinnedObject();
    handle = GCHandle.Alloc(DWrd);
    this.DWrd = handle.AddrOfPinnedObject();
    }
     
    // IDisposable explicit interface implementation
    void IDisposable.Dispose()
    {
    GCHandle handle = (GCHandle)this.CurSpd;
    if (handle.IsAllocated) handle.Free();
    handle = (GCHandle)this.MaxRdSpd;
    if (handle.IsAllocated) handle.Free();
    handle = (GCHandle)this.CrwWrd;
    if (handle.IsAllocated) handle.Free();
    handle = (GCHandle)this.DWrd;
    if (handle.IsAllocated) handle.Fr

    V Offline
    V Offline
    Vini Deep
    wrote on last edited by
    #5

    Heath Stewart wrote: // Define the callback.[return: MarshalAs(UnmanagedType.SysUInt)]public delegate IntPtr MyFunc(ref SecondStruct Info); This should work. Thanks Very much. But I am not fully clear. __declspec (dllexport) unsigned int CALLBACK MyFunc(SEC_STRUCT * Info); This is the function exported by the C++ Dll. How should I call this function from my C# client?

    [DllImport("MyDll",CallingConvention=CallingConvention.Cdecl)]
    public extern static System.UInt32  MyFunc(ref SecondStruct Info) ;
      
    
    private void button1_Click(object sender, System.EventArgs e)
    {
        FirstStruct[] first= new FirstStruct[40];
        ...
        SecondStruct info = new SecondStruct(....,first,...);
        System.UInt32 uRet= MyFunc(ref info);
        MessageBox.Show(info.Model);
        ...
    }
    

    Is this code correct? How to marshal the SecondStruct to IntPtr using Marshal.StructureToPtr and back using Marshal.PtrToStructure? Pls Help. Thanks :rose: Vini

    H 1 Reply Last reply
    0
    • V Vini Deep

      Heath Stewart wrote: // Define the callback.[return: MarshalAs(UnmanagedType.SysUInt)]public delegate IntPtr MyFunc(ref SecondStruct Info); This should work. Thanks Very much. But I am not fully clear. __declspec (dllexport) unsigned int CALLBACK MyFunc(SEC_STRUCT * Info); This is the function exported by the C++ Dll. How should I call this function from my C# client?

      [DllImport("MyDll",CallingConvention=CallingConvention.Cdecl)]
      public extern static System.UInt32  MyFunc(ref SecondStruct Info) ;
        
      
      private void button1_Click(object sender, System.EventArgs e)
      {
          FirstStruct[] first= new FirstStruct[40];
          ...
          SecondStruct info = new SecondStruct(....,first,...);
          System.UInt32 uRet= MyFunc(ref info);
          MessageBox.Show(info.Model);
          ...
      }
      

      Is this code correct? How to marshal the SecondStruct to IntPtr using Marshal.StructureToPtr and back using Marshal.PtrToStructure? Pls Help. Thanks :rose: Vini

      H Offline
      H Offline
      Heath Stewart
      wrote on last edited by
      #6

      What I did is an alternative to Marshal.StructureToPtr and Marshal.PtrToStructure (along with using Marshal.AllocHGlobal). Either way should work. The reason I define MyFunc as a delegate is because the native signature declared it as a CALLBACK. This indicates (though for your circumstances, I may be wrong) that you don't actually call this method, but simply pass it as a callback to some other function. If you were to declare it as a P/Invoke method, it would look like this:

      [DllImport("mydll.dll")]
      private static extern uint MyFunc(ref SecondStruct s);

      Microsoft MVP, Visual C# My Articles

      V 1 Reply Last reply
      0
      • H Heath Stewart

        What I did is an alternative to Marshal.StructureToPtr and Marshal.PtrToStructure (along with using Marshal.AllocHGlobal). Either way should work. The reason I define MyFunc as a delegate is because the native signature declared it as a CALLBACK. This indicates (though for your circumstances, I may be wrong) that you don't actually call this method, but simply pass it as a callback to some other function. If you were to declare it as a P/Invoke method, it would look like this:

        [DllImport("mydll.dll")]
        private static extern uint MyFunc(ref SecondStruct s);

        Microsoft MVP, Visual C# My Articles

        V Offline
        V Offline
        Vini Deep
        wrote on last edited by
        #7

        Thanks.. Couldn't quite get it correct. The structure is passed to the function in dll as reference. If I declare the structure array variable as IntPtr, should I use pointer arithematics to read the value back from the structure array member of the struct? Tnx :) Vini

        H 1 Reply Last reply
        0
        • V Vini Deep

          Thanks.. Couldn't quite get it correct. The structure is passed to the function in dll as reference. If I declare the structure array variable as IntPtr, should I use pointer arithematics to read the value back from the structure array member of the struct? Tnx :) Vini

          H Offline
          H Offline
          Heath Stewart
          wrote on last edited by
          #8

          More than likely, this is going to be necessary. See the Marshal class documentation, though, for some methods that may ease the process a little. One more thing you should consider if you can modify the unmanaged code is a thunking layer. Basically, these come in handy when you have marshaling problems such as this. For example, you could define a method with takes all the fields as parameters for the first and second struct and then assembles them internally into the second struct, which it then calls the unmanaged function you are now. Using this approach, you'd be able to easily marshal members of both of the structs.

          Microsoft MVP, Visual C# My Articles

          V 1 Reply Last reply
          0
          • H Heath Stewart

            More than likely, this is going to be necessary. See the Marshal class documentation, though, for some methods that may ease the process a little. One more thing you should consider if you can modify the unmanaged code is a thunking layer. Basically, these come in handy when you have marshaling problems such as this. For example, you could define a method with takes all the fields as parameters for the first and second struct and then assembles them internally into the second struct, which it then calls the unmanaged function you are now. Using this approach, you'd be able to easily marshal members of both of the structs.

            Microsoft MVP, Visual C# My Articles

            V Offline
            V Offline
            Vini Deep
            wrote on last edited by
            #9

            Sorry about this. I very much appretiate your help :rose:. Still a basic doubt: Heath Stewart wrote:

            [StructLayout(LayoutKind.Sequential)]
            public struct FirstStruct
            {
            [MarshalAs(UnmanagedType.R4)] public double XSpeed;
            [MarshalAs(UnmanagedType.SysInt)] public IntPtr DRate;
            [MarshalAs(UnmanagedType.SysUInt)] public IntPtr RotCtrl;
            // ctor added for convenience and example.
            public FirstStruct(double XSpeed, long DRate, long RotCtrl)
            {
            this.XSpeed = XSpeed;
            this.DRate = new IntPtr(DRate);
            this.RotCtrl = new IntPtr(RotCtrl);
            }
            }

            Is there any problem if I declare the structure as [StructLayoutAttribute(LayoutKind.Sequential)] public struct FirstStruct { public System.Double XSpeed; public System.Int32 DRate; public System.UInt32 RotCtrl; } If I want to call a function from a dll written in C++ from my c# client, what should I do? Should I create a similar C# structure with managed DataTypes and use that to call the c++ dll function from my C# client, then use it to get the values returned by the Dll **OR** Should I create a similar structure in C# with Unmanaged Type data and then pass it to the function exported by the Dll and use the values returned? Is the above both declaration one and the same? I have used [MarshalAs(UnmanagedType.ByValTStr, ....)] only in places where the variable declared was char[].

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)] public string Vendor;
            

            When I debug the program, at the function call I get an 'ExecutionEngineException'. Is it the problem which the marshaling of the structure array? Kindly help. Vini

            H 1 Reply Last reply
            0
            • V Vini Deep

              Sorry about this. I very much appretiate your help :rose:. Still a basic doubt: Heath Stewart wrote:

              [StructLayout(LayoutKind.Sequential)]
              public struct FirstStruct
              {
              [MarshalAs(UnmanagedType.R4)] public double XSpeed;
              [MarshalAs(UnmanagedType.SysInt)] public IntPtr DRate;
              [MarshalAs(UnmanagedType.SysUInt)] public IntPtr RotCtrl;
              // ctor added for convenience and example.
              public FirstStruct(double XSpeed, long DRate, long RotCtrl)
              {
              this.XSpeed = XSpeed;
              this.DRate = new IntPtr(DRate);
              this.RotCtrl = new IntPtr(RotCtrl);
              }
              }

              Is there any problem if I declare the structure as [StructLayoutAttribute(LayoutKind.Sequential)] public struct FirstStruct { public System.Double XSpeed; public System.Int32 DRate; public System.UInt32 RotCtrl; } If I want to call a function from a dll written in C++ from my c# client, what should I do? Should I create a similar C# structure with managed DataTypes and use that to call the c++ dll function from my C# client, then use it to get the values returned by the Dll **OR** Should I create a similar structure in C# with Unmanaged Type data and then pass it to the function exported by the Dll and use the values returned? Is the above both declaration one and the same? I have used [MarshalAs(UnmanagedType.ByValTStr, ....)] only in places where the variable declared was char[].

              [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)] public string Vendor;
              

              When I debug the program, at the function call I get an 'ExecutionEngineException'. Is it the problem which the marshaling of the structure array? Kindly help. Vini

              H Offline
              H Offline
              Heath Stewart
              wrote on last edited by
              #10

              First, in your declaration it is more desirable to use the intrinsic keywords instead of their actual types, like double instead of System.Double. Either way works, but the former makes your code more readable. They are the same thing, after all. The problem with declaring the last two as int and uint is that a native int and unsigned int are actual processor dependent. So, if this was running on a 64-bit processor, your struct wouldn't marshal correctly. An Int32 (int) will always be 32 bits, meaning that your field alignment will be incorrect and you'll get invalid values. That's why I declared them as IntPtr and made the parameters long (to allow for large enough numbers, although your values may never be more than 32 bits). No matter how you declare your structs, the problem is that nested structures can't be marshalled by the CLR. That's why I suggested a thunk. You could declare a native function and P/Invoke that like so:

              [DllImport("whatever.dll", CharSet=CharSet.Ansi)]
              private static extern IntPtr MyFuncThunk(
              [MarshalAs(UnmanagedType.ByValTStr, SizeConst=20)] string Model,
              [MarshalAs(UnmanagedType.SysUInt)] IntPtr SuptText,
              FirstStruct CurSpd,
              FirstStruct MaxRdSpd,
              [MarshalAs(UnmanagedType.SysUInt)] IntPtr cNumSpd,
              [MarshalAs(UnmanagedType.ByValArray, SizeConst=40)] FirstStruct[] CrwWrd,
              [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)] FirstStruct[] DWrd);
               
              [DllImport("whatever.dll")]
              private static extern IntPtr MyFunc(IntPtr Info);

              You pass your data to the thunk which allocs and initializes the struct (SEC_STRUCT), then returns the address to the struct (a pointer). You can use that pointer then in the call to MyFunc, although I still wonder if you really want to P/Invoke this since the function is most likely not exported, being that it's a CALLBACK. The one way to find out is to load your DLL into depends.exe (comes with the Platform SDK tools, which is installed by default with Visual Studio) and look at the exports.

              Microsoft MVP, Visual C# My Articles

              V 1 Reply Last reply
              0
              • H Heath Stewart

                First, in your declaration it is more desirable to use the intrinsic keywords instead of their actual types, like double instead of System.Double. Either way works, but the former makes your code more readable. They are the same thing, after all. The problem with declaring the last two as int and uint is that a native int and unsigned int are actual processor dependent. So, if this was running on a 64-bit processor, your struct wouldn't marshal correctly. An Int32 (int) will always be 32 bits, meaning that your field alignment will be incorrect and you'll get invalid values. That's why I declared them as IntPtr and made the parameters long (to allow for large enough numbers, although your values may never be more than 32 bits). No matter how you declare your structs, the problem is that nested structures can't be marshalled by the CLR. That's why I suggested a thunk. You could declare a native function and P/Invoke that like so:

                [DllImport("whatever.dll", CharSet=CharSet.Ansi)]
                private static extern IntPtr MyFuncThunk(
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst=20)] string Model,
                [MarshalAs(UnmanagedType.SysUInt)] IntPtr SuptText,
                FirstStruct CurSpd,
                FirstStruct MaxRdSpd,
                [MarshalAs(UnmanagedType.SysUInt)] IntPtr cNumSpd,
                [MarshalAs(UnmanagedType.ByValArray, SizeConst=40)] FirstStruct[] CrwWrd,
                [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)] FirstStruct[] DWrd);
                 
                [DllImport("whatever.dll")]
                private static extern IntPtr MyFunc(IntPtr Info);

                You pass your data to the thunk which allocs and initializes the struct (SEC_STRUCT), then returns the address to the struct (a pointer). You can use that pointer then in the call to MyFunc, although I still wonder if you really want to P/Invoke this since the function is most likely not exported, being that it's a CALLBACK. The one way to find out is to load your DLL into depends.exe (comes with the Platform SDK tools, which is installed by default with Visual Studio) and look at the exports.

                Microsoft MVP, Visual C# My Articles

                V Offline
                V Offline
                Vini Deep
                wrote on last edited by
                #11

                Thanks. But my function eventhough declared as a call back, is called by the UI. I already have a c++ client which uses this dll and calls the said function. I am trying to build a similar client in C#. As far as writing another method is concerned, I have got only the .dll file and the .h file with me. source code is not available. I have used the depends.exe, which shows me an entry to the above mentioned function as _MyFunc@4 in the dll. Any idea?? Vini

                H 1 Reply Last reply
                0
                • V Vini Deep

                  Thanks. But my function eventhough declared as a call back, is called by the UI. I already have a c++ client which uses this dll and calls the said function. I am trying to build a similar client in C#. As far as writing another method is concerned, I have got only the .dll file and the .h file with me. source code is not available. I have used the depends.exe, which shows me an entry to the above mentioned function as _MyFunc@4 in the dll. Any idea?? Vini

                  H Offline
                  H Offline
                  Heath Stewart
                  wrote on last edited by
                  #12

                  In your DllImportAttribute, set EntryPoint="_MyFunc@4". If you can't modify the source, you'll have to manually marshal the nested structs as I mentioned before by either pinning the first struct or using the appropriate Marshal methods.

                  Microsoft MVP, Visual C# My Articles

                  V 1 Reply Last reply
                  0
                  • H Heath Stewart

                    In your DllImportAttribute, set EntryPoint="_MyFunc@4". If you can't modify the source, you'll have to manually marshal the nested structs as I mentioned before by either pinning the first struct or using the appropriate Marshal methods.

                    Microsoft MVP, Visual C# My Articles

                    V Offline
                    V Offline
                    Vini Deep
                    wrote on last edited by
                    #13

                    Thank You very much... :rose: Finally I think I am getting everything right. I used the method of pinning the first structure , which u mentioned in one of your previous post. Tnx a lot. cheers :) Vini

                    P 1 Reply Last reply
                    0
                    • V Vini Deep

                      Thank You very much... :rose: Finally I think I am getting everything right. I used the method of pinning the first structure , which u mentioned in one of your previous post. Tnx a lot. cheers :) Vini

                      P Offline
                      P Offline
                      poda
                      wrote on last edited by
                      #14

                      Hai Vini Deep, My need is same as your problem. Please reply if you have solved it. Thanks friend.

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups