天天看點

關于Marshal 類的整理

在兩個不同的實體(兩個線程或者程序甚至機器、在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;//需要那幾個圖層。 

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); 

//使用這個方法将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; 

}

繼續閱讀