New methods for managed and unmanaged conversions: Marshaling Library (ZZ)
New methods for managed and unmanaged conversions: Marshaling Library (ZZ)
Http://hi.baidu.com/superql/blog/item/38e9c8073202fcc37a8947ac.html
Newly added libraries in 1.vc++2008: Marshaling Library
Let's discuss the new library--marshaling, introduced in vc++2008. The traditional method we used before this class library was the fixed pointer (pin_ptr). To use the marshaling library, you must include the header file <msclr/marshal.h>, use a namespace msclr::interop, and use the Marshal_as template method to perform the transformation, which requires two parameters: One is the target type as the template parameter , and the other is the parameter of the method, which is the object to be converted .
If you want to convert a const wchar_t* type to string^, you can write:
Const wchar_t* Source;
string^ dest = marshal_as<string^> (source);
Some transformations need to allocate memory and must be deleted later. Such conversions require an object called context, which is deleted when it is no longer needed. For example, converting from a managed string^ to a local char* requires a context because a temporary copy of string is generated during the conversion process. The code is as follows:
Marshal_context context;
Const WCHAR_T* = context.marshal_as<const wchar_t*> (str);
Many conversions are predefined in this marshaling library, most of which are type conversions of strings. You can also expand yourself to your own needs. If you are interested, you can refer to MSDN.
2. Using the marshaling library for interoperability versus previous comparisons
Take a look at some concrete examples to see the marshaling library brings us the convenience:
previous situation: before we did this by including some methods of the <vcclr.h> header file, referring to the Marshal class in the System::runtime::interopservices namespace, to convert the type, These methods are not easy to remember on the one hand, and the conversion is not straightforward and error prone. For example, a string is converted between managed and unmanaged:
L Convert managed strings to ANSI strings
string^ s = gcnew string ("sample string");
IntPtr IP = marshal::stringtohglobalansi (s);
Const char* str = static_cast<const char*> (IP. ToPointer ());
L Convert an unmanaged ANSI string to a managed string
void Managedstringfunc (s) {
string^ ms = Marshal::P trtostringansi (static_cast<intptr> (s));
}
Here S is the type of char*, if it is a const char*, you need to first remove the constant character of the string variable
Const char* tempstring = const_cast<char*> (s);
Because Static_const cannot convert const char* to system::intptr.
the conversion of Unicode strings is similar to the above, with the const wchar_t* being converted to the string^ type by first removing its constant character.
with the Marshal Library: now with after the Marshal Library, you can marshal_as the template method for all conversions!
The Marshal_as template method provides a way to include the Ansi,unicode string directly into the managed and unmanaged transformations, remembering to include the header file and the reference namespace. The sample code is as follows:
#include <msclr/marshal.h>
Using namespace MSCLR::Interop;
L Convert ANSI string char* ch to managed string
string^ s = marshal_as<string^> (ch);
L Convert constant ANSI string const char* CH to managed string
string^ s = marshal_as<string^> (CH);
Note: This is no longer necessary to remove the constant!
L Convert managed strings to unmanaged
marshal_context context;
return context.marshal_as<const char*> (str);
Note: A context contextual object is required at this point
The conversion of a Unicode string between managed and unmanaged types is similar to the conversion of an ANSI string.
As can be seen, marshal_as is not only more convenient, but also provides more support types such as BSTR and system::string^, std::string and system::string^ and so on. This greatly improves the efficiency of the developer and makes the transition a lot more efficient.
If you want to extend the custom type, from local to managed, you only need to implement the following template method:
Namespace MSCLR {
Namespace Interop {
Template<>
Inline to Marshal_as<to, from> (const from& from) {
Insert conversion logic here, and return a to parameter.
}
}
}
If you need to convert from a managed type to a local type, you also need to implement a template class, and if you are interested, you can refer to MSDN and not repeat it here.
int intdat1[] = {1,2,3,4,5};
array<int>^ GCDAT1 = gcnew array<int> (5);
Marshal::copy ((INTPTR) intdat1,gcdat1,0,5);
char* str = "abcdef";
array<byte>^ ByteArray =gcnew array<byte> (6);
Marshal::copy ((INTPTR) str,bytearray,0,6);
Starting from the definition of array, this paper introduces three methods of array marshalling, and further discusses the concepts of blittable type.
When managed code needs to interoperate with native code, we go into the realm of interop. The interop scene is diverse, and the constant is that we need to marshal data from one world to another.
Before discussing the array marshalling, please join me in thinking about a question, what is an array? The reason for discussing this problem is that different terms have different meanings in different contexts. When I use C, I think the array is a pointer. But friends who are familiar with C # may disagree with my view that the array is System.Array or object[]. I think both of these responses are from the correct point of view in the Language field. So if there is a project with two modules, one written in local code, the other is written in managed code, the interface between the two requires passing an array, what semantics does this "array" contain?
I think it's important to have two points:
1. How to access array elements. Just like an array pointer in C, an array reference in C # is an essential clue to accessing an array.
2. The size of the array. The size of the array is not just System.Array.Length. It can also include dimensions such as arrays, start and end boundaries on each dimension.
. NET in the Marshal array, is to a large extent from the above two points, set up between the managed world and the local Code bridge. Depending on the specific data type of the operation, the array marshal can be divided into the following two large categories, three small classes, we introduce:
1. The array is passed as a parameter
A) Arrays of type C + +
An array of type C, that is, an array of the first address of the storage space indicated by the pointer, is a very low self-describing data structure. Although some compilers support writing the length of an array at a fixed offset, there is no standard for the CLR to refer to because of the different methods that each compiler handles. So when we marshal a C-type array, we had to consider the size of the passed array in other ways, with the following two types:
1) Convention pointer array length
This method requires a contract between the caller and the callee, giving a fixed value for the length of the array. When declaring an interop method on the managed side, simply use the SizeConst property to tell the CLR about this Convention. The CLR allocates the appropriate space on the local heap, based on this value, when it is marshal.
public static extern void Ex (
[In, out] [MarshalAs (UnmanagedType.LPArray,sizeparamconst=3)]string[] a);
2) Specify the length of the array with an additional parameter
Perhaps some friends think that the convention of a static array length is not flexible enough to be able to dynamically pass the length of the array, so that the array marshalling does not have to be constrained by the fixed array length limit. Let's take a look at how the normal function call solves the problem: caller and callee Pass the length of the array by agreeing on an extra parameter, which can be seen as a contract between the caller and the callee. Since marshalling requires the participation of the CLR, it is necessary to extend this convention in a way that the CLR can understand to form a tripartite convention.
The CLR uses attribute SizeParamIndex to describe such conventions.
public static extern void Ex2 (
[In, out] [MarshalAs (UnmanagedType.LPArray, sizeparamindex=1)]string[] A,
int len);
b) SafeArray
SAFEARRAY is a data type introduced by COM and is a highly self-descriptive data structure. He can tell the user very clearly, the element type of the array, how many dimensions the array contains, the starting and ending positions of each dimension. So when marshal this kind of safearray, just by setting the property, tell the CLR that the local code corresponding to the current array is SAFEARRAY. Examples are as follows:
public void Dumpsafearraystringin ([In][marshalas (Unmanagedtyp E.safearray, SAFEARRAYSUBTYPE=VARENUM.VT_BSTR)]object[] array);
As you can see, safearraysubtype can be used to specify the type of the array element
2. Arrays are passed as fields
For a long time, for interop, there has been such a review, the simple data structure of the marshalling is not complex, but once entered the struct or class you have me, I have your cascade data structure, marshalling become a bug hotbed. So here we also want to mention the array as a field of the Struct/class method. The first thing to do here is to add a limit to this stuct/class, which is ByVal. As a result of this limitation, as you can imagine, when the CLR is marshal, it does something similar to a shallow copy of memory, so when an array is marshal, it supports only fixed-length arrays marshal.
public class Structintarray
{
[MarshalAs (UnmanagedType.ByValArray, sizeconst=4)]
Public int[] array;
}
Array as a common data structure, a variety of high-level languages have provided the corresponding support, in these high-level language interaction between the time, the array is also a collection type of data transfer important structure, I hope today's content can help.
New methods for managed and unmanaged conversions: Marshaling Library (ZZ) "Go"