解讀封送類、結(jié)構(gòu)體和聯(lián)合體實例
封送類、結(jié)構(gòu)體和聯(lián)合體實例
封送類
在.NET Framework中,類是引用類型,而結(jié)構(gòu)體是值類型。對于類而言,它們只能通過COM互操作來封送,并且總是作為接口封送。
當(dāng)托管類傳遞給COM時,互操作封送處理器會自動使用COM代理包裝該類,并將由代理生成的類接口傳遞到COM方法調(diào)用。
例如:
// 假設(shè)有一個非托管的COM接口IDemoInterface
[ComImport]
[Guid("...")]
interface IDemoInterface {
void DoSomething();
}
// 定義一個實現(xiàn)該接口的托管類
public class ManagedClass : IDemoInterface {
public void DoSomething() {
Console.WriteLine("Doing something...");
}
}
// 在托管代碼中創(chuàng)建并傳遞給非托管代碼
var managedInstance = new ManagedClass();
// 這里假設(shè)有一個非托管函數(shù)接收IDemoInterface類型的參數(shù)
NativeMethods.PassToUnmanaged(managedInstance);這里PassToUnmanaged是一個平臺調(diào)用(P/Invoke)定義的方法,它負(fù)責(zé)將ManagedClass對象轉(zhuǎn)換成COM接口指針傳遞給非托管代碼。
封送結(jié)構(gòu)體
結(jié)構(gòu)體作為值類型,在跨平臺調(diào)用時也需要適當(dāng)?shù)姆馑吞幚怼?/p>
為了確保結(jié)構(gòu)體成員按照預(yù)期的方式被解釋,通常會在結(jié)構(gòu)體上應(yīng)用StructLayoutAttribute屬性來指定布局方式。
考慮如下C++定義的結(jié)構(gòu)體:
typedef struct _MYPERSON {
char* first;
char* last;
} MYPERSON, *LP_MYPERSON;C#封送定義可能是這樣的:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyPerson {
[MarshalAs(UnmanagedType.LPStr)]
public string first;
[MarshalAs(UnmanagedType.LPStr)]
public string last;
}這里使用了StructLayout特性指定了順序布局,并通過MarshalAs特性指定了字符串字段如何被封送。
如果要傳遞此結(jié)構(gòu)體到非托管代碼,則可以像下面這樣操作:
[DllImport("PinvokeLib.dll")]
static extern int TestStructInStruct([In] MyPerson2 person2);
// 構(gòu)建MyPerson實例
var person = new MyPerson { first = "John", last = "Doe" };
// 創(chuàng)建包含person指針的MyPerson2實例
var person2 = new MyPerson2 { person = Marshal.AllocCoTaskMem(Marshal.SizeOf(person)), age = 30 };
// 復(fù)制person的內(nèi)容到分配的非托管內(nèi)存
Marshal.StructureToPtr(person, person2.person, false);
try {
// 調(diào)用非托管函數(shù)
var result = TestStructInStruct(person2);
} finally {
// 清理非托管資源
Marshal.FreeCoTaskMem(person2.person);
}這段代碼展示了如何安全地管理非托管內(nèi)存,并確保正確地封送結(jié)構(gòu)體給非托管函數(shù)。
封送聯(lián)合體
聯(lián)合體(Union)允許在同一段內(nèi)存空間內(nèi)存儲不同類型的數(shù)據(jù)成員。這意味著任何時候只有一個成員有效。
在C#中表示聯(lián)合體通常涉及到使用StructLayout(LayoutKind.Explicit)特性以及FieldOffset特性來精確控制成員的位置。
比如,我們有以下C++定義的聯(lián)合體:
union MYUNION {
int i;
double d;
};C#封送定義可以是:
[StructLayout(LayoutKind.Explicit)]
public struct MyUnion {
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public double d;
}這里使用了Explicit布局模式,所有字段都從偏移量0開始,意味著它們共享相同的內(nèi)存位置。
當(dāng)需要傳遞這個聯(lián)合體到非托管代碼時,可以直接使用上述定義,因為.NET運行時知道如何正確地封送聯(lián)合體中的成員。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#調(diào)用RabbitMQ實現(xiàn)消息隊列的示例代碼
這篇文章主要介紹了C#調(diào)用RabbitMQ實現(xiàn)消息隊列的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
C#中如何將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類的方法總結(jié)
這篇文章主要給大家總結(jié)介紹了關(guān)于C#中如何將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2018-04-04
C# 使用WPF 用MediaElement控件實現(xiàn)視頻循環(huán)播放
在WPF里用MediaElement控件,實現(xiàn)一個循環(huán)播放單一視頻的程序,同時可以控制視頻的播放、暫停、停止。這篇文章給大家介紹了C# 使用WPF 用MediaElement控件實現(xiàn)視頻循環(huán)播放,需要的朋友參考下吧2018-04-04

