A solution to the C # call C++dll passing struct-body array

Source: Internet
Author: User
This article mainly describes the C # call C++dll transfer struct array of the ultimate solution of the relevant data, the need for friends can refer to the following

C # Call C++dll the ultimate solution for passing struct-body arrays

In the project development, to invoke the C + + encapsulated DLL, ordinary type C # on the general correspondence, as long as the use of DllImport passed into the DLL from the introduction of functions can be. But when passing a struct, struct array, or struct pointer, there is no type on C # that can correspond. How to do this, the first reaction is C # also define the structure, and then as the parameters of the brother. However, when we define a struct, we want to pass the parameter in, throw an exception, or pass in the struct, but the return value is not what we want, after debugging the trace found that the values have not changed at all, the code is as follows.

[dllimport ("WorkStation.dll")] private static extern bool Fetchinfos (info[] infos);        public struct Info {public int orderno;        Public byte[] Uniquecode;               public float cpupercent;     };         private void Buttontest_click (object sender, EventArgs e) {try {info[] infos=new info[128];         if (Fetchinfos (infos)) {MessageBox.Show ("Fail");           } else {String message = ""; foreach (info info in infos) {message + = string. Format ("orderno={0}\r\nuniquecode={1}\r\ncpu={2}", info. OrderNo, Encoding.UTF8.GetString (info. Uniquecode), info.           Cpupercent);       } messagebox.show (message); }} catch (System.Exception ex) {MessageBox.Show (ex).       Message); }     }

Later, after looking for information, it is mentioned that for C # is a managed memory, now to pass the struct array, is the property of unmanaged memory, you must specify the space with Marsh, and then pass. The structure is then changed as follows.

StructLayoutAttribute (layoutkind.sequential, CharSet = charset.ansi, Pack = 1)] public    struct Info    {      public int orderno;       [MarshalAs (UnmanagedType.ByValArray, SizeConst = +)]      Public byte[] Uniquecode;       public float cpupercent;              };

However, after such an improvement, the result is still not ideal, the value is either wrong or not changed. What is the reason for this? Constantly search information, finally saw an article, which refers to the structure of the transfer, and some can do as above, but some but not, especially when the parameters in C + + is a struct pointer or struct array pointer, in C # call place also to use pointers to correspond to, the following improved code.

[DllImport ("WorkStation.dll")] private static extern bool Fetchinfos (IntPtr infosintptr); [StructLayoutAttribute (layoutkind.sequential, CharSet = charset.ansi, Pack = 1)] public struct Info {public int O      Rderno;      [MarshalAs (UnmanagedType.ByValArray, SizeConst = +)] public byte[] Uniquecode;    public float cpupercent;   };       private void Buttontest_click (object sender, EventArgs e) {try {int workstationcount = 128;       int size = marshal.sizeof (typeof (Info));       IntPtr infosintptr = marshal.allochglobal (Size * workstationcount);       info[] infos = new Info[workstationcount];         if (Fetchinfos (infosintptr)) {MessageBox.Show ("Fail");       Return } for (int inkindex = 0; Inkindex < Workstationcount; inkindex++) {IntPtr ptr = (IntPtr) ((UInt32) I         Nfosintptr + inkindex * size);       Infos[inkindex] = (info) marshal.ptrtostructure (PTR, typeof (info)); } marshal.freehglobal (InfosintPTR);       String message = ""; foreach (info info in infos) {message + = string. Format ("orderno={0}\r\nuniquecode={1}\r\ncpu={2}", info. OrderNo, Encoding.UTF8.GetString (info. Uniquecode), info.       Cpupercent);      } messagebox.show (message); } catch (System.Exception ex) {MessageBox.Show (ex.     Message); }   }

Note that the interface has been changed to IntPtr. Through the above way, finally the structure of the array to pass in. However, it is important to note that different compilers are not necessarily the size of the struct, such as the structure above

In BCB, if there is no byte alignment, it is sometimes 22 bytes more than the normal structure size. Because BCB default is 2 byte sort, and VC is the default 1 byte sort. To solve this problem, either increase the byte alignment in the BCB structure, or open two more bytes in C # (if there are more). The byte alignment code is as follows.

#pragma pack (push,1)   struct Info {   int orderno;          Char uniquecode[32];    float cpupercent; }; #pragma pack (POP)

Using Marsh.allochglobal as the structure of the pointer to open up memory space, the purpose is to change the unmanaged memory, then if not marsh.allochglobal, there is no other way?

In fact, whether in C + + is a pointer or an array, eventually in memory or a byte of storage, that is, eventually in a one-dimensional array of bytes to show, so if we open a one-dimensional array of equal size, then whether it is possible? The answer is yes, the following gives the implementation.

[DllImport ("WorkStation.dll")] private static extern bool Fetchinfos (IntPtr infosintptr);     [DllImport ("WorkStation.dll")] private static extern bool Fetchinfos (byte[] infos);  [StructLayoutAttribute (layoutkind.sequential, CharSet = charset.ansi, Pack = 1)] public struct Info {public        int OrderNo;        [MarshalAs (UnmanagedType.ByValArray, SizeConst = +)] public byte[] Uniquecode;      public float cpupercent;         };         private void Buttontest_click (object sender, EventArgs e) {try {int count = 128;         int size = marshal.sizeof (typeof (Info));                 byte[] Inkinfosbytes = new byte[count * size];           if (Fetchinfos (inkinfosbytes)) {MessageBox.Show ("Fail");         Return         } info[] Infos = new Info[count];           for (int inkindex = 0; inkindex < count; inkindex++) {byte[] inkinfobytes = new Byte[size]; Array.copy (Inkinfosbytes, InkiNdex * size, inkinfobytes, 0, size);         Infos[inkindex] = (info) bytestostruct (inkinfobytes, typeof (Info));         } String message = ""; foreach (info info in infos) {message + = string. Format ("orderno={0}\r\nuniquecode={1}\r\ncpu={2}", info. OrderNo, Encoding.UTF8.GetString (info. Uniquecode), info.         Cpupercent);        } messagebox.show (message); } catch (System.Exception ex) {MessageBox.Show (ex.       Message);     }} #region Bytestostruct//<summary>//Byte array to struct or classs. </summary>//<param name= "bytes" >byte array</param>//<param name= "type" >struct ty     PE or class type.     Egg:class human{...};     Human human=new Human (); Type Type=human. GetType ();</param>///<returns>destination struct or class.</returns&Gt  public static Object Bytestostruct (byte[] bytes, type type) {int size = marshal.sizeof (Type);//get size of the            struct or class. if (bytes.       Length < size) {return null;        } IntPtr structptr = Marshal.allochglobal (size);//allocate memory space of the struct or class.       Marshal.Copy (bytes, 0, structptr, size);//copy byte array to the memory space.            Object obj = Marshal.PtrToStructure (structptr, type);//convert memory space to destination struct or class.         Marshal.freehglobal (structptr);//release memory space.     return obj; } #endregion

For the really unexpected how to transmit data, you can consider a byte array to pass (that is, the integer type can also, as long as the opening of 4 bytes (under 32 bits)), as long as the length of the open, after the data, to the type of the rules to be converted to the desired data, generally can achieve the purpose.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.