C#使用StructLayout特性來控制內(nèi)存結(jié)構(gòu)的操作代碼
C#在調(diào)用WInAPI函數(shù)時(shí),可能會(huì)看到如下的聲明
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
在類或者結(jié)構(gòu)體前面帶上了
[StructLayout(LayoutKind.Sequential)]
StructLayoutAttribute特性的作用是允許你控制內(nèi)存中類或結(jié)構(gòu)的數(shù)據(jù)字段的物理布局。
平常我們?cè)贑#代碼中使用類或者結(jié)構(gòu)體時(shí),不需要使用此特性。但在與非托管代碼時(shí)交互,需要使用StructLayoutAttribute特性來控制類型的非托管布局。
StructLayoutAttribute常用構(gòu)造函數(shù)是:
StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind)
System.Runtime.InteropServices.LayoutKind是一個(gè)枚舉類型,有三個(gè)取值。
LayoutKind.Sequential
強(qiáng)制按成員的顯示順序?qū)ζ溥M(jìn)行排列。對(duì)于blittable類型,在托管和非托管內(nèi)存中控制布局。對(duì)于non-blittable類型,它會(huì)在將類或者結(jié)構(gòu)體封送到非托管代碼時(shí)控制布局(換言之,如果僅在C#中進(jìn)行調(diào)用,不會(huì)做任何操作,在與非托管代碼交互時(shí),僅控制送入非托管代碼的布局)
LayoutKind.Explicit
控制每個(gè)數(shù)據(jù)成員的精確位置,這會(huì)影響托管和非托管代碼中的布局,不管是blittable類型還是non-blittable類型。,使用LayoutKind.Explicit時(shí),需要使用FieldOffsetAttribute特性指示類型中每個(gè)字段的位置。
默認(rèn)情況下,編譯器會(huì)將LayoutKind.Sequential應(yīng)用到結(jié)構(gòu)體,對(duì)于類,需要顯式應(yīng)用LayoutKind.Sequential值。
到這里也就明白了,以后在調(diào)用API函數(shù)時(shí),如果使用的是結(jié)構(gòu)體,就不再需要下面這句代碼了。
[StructLayout(LayoutKind.Sequential)]
下面用示例代碼說明一下
這里以獲取桌面窗體的寬高為例,需要用到的API函數(shù)是
HWND GetDesktopWindow(); BOOL GetWindowRect(HWND hWnd, LPRECT lpRect );
其中LPRECT是指向RECT結(jié)構(gòu)體的指針,RECT結(jié)構(gòu)聲明如下:
typedef struct tagRECT { LONG left; LONG top; LONG right; LONG bottom; } RECT, *PRECT, *NPRECT, *LPRECT;
使用結(jié)構(gòu)體時(shí),調(diào)用代碼如下:
using System; using System.Runtime.InteropServices; namespace ConsoleApp10 { public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } class Program { [DllImport("user32.dll")] private static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowRect(IntPtr hwnd, out RECT rc); static void Main(string[] args) { IntPtr hwnd = GetDesktopWindow(); RECT rect; GetWindowRect(hwnd, out rect); Console.WriteLine($"Left:{rect.Left},Top:{rect.Top},Right:{rect.Right},Bottom:{rect.Bottom}"); } } }
運(yùn)行結(jié)果如下:
下面我們來看一下,把結(jié)構(gòu)體換成類的情況
using System; using System.Runtime.InteropServices; namespace ConsoleApp10 { public class RECT { public int Left; public int Top; public int Right; public int Bottom; } class Program { [DllImport("user32.dll")] private static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowRect(IntPtr hwnd,RECT rc); static void Main(string[] args) { IntPtr hwnd = GetDesktopWindow(); RECT rect = new RECT(); GetWindowRect(hwnd, rect); Console.WriteLine($"Left:{rect.Left},Top:{rect.Top},Right:{rect.Right},Bottom:{rect.Bottom}"); } } }
運(yùn)行結(jié)果如下:
運(yùn)行結(jié)果并不正常
把類修改一下,帶上[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential)] public class RECT { public int Left; public int Top; public int Right; public int Bottom; }
再次運(yùn)行,發(fā)現(xiàn)結(jié)果正常了
最后再看看LayoutKind.Explicit的情況,調(diào)用代碼如下
using System; using System.Runtime.InteropServices; namespace ConsoleApp10 { [StructLayout(LayoutKind.Explicit)] public class RECT { [FieldOffset(0)]public int Left; //FieldOffset用于指示類或結(jié)構(gòu)的非托管表示形式中字段的物理位置 [FieldOffset(4)]public int Top; [FieldOffset(8)]public int Right; [FieldOffset(12)]public int Bottom; } class Program { [DllImport("user32.dll")] private static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowRect(IntPtr hwnd,[MarshalAs(UnmanagedType.LPStruct)]RECT rc); static void Main(string[] args) { IntPtr hwnd = GetDesktopWindow(); RECT rect = new RECT(); GetWindowRect(hwnd, rect); Console.WriteLine($"Left:{rect.Left},Top:{rect.Top},Right:{rect.Right},Bottom:{rect.Bottom}"); } } }
以上就是C#使用StructLayout特性來控制內(nèi)存結(jié)構(gòu)的操作代碼的詳細(xì)內(nèi)容,更多關(guān)于C# StructLayout控制內(nèi)存結(jié)構(gòu)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#開發(fā)微信門戶及應(yīng)用(2) 微信消息處理和應(yīng)答
文章主要為大家詳細(xì)介紹了C#開發(fā)微信門戶及應(yīng)用第二篇,微信消息處理和應(yīng)答,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06詳解C#如何計(jì)算一個(gè)實(shí)例占用多少內(nèi)存
我們都知道CPU和內(nèi)存是程序最為重要的兩類指標(biāo),那么有多少人真正想過一個(gè)類型的實(shí)例在內(nèi)存中究竟占多少字節(jié),本文就來用C#計(jì)算一下一個(gè)實(shí)例占用多少內(nèi)存吧2023-06-06