原文轉載於:https://www.cnblogs.com/DragonX/p/3474251.html
在兩個不同的實體(兩個線程或者進程甚至機器、在Managed和Unmanaged之間)進行方法調用和參數傳遞的時候,具體的調用方法和參數的內存格式可能需要一定的轉換,這個轉換的過程叫做Marshal。
Marshal就是把一個結構(類)序列化成一段內存,然後送到另一個進程(.net中Application domain)中供另一個進程中的函數使用。
比如你的一個結構
struct{
Pen pen;
}s; s是一個指向已有的Pen對象的引用,當你把s傳給本進程中的一個函數f時,f可以很容易地找到pen的實際對象,但如果你把s傳到另外一個進程時,甚至是另外一臺機器上的進程時,這個進程就沒辦法找到pen的實際內容。Marshal技術則可以把pen對象中的所有實際內容按規則放到一個緩衝中,(所有的引用或指針都要轉換成實際對象)然後把緩衝中的內容送到另一個進程,函數調用完成再用同樣方式把結果返回來。
在RPC,Interop,COM中Marshal應用很多。
Marshal 類提供了一個方法集,這些方法用於分配非託管內存、複製非託管內存塊、將託管類型轉換爲非託管類型,此外還提供了在與非託管代碼交互時使用的其他雜項方法。
類別 | 成員 |
---|---|
高級封送處理 |
GetManagedThunkForUnmanagedMethodPtr、GetUnmanagedThunkForManagedMethodPtr、NumParamBytes |
COM 庫函數 |
BindToMoniker、GetActiveObject |
COM 實用工具 |
ChangeWrapperHandleStrength、CreateWrapperOfType、GetComObjectData、GetComSlotForMethodInfo、GetEndComSlot、 GetMethodInfoForComSlot、GetStartComSlot、ReleaseComObject、SetComObjectData |
數據轉換 |
託管到非託管:Copy、GetComInterfaceForObject、GetIDispatchForObject、GetIUnknownForObject、StringToBSTR、StringToCoTaskMemAnsi、 StringToCoTaskMemAuto、StringToCoTaskMemUni、StringToHGlobalAnsi、StringToHGlobalAuto、StringToHGlobalUni、StructureToPtr、 UnsafeAddrOfPinnedArrayElement 非託管到託管:Copy、GetObjectForIUnknown、GetObjectForNativeVariant、GetObjectsForNativeVariants、GetTypedObjectForIUnknown、 GetTypeForITypeInfo、PtrToStringAnsi、PtrToStringAuto、PtrToStringBSTR、PtrToStringUni 屬性:SystemDefaultCharSize、SystemMaxDBCSCharSize |
直接讀取和寫入 | ReadByte、ReadInt16、ReadInt32、ReadInt64、ReadIntPtr、WriteByte、WriteInt16、WriteInt32、WriteInt64、WriteIntPtr
|
錯誤處理 | COM:GetHRForException、ThrowExceptionForHR
Win32:GetLastWin32Error、GetExceptionCode、GetExceptionPointers 兩者:GetHRForLastWin32Error |
承載實用工具 | GetThreadFromFiberCookie
|
IUnknown | AddRef、QueryInterface、Release
|
內存管理 | COM:AllocCoTaskMem、ReAllocCoTaskMem、FreeCoTaskMem、FreeBSTR
Win32:AllocHGlobal、ReAllocHGlobal、FreeHGlobal 兩者:DestroyStructure |
平臺調用實用工具 | Prelink、PrelinkAll、GetHINSTANCE
|
結構檢查 | OffsetOf、SizeOf
|
類型信息 |
GenerateGuidForType、GenerateProgIdForType、GetTypeInfoName、GetTypeLibGuid、GetTypeLibGuidForAssembly、GetTypeLibLcid、 GetTypeLibName、IsComObject、IsTypeVisibleFromCom |
特別注意:Marshal.PtrToStringAuto方法:分配託管 String,並從非託管內存中存儲的字符串向其複製第一個空字符之前的所有字符。
例1、
public struct ImageDataMsg
{
public char DataType;
public int Srv_index;
public char ConvertType;
//這個個地方要指定長度,這樣就可以得到結構體的正確長度了
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] VecLayer;//需要那幾個圖層。
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] GridLayer;//需要那幾個柵格圖層
public int Scale_index;//需要的是那個比例尺的圖像
public int x_pos;
public int y_pos;
public int ClientArea_x;
public int ClientArea_y;
}
//使用這個方法將你的結構體轉化爲bytes數組
public static byte[] Struct2Bytes(ImageDataMsg obj)
{
int size = Marshal.SizeOf(obj);
byte[] bytes = new byte[size];
try
{
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, false);
Marshal.Copy(ptr, bytes, 0, size);
Marshal.FreeHGlobal(ptr);
return bytes;
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
return bytes;
}
}
//使用這個方法將byte數組轉化爲結構體
public static object BytesToStuct2(byte[] bytes, ImageDataMsg type)
{
//得到結構體的大小
int size = Marshal.SizeOf(type);
//byte數組長度小於結構體的大小
if (size > bytes.Length)
{
//返回空
return null;
}
//分配結構體大小的內存空間
IntPtr structPtr = Marshal.AllocHGlobal(size);
//將byte數組拷到分配好的內存空間
Marshal.Copy(bytes, 0, structPtr, size);
//將內存空間轉換爲目標結構體
object obj = Marshal.PtrToStructure(structPtr, typeof(ImageDataMsg));
//釋放內存空間
Marshal.FreeHGlobal(structPtr);
//返回結構體
return obj;
}