Absolutely good. C # call C++dll the ultimate solution for passing struct-body arrays

Source: Internet
Author: User

C # Call C++dll the ultimate solution for passing struct-body arraystime 2013-09-17 18:40:56 csdn blog Similar article ( 0) original http://blog.csdn.net/xxdddail/article/ details/11781003

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 Inf                O[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 OrderNo;            [MarshalAs (UnmanagedType.ByValArray, SizeConst = +)] public byte[] Uniquecode;        public float cpupercent;        }; private void Buttontest_click (object sender, EventArgs e) {try {int workstat                Ioncount = 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) infosintptr + 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;               public 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" >str        UCT type or class type.        Egg:class human{...};        Human human=new Human (); Type Type=human. GetType ();</param>///<returns>destination struct or class.</returns> public static objec T bytestostruct (byte[] bytes, type type) {int size = marshal.sizeof (Type);//get size of the struct or C                      Lass. 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
Error

Absolutely good. C # call C++dll the ultimate solution for passing struct-body arrays

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.