C#使用StructLayout特性來(lái)控制內(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;
}
在類(lèi)或者結(jié)構(gòu)體前面帶上了
[StructLayout(LayoutKind.Sequential)]
StructLayoutAttribute特性的作用是允許你控制內(nèi)存中類(lèi)或結(jié)構(gòu)的數(shù)據(jù)字段的物理布局。
平常我們?cè)贑#代碼中使用類(lèi)或者結(jié)構(gòu)體時(shí),不需要使用此特性。但在與非托管代碼時(shí)交互,需要使用StructLayoutAttribute特性來(lái)控制類(lèi)型的非托管布局。
StructLayoutAttribute常用構(gòu)造函數(shù)是:
StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind)
System.Runtime.InteropServices.LayoutKind是一個(gè)枚舉類(lèi)型,有三個(gè)取值。
LayoutKind.Sequential
強(qiáng)制按成員的顯示順序?qū)ζ溥M(jìn)行排列。對(duì)于blittable類(lèi)型,在托管和非托管內(nèi)存中控制布局。對(duì)于non-blittable類(lèi)型,它會(huì)在將類(lèi)或者結(jié)構(gòu)體封送到非托管代碼時(shí)控制布局(換言之,如果僅在C#中進(jìn)行調(diào)用,不會(huì)做任何操作,在與非托管代碼交互時(shí),僅控制送入非托管代碼的布局)
LayoutKind.Explicit
控制每個(gè)數(shù)據(jù)成員的精確位置,這會(huì)影響托管和非托管代碼中的布局,不管是blittable類(lèi)型還是non-blittable類(lèi)型。,使用LayoutKind.Explicit時(shí),需要使用FieldOffsetAttribute特性指示類(lèi)型中每個(gè)字段的位置。
默認(rèn)情況下,編譯器會(huì)將LayoutKind.Sequential應(yīng)用到結(jié)構(gòu)體,對(duì)于類(lèi),需要顯式應(yīng)用LayoutKind.Sequential值。
到這里也就明白了,以后在調(diào)用API函數(shù)時(shí),如果使用的是結(jié)構(gòu)體,就不再需要下面這句代碼了。
[StructLayout(LayoutKind.Sequential)]
下面用示例代碼說(shuō)明一下
這里以獲取桌面窗體的寬高為例,需要用到的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é)果如下:

下面我們來(lái)看一下,把結(jié)構(gòu)體換成類(lèi)的情況
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é)果并不正常
把類(lèi)修改一下,帶上[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用于指示類(lèi)或結(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特性來(lái)控制內(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#自動(dòng)刪除Word文檔空白行和空白頁(yè)的完整代碼
在處理 Word 文檔時(shí),經(jīng)常會(huì)遇到空白行、空表格或空白頁(yè)的問(wèn)題,這不僅影響排版美觀,還可能導(dǎo)致文檔頁(yè)數(shù)冗余,所以本文將介紹如何使用 Spire.Doc for .NET 在 C# 中自動(dòng)刪除 Word 文檔的空白行、空表格和空白頁(yè),需要的朋友可以參考下2025-08-08
C#中Property和Attribute的區(qū)別實(shí)例詳解
這篇文章主要介紹了C#中Property和Attribute的區(qū)別,較為詳細(xì)的分析了C#中Property和Attribute的功能、定義、區(qū)別及使用時(shí)的相關(guān)注意事項(xiàng),需要的朋友可以參考下2015-06-06
C#操作Word模擬解析HTML標(biāo)記輸出帶格式的文本
這篇文章介紹了一種解決Word文檔格式設(shè)置問(wèn)題的方案,通過(guò)HTML標(biāo)記化文本內(nèi)容,利用正則表達(dá)式提取關(guān)鍵字,并對(duì)Word字符集對(duì)象逐字操作來(lái)重置格式,感興趣的小伙伴可以了解下2026-01-01
C# 利用代理爬蟲(chóng)網(wǎng)頁(yè)的實(shí)現(xiàn)方法
這篇文章主要介紹了C# 利用代理爬網(wǎng)頁(yè)的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本能幫助到大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10
.NET實(shí)現(xiàn)父窗體關(guān)閉而不影響子窗體的方法
這篇文章主要介紹了.NET實(shí)現(xiàn)父窗體關(guān)閉而不影響子窗體的方法,很實(shí)用的功能,需要的朋友可以參考下2014-08-08
Unity實(shí)現(xiàn)蘋(píng)果手機(jī)Taptic震動(dòng)
這篇文章主要介紹了Unity實(shí)現(xiàn)蘋(píng)果手機(jī)Taptic震動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10

