C#——Marshal.StructureToPtr方法簡介
阿新 • • 發佈:2019-02-15
迎廣大朋友指正!
名稱空間:System.Runtime.InteropServices
程式集:mscorlib(在 mscorlib.dll 中)
C++: [ComVisibleAttribute(true)]public: static void StructureToPtr (Object^ structure, IntPtr ptr, bool fDeleteOld);3. 引數說明
structure:託管物件,包含要封送的資料。該物件必須是格式化類的例項。
ptr:指向非託管記憶體塊的指標,必須在呼叫此方法之前分配該指標。
fDeleteOld:設定為 true 可在執行Marshal.DestroyStructure方法前對 ptr 引數呼叫此方法。請注意,傳遞 false 可導致記憶體洩漏。
條件:structrue引數是泛型型別6. 舉例
定義PERSON結構,並將該結構的一個變數拷貝到非託管記憶體,再將該記憶體中的PERSON還原為PERSON物件,觀察其內容的變化。
原始碼如下:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace testStructureToPtr
{
publicstaticclass define //define some constant
{
publicconstint MAX_LENGTH_OF_IDENTICARDID =20; //maximum length of identicardid
publicconstint MAX_LENGTH_OF_NAME =50; //maximum length of name
publicconstint MAX_LENGTH_OF_COUNTRY =50; //maximum length of country
publicconstint MAX_LENGTH_OF_NATION =50; //maximum length of nation
publicconstint MAX_LENGTH_OF_BIRTHDAY =8; //maximum length of birthday
publicconstint MAX_LENGTH_OF_ADDRESS =200; //maximum length of address
}
publicstruct PERSON //person structure
{
//MarshalAs:指示如何在託管程式碼和非託管程式碼之間封送資料
//UnmanagedType:指定如何將引數或欄位封送到非託管記憶體塊
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)]
publicbyte[] identicardid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)]
publicbyte[] name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)]
publicbyte[] country;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)]
publicbyte[] nation;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)]
publicbyte[] birthday;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)]
publicbyte[] address;
}
class testProgram
{
privatestaticbyte _fillChar =0; //the fill character
//convert string to byte array in Ascii with length is len
publicstaticbyte[] CodeBytes(string str, int len)
{
if (string.IsNullOrEmpty(str))
{
str =string.Empty;
}
byte[] result =newbyte[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
publicstaticvoid 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));
}
staticvoid 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
}
}
}
} 執行過程中的物件地址及其內容如下: intPtr指向的記憶體塊的內容就是程式中對person物件所賦的初值,如下圖所示,共計378個位元組: 物件person和another的地址及其identicardid成員的地址: 物件person的identicardid成員的內容,即程式中的值123456198001011111,最後的2個位元組為0,圖中顯示的是20個元素的ASCII碼的16進位制數值: 執行結果如下:
Marshal.StructureToPtr方法簡介
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
{
publicstaticclass define //define some constant
{
publicconstint MAX_LENGTH_OF_IDENTICARDID =20;
publicconstint MAX_LENGTH_OF_NAME =50; //maximum length of name
publicconstint MAX_LENGTH_OF_COUNTRY =50; //maximum length of country
publicconstint MAX_LENGTH_OF_NATION =50; //maximum length of nation
publicconstint MAX_LENGTH_OF_BIRTHDAY =8; //maximum length of birthday
publicconstint MAX_LENGTH_OF_ADDRESS =200; //maximum length of address
}
publicstruct PERSON //person structure
{
//MarshalAs:指示如何在託管程式碼和非託管程式碼之間封送資料
//UnmanagedType:指定如何將引數或欄位封送到非託管記憶體塊
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)]
publicbyte[] identicardid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)]
publicbyte[] name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)]
publicbyte[] country;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)]
publicbyte[] nation;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)]
publicbyte[] birthday;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)]
publicbyte[] address;
}
class testProgram
{
privatestaticbyte _fillChar =0; //the fill character
//convert string to byte array in Ascii with length is len
publicstaticbyte[] CodeBytes(string str, int len)
{
if (string.IsNullOrEmpty(str))
{
str =string.Empty;
}
byte[] result =newbyte[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
publicstaticvoid 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));
}
staticvoid 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
}
}
}
} 執行過程中的物件地址及其內容如下: intPtr指向的記憶體塊的內容就是程式中對person物件所賦的初值,如下圖所示,共計378個位元組: 物件person和another的地址及其identicardid成員的地址: 物件person的identicardid成員的內容,即程式中的值123456198001011111,最後的2個位元組為0,圖中顯示的是20個元素的ASCII碼的16進位制數值: 執行結果如下: