1. 功能及位置 將數據從託管對象封送到非託管內存塊,屬於.NET Framework 類庫 命名空間:System.Runtime.InteropServices 程序集:mscorlib(在 mscorlib.dll 中) 2. 語法 C#: [ComVisibleAttribute(true)] public static void StructureToPtr (Object structure,IntPtr ptr,bool fDeleteOld); C++: [ComVisibleAttribute(true)]public: static void StructureToPtr (Object^ structure, IntPtr ptr, bool fDeleteOld); 3. 參數說明 structure:託管對象,包含要封送的數據。該對象必須是格式化類的實例。 ptr:指向非託管內存塊的指針,必須在調用此方法以前分配該指針。 fDeleteOld:設置爲 true 可在執行Marshal.DestroyStructure方法前對 ptr 參數調用此方法。請注意,傳遞 false 可致使內存泄漏。 4. 異常 異常類型:ArgumentException 條件:structrue參數是泛型類型 5. 備註 StructureToPtr將結構的內容複製到 ptr 參數指向的預分配內存塊。若是 fDeleteOld 參數爲 true,則使用嵌入指 針上適當的刪除 API 來刪除最初由 ptr 指向的緩衝區,但該緩衝區必須包含有效數據。此方法爲在鏡像託管類中指 定的每一個引用字段執行清理工做。 假設 ptr 指向非託管內存塊。此內存塊的佈局由相應的託管類 structure 描述。StructureToPtr將字段值從結構封 送到指針。假設 ptr 塊包含引用字段,該字段指向當前包含「abc」的字符串緩衝區。假設託管端上相應的字段是包含「vwxyz」的字符串。若是不另行通知它,StructureToPtr將分配一個新的非託管緩衝區來保存「vwxyz」,並將它掛鉤到 ptr 塊。這將丟棄舊緩衝區「abc」使之漂移而不將其釋放回非託管堆。最後,您將獲得一個孤立的緩衝區,它表示在代碼中存在內存泄漏。若是將 fDeleteOld 參數設置爲真,則 StructureToPtr 在繼續爲「vwxyz」分配新緩衝區以前釋放保存「abc」的緩衝區。 6. 舉例 定義PERSON結構,並將該結構的一個變量拷貝到非託管內存,再將該內存中的PERSON還原爲PERSON對象,觀察其內容的變化。 源代碼以下: using System; using System.Text; using System.Runtime.InteropServices; namespace testStructureToPtr { public static class define //define some constant { public const int MAX_LENGTH_OF_IDENTICARDID = 20; //maximum length of identicardid public const int MAX_LENGTH_OF_NAME = 50; //maximum length of name public const int MAX_LENGTH_OF_COUNTRY = 50; //maximum length of country public const int MAX_LENGTH_OF_NATION = 50; //maximum length of nation public const int MAX_LENGTH_OF_BIRTHDAY = 8; //maximum length of birthday public const int MAX_LENGTH_OF_ADDRESS = 200; //maximum length of address } public struct PERSON //person structure { //MarshalAs:指示如何在託管代碼和非託管代碼之間封送數據 //UnmanagedType:指定如何將參數或字段封送到非託管內存塊 [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)] public byte[] identicardid; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)] public byte[] name; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)] public byte[] country; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)] public byte[] nation; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)] public byte[] birthday; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)] public byte[] address; } class testProgram { private static byte _fillChar = 0; //the fill character //convert string to byte array in Ascii with length is len public static byte[] CodeBytes(string str, int len) { if (string.IsNullOrEmpty(str)) { str = string.Empty; } byte[] result = new byte[len]; byte[] strBytes = Encoding.Default.GetBytes(str); //copy the array converted into result, and fill the remaining bytes with 0 for (int i = 0; i < len; i++) result[i] = ((i < strBytes.Length) ? strBytes[i] : _fillChar); return result; } //show the person information public static void ShowPerson(PERSON person) { Console.WriteLine("cardid :" + Encoding.ASCII.GetString(person.identicardid)); Console.WriteLine("name :" + Encoding.ASCII.GetString(person.name)); Console.WriteLine("country :" + Encoding.ASCII.GetString(person.country)); Console.WriteLine("nation :" + Encoding.ASCII.GetString(person.nation)); Console.WriteLine("birthday :" + Encoding.ASCII.GetString(person.birthday)); Console.WriteLine("address :" + Encoding.ASCII.GetString(person.address)); } static void Main(string[] args) { PERSON person; person.identicardid = CodeBytes("123456198001011111", define.MAX_LENGTH_OF_IDENTICARDID); person.name = CodeBytes("jackson", define.MAX_LENGTH_OF_NAME); person.country = CodeBytes("China", define.MAX_LENGTH_OF_COUNTRY); person.nation = CodeBytes("HanZu", define.MAX_LENGTH_OF_NATION); person.birthday = CodeBytes("19800101", define.MAX_LENGTH_OF_BIRTHDAY); person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS); int nSizeOfPerson = Marshal.SizeOf(person); IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfPerson); Console.WriteLine("The person infomation is as follows:"); ShowPerson(person); try { //將數據從託管對象封送到非託管內存塊,該內存塊開始地址爲intPtr Marshal.StructureToPtr(person, intPtr, true); //將數據從非託管內存塊封送到新分配的指定類型的託管對象anotherPerson PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON)); Console.WriteLine("The person after copied is as follows:"); ShowPerson(anotherPerson); } catch (ArgumentException) { throw; } finally { Marshal.FreeHGlobal(intPtr); //free tha memory } } } } 7. 分析及擴展 結構體: public struct PERSON //person structure { //MarshalAs:指示如何在託管代碼和非託管代碼之間封送數據 //UnmanagedType:指定如何將參數或字段封送到非託管內存塊 [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)] public byte[] identicardid; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)] public byte[] name; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)] public byte[] country; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)] public byte[] nation; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)] public byte[] birthday; [MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)] public byte[] address; } A. 經過獲取Person信息的函數返回的指針,再將該指針轉換爲結構體,並顯示結構體中的內容 a. 獲取Person信息的函數 //獲取 Person信息 [DllImport("person.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr GetPerson(IntPtr pEngine); b. 使用指針定義一個變量,來獲取一個返回值爲該指針的函數 IntPtr Person = GetPerson(pEngine); c. 將指針變量裝換爲結構體,操做以下: PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON)); d. 經過ShowPerson(PERSON person)函數,用來打印輸出信息 Console.WriteLine("cardid :" + Encoding.ASCII.GetString(anotherPerson.identicardid)); B. 經過定義結構體,並賦值結構體中的數據,再將結構體轉爲指針數據,並將指針傳入到SetPerson信息的函數中 a. 設置Person信息的函數 //獲取 Person信息 [DllImport("person.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int SetPerson(IntPtr pEngine); b. 定義結構體,並賦值結構體中的數據 PERSON person = new PERSON(); person.identicardid = CodeBytes("123456198001011111", define.MAX_LENGTH_OF_IDENTICARDID); person.name = CodeBytes("jackson", define.MAX_LENGTH_OF_NAME); person.country = CodeBytes("China", define.MAX_LENGTH_OF_COUNTRY); person.nation = CodeBytes("HanZu", define.MAX_LENGTH_OF_NATION); person.birthday = CodeBytes("19800101", define.MAX_LENGTH_OF_BIRTHDAY); person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS); c. 將結構體轉爲指針數據 int nSizeOfPerson = Marshal.SizeOf(person); //定義指針長度 IntPtr personX = Marshal.AllocHGlobal(nSizeOfPerson); //定義指針 Marshal.StructureToPtr(person, personX, true); //將結構體person轉爲personX指針 d. 將指針傳入到SetPerson函數中 SetPerson(personX);