Marshal類
提供了一個方法集,這些方法用於分配非托管內存、復制非托管內存塊、將托管類型轉換為非托管類型,此外還提供了在與非托管代碼交互時使用的其他雜項方法。
命名空間:System.Runtime.InteropServices
Marshal 類中定義的 static 方法對於處理非托管代碼至關重要。此類中定義的大多數方法通常由需要在托管和非托管編程模型之間提供橋梁的開發人員使用。
例如,StringToHGlobalAnsi 方法將 ANSI 字符從指定的字符串(在托管堆中)復制到非托管堆中的緩沖區。該方法還分配大小正確的目標堆。
公共方法
方法名稱 |
說明 |
遞增指定接口上的引用計數。 |
|
從 COM 任務內存分配器分配指定大小的內存塊。 |
|
使用 LocalAlloc 分配內存塊。 |
|
獲取由指定的名字對象標識的接口指針。 |
|
在 COM 可調用包裝 (CCW) 句柄包含的對象上更改它的強度。 |
|
將數據從托管數組復制到非托管內存指針,或從非托管內存指針復制到托管數組。 |
|
聚合托管對象和指定的 COM 對象。 |
|
在指定類型的對象中包裝指定的 COM 對象。 |
|
釋放指定的非托管內存塊所指向的所有子結構。 |
|
通過將提供的運行庫可調用包裝 (RCW) 的引用計數設置為 0,釋放對 RCW 的所有引用。 |
|
使用 SysFreeString 釋放 BSTR。 |
|
釋放由非托管 COM 任務內存分配器使用 Marshal.AllocCoTaskMem 分配的內存塊。 |
|
釋放以前使用 AllocHGlobal 從進程的非托管內存中分配的內存。 |
|
返回指定類型的全局唯一標識符 (GUID),或使用類型庫導出程序 (TlbExp.exe) 所用的算法生成 GUID。 |
|
返回指定類型的編程標識符 (ProgID)。 |
|
從運行對象表 (ROT) 獲取指定對象的運行實例。 |
|
返回一個接口指針,該接口指針表示對象的指定接口。 |
|
返回一個接口指針,該指針表示對象的指定接口(如果調用方與對象在同一上下文中)。 |
|
從指定的 COM 對象獲取指定鍵所引用的數據。 |
|
獲取指定的 System.Reflection.MemberInfo 在向 COM 公開時的虛函數表 (VTBL) 槽。 |
|
將非托管函數指針轉換為委托。 |
|
獲取在向 COM 公開時某個類型的虛函數表 (VTBL) 中的最后一個槽。 |
|
檢索標識所發生異常的類型的代碼。 |
|
。 將 HRESULT 錯誤代碼轉換為對應的 Exception 對象。 |
|
檢索與計算機無關的異常描述以及有關異常發生時線程的狀態信息。 |
|
將委托轉換為可從非托管代碼調用的函數指針。 |
|
用作特定類型的哈希函數。GetHashCode 適合在哈希算法和數據結構(如哈希表)中使用。 (從 Object 繼承。) |
|
返回指定模塊的實例句柄 (HINSTANCE)。 |
|
將指定異常轉換為 HRESULT。 |
|
返回 HRESULT,它與使用 Marshal 執行的 Win32 代碼引起的最后一個錯誤相對應。 |
|
從托管對象返回一個 IDispatch 接口。 |
|
如果調用方與托管對象在同一上下文中,則從該對象返回一個 IDispatch 接口指針。 |
|
從托管類型返回一個 ITypeInfo 接口。 |
|
從托管對象返回一個 IUnknown 接口。 |
|
如果調用方與托管對象在同一上下文中,則從該對象返回一個 IUnknown 接口。 |
|
返回由上一個非托管函數返回的錯誤代碼,該函數是使用設置了 DllImportAttribute.SetLastError 標志的平台調用來調用的。 |
|
獲取指向 thunk 的指針,該 thunk 封送從托管代碼到非托管代碼的調用。 |
|
檢索指定的虛函數表 (VTBL) 槽的 MethodInfo。 |
|
將對象轉換為 COM VARIANT。 |
|
返回通過指向 COM 對象的 IUnknown 接口的指針表示該對象的類型實例。 |
|
將 COM VARIANT 轉換為對象。 |
|
將 COM VARIANT 數組轉換為對象數組。 |
|
獲取虛函數表 (VTBL) 中第一個包含用戶定義的方法的槽。 |
|
將纖程 Cookie 轉換為相應的 System.Threading.Thread 實例。 |
|
返回表示 COM 對象的指定類型的托管對象。 |
|
將 ITypeInfo 轉換為托管 Type 對象。 |
|
。 檢索由 ITypeInfo 表示的類型的名稱。 |
|
。 檢索類型庫的庫標識符 (LIBID)。 |
|
檢索從指定程序集導出類型庫時分配給該類型庫的庫標識符 (LIBID)。 |
|
。 檢索類型庫的 LCID。 |
|
。 檢索類型庫的名稱。 |
|
檢索將從指定程序集導出的類型庫的版本號。 |
|
為給定的 IUnknown 創建唯一的運行庫可調用包裝 (RCW) 對象。 |
|
獲取指向 thunk 的指針,該 thunk 封送從非托管代碼到托管代碼的調用。 |
|
指示指定對象是否表示 COM 對象。 |
|
指示類型對 COM 客戶端是否可見。 |
|
計算在非托管內存中保存指定方法的參數所需要的字節數。 |
|
返回托管類的非托管形式的字段偏移量。 |
|
在不調用方法的情況下執行一次性方法設置任務。 |
|
對類上的所有方法執行預鏈接檢查。 |
|
分配托管 String 並向其復制所有或部分非托管 ANSI 字符串。 |
|
分配托管 String,並從非托管字符串向其復制指定數目的字符。 |
|
分配托管 String,並向其復制存儲在非托管內存中的 BSTR 字符串。 |
|
分配托管 String,並從非托管 Unicode 字符串向其復制指定數目的字符。 |
|
將數據從非托管內存塊封送到托管對象。 |
|
從 COM 對象請求指向指定接口的指針。 |
|
從非托管指針讀取單個字節。 |
|
從非托管內存中讀取一個 16 位有符號整數。 |
|
從非托管內存中讀取一個 32 位有符號整數。 |
|
從非托管內存中讀取一個 64 位有符號整數。 |
|
從非托管內存中讀取處理器本機大小的整數。 |
|
調整以前用 AllocCoTaskMem 分配的內存塊的大小。 |
|
調整以前用 AllocHGlobal 分配的內存塊的大小。 |
|
確定指定的 Object 實例是否是相同的實例。 (從 Object 繼承。) |
|
遞減指定接口上的引用計數。 |
|
遞減所提供的運行庫可調用包裝的引用計數。 |
|
釋放線程緩存。 |
|
分配 BSTR 並向其復制托管 SecureString 對象的內容。 |
|
將托管 SecureString 對象的內容復制到從非托管 COM 任務分配器分配的內存塊。 |
|
將托管 SecureString 對象的內容復制到從非托管 COM 任務分配器分配的內存塊。 |
|
將托管 SecureString 中的內容復制到非托管內存,並在復制時轉換為 ANSI 格式。 |
|
向非托管內存復制托管 SecureString 的內容。 |
|
設置由指定 COM 對象中的指定鍵引用的數據。 |
|
使用 Marshal 返回類的非托管大小(以字節為單位)。 |
|
分配 BSTR 並向其復制托管 String 的內容。 |
|
將托管 String 的內容復制到從非托管 COM 任務分配器分配的內存塊。 |
|
將托管 String 的內容復制到從非托管 COM 任務分配器分配的內存塊。 |
|
將托管 String 的內容復制到從非托管 COM 任務分配器分配的內存塊。 |
|
將托管 String 中的內容復制到非托管內存,並在復制時轉換為 ANSI 格式。 |
|
向非托管內存復制托管 String 的內容,並在需要時轉換為 ANSI 格式。 |
|
向非托管內存復制托管 String 的內容。 |
|
將數據從托管對象封送到非托管內存塊。 |
|
用特定的失敗 HRESULT 值引發異常。 |
|
返回表示當前 Object 的 String。 (從 Object 繼承。) |
|
獲取指定數組中指定索引處的元素的地址。 |
|
將單個字節值寫入到非托管內存。 |
|
將 16 位有符號整數寫入非托管內存。 |
|
將 32 位有符號整數寫入非托管內存。 |
|
將 64 位有符號整數寫入非托管內存。 |
|
將一個處理器本機大小的整數值寫入非托管內存。 |
|
釋放 BSTR 指針,該指針是使用 SecureStringToBSTR 方法分配的。 |
|
釋放非托管字符串指針,該指針是使用 SecureStringToCoTaskMemAnsi 方法分配的。 |
|
釋放非托管字符串指針,該指針是使用 SecureStringToCoTaskMemUnicode 方法分配的。 |
|
釋放非托管字符串指針,該指針是使用 SecureStringToGlobalAllocAnsi 方法分配的。 |
|
釋放非托管字符串指針,該指針是使用 SecureStringToCoTaskMemUnicode 方法分配的。 |
簡介
Marshal 類中有許多成員,但他們大多是公用事業援助COM代碼進行互操作。
使用.NET,Visual Basic中有很大的權力,以至於處理在與 Windows 系統較低水平層次,並從外部庫的非托管代碼的工作。這權力是發現了三個新的工具:IntPtr的,NET的平台相關的內存地址代表性的GCHandle,從而你針和檢索的管理內存堆的數據的地址; Marshal類的一站式。您的內存分配,清理,和操作的需要。
如果您決定與VB.NET直接內存操作,你需要了解的第一件事是IntPtr類型。
IntPtr 的是一個結構,它表示兩個地址和處理(大多數處理 Windows 的指針的指針)。
IntPtr 的實例也依賴於平台的(或獨立,取決於你的觀點)。在32位系統,IntPtr 的是32位,而在64位系統 IntPtr 的是64位。這樣做的好處是,你不需要更改或重新編譯你的代碼,或兩個平台內的任何.NET Framework的公開的方式與地址和處理工作的功能。
使用 IntPtr 類型,這種功能是封送到非托管代碼,僅僅作為內部地址編號,這意味着你可以通過一個 IntPtr 類型的變量的任何非托管代碼的預計指針。因此,好消息是,雖然你不能在VB.NET中使用這樣的: 如void * Dim MyPointer 這個工程精辟VB.NET:作為 IntPtr 的 DIM MyPointer
請注意,在Beta 1沒有IntPtr類型??相反,工作指針和處理使用 Integer 類型。
IntPtr 類型有 ToInt32 方法的地址轉換為一個整數,但可以將導致在64位系統的溢出異常。 IntPtr 也有 ToInt64 方法,但你必須保持跟蹤的平台,如果你想要做的這些轉換。StrPtr()和 VarPtr()NBSP在 VB.NET 這兩個無證 VB 的6個功能變量的返回地址。相同的功能,可以在VB.NET的GCHandle類。
讓我們來看看如何放到一個 IntPtr 變量的地址。您可以使用的 GCHandle 的類,它有一個 AddrOfPinnedObject 的方法返回一個變量一個IntPtr。
您必須"針"的數據,然后才可以得到這個地址。這可以防止不經意間移動數據的垃圾收集器,而你指的是原來的地址。這代碼引腳一個變量,其地址顯示在控制台窗口,並釋放句柄:"昏暗的管理變量DIM MyString的字符串=阿德南塞繆爾? "針變量和創建"GC的處理實例昏暗的GH(MyString中,GCHandleType.Pinned)的GCHandle = GCHandle.Alloc "得到的變量的地址DIM AddrOfMyString作為IntPtr的= gh.AddrOfPinnedObject() Console.WriteLine(AddrOfMyString.ToString()) "自由的處理,並脫離"變量gh.Free()說明AllocHGlobal和AllocCoTaskMem
上的本機堆內部使用GlobalAlloc函數分配內存AllocHGlobal; AllocCoTaskMem,這是類似的,而是使用的COM內存管理器(CoTaskMemAlloc來)。這兩個函數有一個參數,分配的字節數。這兩個函數返回一個IntPtr,新分配的緩沖區的基地址。釋放內存,您使用的FreeHGlobal或FreeCoTaskMem方法,取決於分配方法您使用。這些函數有一個參數,新分配的緩沖區的分配函數返回地址。
使用WriteByte,WriteInt16,WriteInt32,或WriteInt64方法簡單的數字數據寫入到一個非托管的緩沖區。每個函數作為參數的寫操作的目的地址和數值你想要寫。這些功能也重載以允許可選的第三個參數指示從抵消所提供的地址,它可以是有用的,如果你試圖填充數組元素或結構領域的內存,例如:"分配一些內存,並獲得它的地址DIM MyPointer的IntPtr = Marshal.AllocHGlobal(4) "寫入到該地址的數量255Marshal.WriteInt32(MyPointer,255) "一些更多的代碼(調用"例如的非托管代碼) "空閑內存Marshal.FreeHGlobal(MyPointer)
您也可以使用提供的地址,而不是你自己分配的非托管代碼:DIM MyPointer作為IntPtr的新的IntPtr([插入整數地址_ 從這里非托管代碼)] Marshal.WriteInt32(MyPointer,255)
反過來也有可能。你可以閱讀簡單的數字數據,從一個IntPtr地址使用的readByte ReadInt16,ReadInt32,並ReadInt64方法:DIM MyInteger為整數= Marshal.ReadInt32(MyPointer)字符串函數
閱讀和寫作字符串相似,讀,寫簡單的數字數據,有一個小的例外:你不先分配內存,然后寫一個字符串。相反,在非托管內存中創建一個字符串的行為分配的空間,並返回字符串的地址。寫有七個方法:StringToBSTR,StringToCoTaskMemAnsi,StringToCoTaskMemUni,StringToCoTaskMemAuto,StringToHGlobalAnsi,StringToHGlobalUni和StringToHGlobalAuto。 StringToCoTaskMemxxx功能字符串數據寫入到COM分配的內存,而StringToHGlobalxxx功能寫入到本地的非托管堆。結束在ANSI的函數寫單字節ANSI字符串。結束在統一的函數寫雙字節的Unicode字符串。功能,自動結束寫入ANSI或Unicode字符串,這取決於操作系統:Windows 98和ME,NT為基礎的平台(Windows NT 4.0中,2000年,和XP)的Unicode字符串的ANSI字符串。 StringToBSTR寫一個自動化BSTR,這是類似於使用SysAllocString函數。這些函數接受一個字符串作為輸入參數,並返回一個指針,得到的字符串:DIM MyStrPointer的IntPtr = Marshal.StringToHGlobalAuto(quot;您好Worldquot;)
四個讀的方法呢??PtrToStringAnsi,PtrToStringUni,PtrToStringAuto,PtrToStringBSTR??在一個給定的地址讀取數據,並創建一個托管String對象,其中包含的字符的副本。 PtrToStringAnsi如果非托管字符串是ANSI,PtrToStringUni如果非托管字符串是Unicode,或PtrToStringBSTR如果非托管字符串是BSTR類型。 PtrToStringAuto假定非托管字符串是一個Windows 98或ME系統的ANSI和Unicode的Windows NT 4.0,2000或XP平台上。 PtrToStringAuto實際上是調用PtrToStringAnsi或PtrToStringUni,取決於操作系統。每個函數重載接受一個可選的數字復制的字符。如果你沒有提供的字符數,函數看起來為終止空字符:"復制整個字符串昏暗的MyString的字符串= Marshal.PtrToStringAuto(MyPointer)"復制前5個字符DIM MyString的字符串= Marshal.PtrToStringAuto(MyPointer,5)
拿着一個字符串要釋放非托管內存緩沖區,可以調用FreeHGlobal或FreeCoTaskMem成員。要免費StringToBSTR創建一個BSTR,你叫FreeBSTR,這反過來又調用FreeSysString功能。 - ; StructureToPtr和PtrToStructure
你寫的非托管內存結構(用戶定義類型)使用的StructureToPtr方法。這種方法需要你有時間提前分配的內存緩沖區。它有三個參數:您要編寫的結構,內存緩沖區的地址(IntPtr的),和一個刪除標志。刪除標志設置為True濕巾和釋放任何現有的數據從緩沖區。這是非常重要的,因為你可能會導致內存泄漏不刪除現有的緩沖空間。例如,如果結構的領域之一,是另一種結構或字符串的引用,數據被外地引用不會被釋放,如果該參數設置為False。還要注意的是結構復制到非托管內存,使用特定的格式(你可以控制可選),和非托管的副本可能不像完全的托管表示。使用sizeof的方法來確定緩沖區所需的字節數:DIM MYVARIABLE為點MyVariable.X = 100MyVariable.Y = 250DIM MyPointer作為IntPtr的Marshal.AllocHGlobal(Marshal.SizeOf(MYVARIABLE))Marshal.StructureToPtr(MYVARIABLE,MyPointer,假)
使用PtrToStructure方法扭轉的過程和讀從非托管內存結構。您可以使用此方法可以作為一個函數返回一個結構的副本類型的基礎上,或填補了結構參數作為一個子。請注意,PtrToStructure返回一個Object類型的引用,和Option Strict On時,您必須轉換為結構類型(例如,所使用的CType):作為點DIM MyPointMyPoint = CTYPE(Marshal.PtrToStructure(MyPointer的GetType(點)),點)復制方法
讀取和寫入陣列中的數據,尤其是寶貴的,當你需要二進制數據流。 Copy方法讀取和寫入,根據您傳遞給它的參數。如果你想寫入數據,你需要先分配一些緩沖區空間,就像你會使用字符串。接下來,您呼叫的復制方法,並通過數組本身,目的地址(IntPtr的分配),你要開始復制的元素的數組的索引,和緩沖區的大小:DIM MyData的(255)作為字節"在這里插入代碼,以填補字節數組DIM BufferAddress的IntPtr = Marshal.AllocHGlobal(256)Marshal.Copy(MYDATA,0,BufferAddress,256)
要閱讀從非托管內存中的數組,調用復制的方法,並通過緩沖區的地址(IntPtr的),你想從緩沖區中的數據填充數組,數組的索引,你要開始復制到了,你要復制的數據的大小:MyData的DIM(255)以字節 Marshal.Copy(BufferAddress,MYDATA,0,256)
Marshal類中有更多的方法,但他們大多是公用事業援助COM代碼進行互操作。結論
這些功能也相當有助於封送處理以及asnbsp管理的數據; CopyMemory如非托管的內存也被稱為RtlMoveMomry功能的一個很好的替代。
我總是樂於幫助,因此,如果您有任何疑問,或對我的文章建議,感到自由。您還可以在MSN Messenger上達到我的屏幕名稱千里馬嗎??