This class is. Class in NETFramework2.0, so we can use it in unity. Similar to this class is the Litjson, perhaps to save byte space, the Marshal class only packages the value into bytes stream, and JSON also contains the previous key value. Of course you can also choose the way JSON, I just introduce the use of the Marshal class.
The Marshal class supports copying data from a managed memory space to an unmanaged memory space, or from an unmanaged memory space to a managed memory space. If you study the MSDN document Library online, you will see it on the desktop. NET Framework, this class supports methods for allocating unmanaged memory space and other methods that work with COM objects. No memory space management and COM support methods appear in the marshal implementation of the. NET Compact Framework. Table 4.5 summarizes the members supported by the. NET Compact Framework for the Marshal class: The 13 method name (with one or more overloaded versions) and a read-only domain.
Table 4.5 members supported by the. NET Compact Framework in the Marshal class
Marshal Members |
Describe |
Replication between managed and unmanaged |
Copy |
Copies the array of value types between managed and unmanaged memory spaces. Supports CLI integral type, including 64-bit integer type. Supports single-precision and double-precision floating-point numbers. There are 14 overloaded methods (7 are used to replicate to managed memory space; 7 are used to replicate to unmanaged memory space) |
Copy to unmanaged memory space |
StructureToPtr |
Replicating managed objects to unmanaged memory space |
WriteByte |
Writes a byte (byte) to an unmanaged memory space |
WriteInt16 |
Writes two bytes to an unmanaged memory space |
WriteInt32 |
Writes 4 bytes to an unmanaged memory space |
Copy to managed memory space |
Ptrtostringuni |
To create a managed string in an unmanaged memory space |
PtrToStructure |
Create an object in an unmanaged memory space |
ReadByte |
Reads a byte from an unmanaged memory space |
ReadInt16 |
Reads two bytes from an unmanaged memory space |
ReadInt32 |
Reads four bytes from an unmanaged memory space |
of information |
Iscomobject |
If it is hard-coded to return false |
SizeOf |
Queries the unmanaged size of an object entity. The field value used to set the structure size of some Win32 function calls. |
GetLastWin32Error |
Call the GetLastError function to retrieve the WIN32 error code |
Systemdefaultcharsize |
In the default character set, the character size of the read-only domain. In. NET Compact Framework is returned in 2. ) for portability. |
Some methods of the Marshal class allow you to overwrite unmanaged caches, so you can pass them as parameters to unmanaged functions. Other methods of this class allow you to read the value from the unmanaged cache and write it to the managed data object. Overwriting and reading from the cache is important because the Win32 API (along with many other C-based APIs) provides an extension that uses the cache for communication from one caller to a tuned function.
This table does not include many functions that are used to allocate unmanaged memory. The following memory allocation functions are described in the MSDN Library and built into the desktop. NET Framework, but they are not. NET Compact Framework is supported.
Üallochglobal
Üfreehglobal
Üalloccotaskmem
Üfreecotaskmem
Before you read or write from managed memory, you need to get some unmanaged memory space. Before delving into the memory copy method of the Marshal class, we need to take a look at one. NET Thin framework programmers how to handle memory allocations.
Allocating unmanaged memory space
What we call "unmanaged" memory is because the runtime's garbage collector does not manage memory. And you have to manage the memory you allocate, which means that when you no longer use it, you need to release the memory. Not releasing memory space can cause a memory leak. When the memory leaks to a certain extent, your program or the operating system itself may crash. You must be careful to release any memory that you have allocated. (For a summary of the WIN32 functions for allocating memory and related cleanup , see annex D.) )
You already have the responsibility to release your allocated memory, and then you need to train you to remember some guidelines to do the work correctly. When we write code that allocates memory, we always write code that frees the memory immediately after writing the code that allocates the memory. We then check to see if the memory allocated for each possible code path is freed, not just for success, but also for handling when an error condition exists. These efforts are to avoid memory leaks, which are the main problems of a WIN32 API (and yes . NET is such an important reason that managed code can do this automatically.
In order to be in . NET Compact Framework allocates unmanaged memory space, you have to call the WIN32 function that allocates memory. Some of the functions available for selection are listed below:
ü Private page Break : VirtualAlloc, VirtualFree
ü Shared Page break : Mapviewoffiles
ü Heap Splitter : heapcreate, HeapAlloc
ü Local Distributor : LocalAlloc, LocalFree
üCOM Allocator : CoTaskMemAlloc, CoTaskMemFree
Each memory type has a suitable use, and you can select a memory allocator by creating a corresponding P/invoke declaration. We use the last two types-local allocator and COM allocator-to implement the definitions in the Marshal class. But in . NET Compact Framework is not implemented in the four memory allocation functions. We choose these functions to assist in importing from the desktop . NET code to the device. Code Listing 4.8 contains the source code for the YaoDurant.Allocator.Marshal class, which implements four allocator functions. We leave it to you to include in your own function, or you can copy and paste the code into your project as you need it.
The code Listing 4.6 Marshal.cs Code provides two ways to allocate unmanaged memory
Using System;
Using System.Data;
Using System.Runtime.InteropServices;
Namespace Yaodurant.allocator
{
<summary>
Summary description for Class1.
</summary>
public class Marshal
{
Public Marshal ()
{
//
Todo:add constructor Logic here
//
}
//------------------------------------------------------------
Allocate/free COM Memory
//------------------------------------------------------------
[DllImport ("Ole32.dll")]
public static extern IntPtr CoTaskMemAlloc (int cb);
[DllImport ("Ole32.dll")]
public static extern void CoTaskMemFree (IntPtr PV);
public static INTPTR AllocCoTaskMem (int cb)
{
Return CoTaskMemAlloc (CB);
}
public static void FreeCoTaskMem (IntPtr ptr)
{
CoTaskMemFree (PTR);
}
//------------------------------------------------------------
Allocate/free Regular Heap Memory
//------------------------------------------------------------
[DllImport ("Coredll.dll")]
public static extern IntPtr
LocalAlloc (int fuflags, int cbbytes);
public const int lmem_fixed = 0x0000;
public const int lmem_zeroinit = 0x0040;
public static INTPTR AllocHGlobal (int cb)
{
Return LocalAlloc (lmem_fixed | Lmem_zeroinit, CB);
}
public static INTPTR AllocHGlobal (INTPTR CB)
{
Return AllocHGlobal (CB. ToInt32 ());
}
[DllImport ("Coredll.dll")]
public static extern IntPtr LocalFree (IntPtr hmem);
public static void FreeHGlobal (IntPtr hglobal)
{
LocalFree (HGLOBAL);
}
}//Class
}//Namespace
In code listing 4.6 There are two allocator functions: one for general heap memory (AllocHGlobal) and the other for the allocator function for COM shared components. In most cases, you can use a regular heap memory allocator. The COM allocator allows one component to allocate memory freed by some other component.
Longtime enthusiasts of the Win32 API may wonder why we call the LocalAlloc function to handle regular heap memory instead of using the GlobalAlloc function. These two functions are very different in the "Dinosaur " era (of course , when 16-bit Windows ruled the world), and the differences between the two sets of functions in the Win32 API have disappeared. Because of these redundancies, the global allocator is not supported in Windows CE, leaving only the local allocator as the only survivor of the "prehistoric" allocator.
Copy to unmanaged memory
Many parameters of an unmanaged function are simple value types that pass values. Some value types are referenced. In these two examples, the. NET Compact Framework built-in P/invoke support is sufficient. A quoted value type parameter allows us to get a pointer to unmanaged code, and the. NET Compact Framework knows how to create this implicit pointer: The NET Compact Framework can even handle many structs, as long as the struct contains only simple value types. These structures are sent as a pass-through parameter, which allows a pointer to be obtained and sent to unmanaged code in 15. In all of these built-in situations. NET streamlining framework to do all the work without using IntPtr and marshal.
When handling manual parameter passing, when the direction of the parameter is [in] or [in][out], before invoking the target function, you must initialize the unmanaged memory by copying the value into memory. In this section, we will discuss copying to unmanaged memory space.
To pass some data into the unmanaged memory space, you first allocate an unmanaged cache space and store the result pointer in a IntPtr. Next, call a member of the Marshal class to copy the data into the cache. Then pass a pointer to the unmanaged function. The last step is to release the allocated memory.
For demonstration purposes, let's redefine the MessageBox function to accept a inptr (instead of the string in the previous example) to illustrate. To simplify, we changed one of the two string arguments, caption:
message box with IntPtr caption
[DllImport ("Coredll.dll")]
public static extern int
MessageBox (int hWnd, String lptext, IntPtr lpcaption,
UInt32 Utype);
Note The IntPtr parameter is a value-passing parameter. Click the button response to invoke the code for this function in Listing 4.7.
Code Listing 4.7 calls the unmanaged MessageBox function
private void Button1_Click (object sender, System.EventArgs e)
{
Create a string
String strcaption = "Caption";
String strText = "Text";
Get the number of characters in a string
int CCH = Strcaption.length;
Create a character array from a string
char[] achcaption = new CHAR[CCH];
Strcaption.copyto (0, achcaption, 0, CCH);
Assigning an unmanaged cache
IntPtr ipcaption = AllocHGlobal ((cch+1) *
Marshal.systemdefaultcharsize);
if (! ipcaption.equals (IntPtr.Zero))
{
Copying characters to an unmanaged cache
Marshal.Copy (achcaption, 0, Ipcaption, CCH);
MessageBox (IntPtr.Zero, StrText, ipcaption, 0);
FreeHGlobal (ipcaption);
}
}
The code shows the four steps that you should always follow when you use IntPtr and marshal to send parameter data to an unmanaged function:
Allocates memory space. Memory allocations are implemented by calling the AllocHGlobal function, which we have previously written about the wrapper Win32 LocalAlloc the memory allocator function.
Copy data to memory space. We copy data to memory space by calling the Marshal.Copy method.
Pass a pointer as a function parameter, such as the third parameter of the MessageBox function in our example. Note that we need a p/invoke declaration with the different MessageBox functions we encountered earlier.
Frees up memory space. We do this by calling the FreeHGlobal function, which is the wrapper we wrote for the LocalFree function.
If the called function writes any value into the cache, we may need additional steps. The additional step is that after step three, before step four, it copies these values from the cache to managed memory.
Of course, we don't need to do this to pass a string to an unmanaged function. But the same method works equally well when dealing with manual parameter marshaling in any kind of array. After all, a string is an array of characters. Of course, in Windows CE This means an array of 2-byte Unicode characters.
Marshaling of String Classes
On the desktop. NET Framework, strings are automatically marshaled using similar techniques shown here-memory is allocated and strings are copied to memory space. In contrast, automatic string marshaling in the. NET Compact Framework does not involve additional memory space and duplication of effort, so it is faster and uses less memory. In the. NET Compact Framework, an unmanaged function obtains a pointer to the internal memory space of the managed string.
To create an object from unmanaged memory
The called function writes some data into the unmanaged memory space when you hand-pass the parameter in [In][out] or [out] direction. In order to retrieve this data, you create a managed object on an unmanaged memory space.
When a Win32 function is called to accept a pointer parameter, the caller allocates cache space of 16. This is a standard for each part of the Win32 API. When we taught the Windows Programming course, we noticed that programmers who had just contacted Win32 often tripped over the problem. But in practice, any programmer can become an expert in this style of function invocation.
When the return structure contains only simple value types, automatic P/invoke support can copy these values into a managed structure for you. When a struct contains an array, a string, a pointer, or any other reference type, you must manually create a managed object. The Findmemorycard example obtains the memory space returned from the unmanaged function call and shows how to assemble the managed code object using different static methods of the Marshal class.
Example: Findmemorycard
As we discussed in chapter 11th, the primary storage area for each Windows CE system is the object store, which contains a RAM-based file system, and other memory parts. This filesystem has many of the same elements as desktop Windows: Hierarchical structure consisting of directories and files, support for long filenames, and the same maximum path length (260 characters). Because object storage is on variable RAM, a battery-operable (battery-operated) smart device typically has an alternate power supply to prevent catastrophic data loss.
To supplement object storage, many Windows CE devices have immutable storage 17. For example, a Pocket pc typically has a slot available to a compact flash card, or a secure data card (also called a multimedia memory card). Many of the smartphone built on Windows Mobile technology have a secure data card slot. Additional storage devices that can be used with Windows CE devices include hard drives, floppy disk drives, and rewritable CD devices.
Unlike desktop windows, there may be a C: drive and a D: drive under Desktop windows, and Windows CE does not use letters to differentiate between different file systems. Instead, an installable file system is installed in a path at the root of the file system. For example, we typically encounter the/storage card as the root path of a compact flash card. You read and write the path and file on this storage device by including a root path in the path string, and you can pass the path string to various file access functions. So, to create a file named Data.dat under the root path of the previously named Thin Flash memory card, you will create a file called/storage Card/data.dat.
However, not all storage devices use this root/storage Card. In order to determine whether the "installed file system exists, and if so, what is the name of the root", you can call the following Win32 function:
Üfindfirstflashcard
Üfindnextflashcard
These functions need to fill in a struct called win32_find_data, by the way, the general purpose of the Win32 file system enumeration functions FindFirstFile and FindNextFile fill in the same structure. The data structure is defined as follows:
typedef struct _WIN32_FIND_DATA {
DWORD dwfileattributes;
FILETIME Ftcreationtime;
FILETIME Ftlastaccesstime;
FILETIME Ftlastwritetime;
DWORD Nfilesizehigh;
DWORD Nfilesizelow;
DWORD dwoid;
TCHAR Cfilename[max_path];
} win32_find_data;
The WIN32_FIND_DATA structure contains four elements that make it impossible to apply automatic parameter marshaling: Three FILETIME values and one character array. Our example has these two WIN32 functions that use unmanaged memory, and its invocation has been placed into the LocalAlloc function. The call then goes into a function that accesses an unmanaged block of memory and copies the value of the struct to provide a data structure equivalent to an unmanaged data structure, as shown below.
public struct WIN32_FIND_DATA
{
public int dwfileattributes;
Public FILETIME Ftcreationtime;
Public FILETIME Ftlastaccesstime;
Public FILETIME Ftlastwritetime;
public int Nfilesizehigh;
public int nfilesizelow;
public int dwoid;
Public String cFileName;
};
For each element in the struct, the conversion function reads a value and then the self-increment pointer prepares to read the next value. The conversion function is displayed in code listing 4.8, making the IntPtr type parameter PLN as a pointer to unmanaged memory. This function assumes that the output has been obtained and sends a managed object that has been instantiated with the type Win32_find_data. Because we like to reuse code, the function we write is for you to use it (FindFirstFile and FindNextFile) when you call a generic Win32 file system traversal function.
Code listing 4.8 Converting unmanaged data to a managed struct
private static void
Copyintptr_to_win32_find_data (IntPtr pIn,
Ref Win32_find_data PFFD)
{
Handy values for incrementing IntPtr pointer.
int i = 0;
int cbint = marshal.sizeof (i);
FILETIME ft = new FILETIME ();
int cbft = marshal.sizeof (ft);
int dwFileAttributes
Pffd.dwfileattributes = Marshal.readint32 (pIn);
Pin = (INTPTR) ((int) pin + cbint);
FILETIME Ftcreationtime;
Marshal.PtrToStructure (PIn, pffd.ftcreationtime);
Pin = (INTPTR) ((int) pin + CBFT);
FILETIME Ftlastaccesstime;
Marshal.PtrToStructure (PIn, pffd.ftlastaccesstime);
Pin = (INTPTR) ((int) pin + CBFT);
FILETIME Ftlastwritetime;
Marshal.PtrToStructure (PIn, pffd.ftlastwritetime);
Pin = (INTPTR) ((int) pin + CBFT);
int Nfilesizehigh;
Pffd.nfilesizehigh = Marshal.readint32 (pIn);
Pin = (INTPTR) ((int) pin + cbint);
int nfilesizelow;
Pffd.nfilesizelow = Marshal.readint32 (pIn);
Pin = (INTPTR) ((int) pin + cbint);
int dwoid;
Pffd.dwoid = Marshal.readint32 (pIn);
Pin = (INTPTR) ((int) pin + cbint);
String cFileName;
Pffd.cfilename = Marshal.ptrtostringuni (pIn);
}
Communicating between unmanaged code and managed code
P/invoke supports one-way function calls-from managed code to unmanaged code. This is with us . NET Framework to be able to find support that differs in the . NET Framework, the callback function is supported (see the section on "Compare P/invoke support" above for more details). In this section, we talk about some of the mechanisms available that you can use to communicate in another direction-from unmanaged code to managed code
A common method for client server communication--marshal class