解讀封送類、結(jié)構(gòu)體和聯(lián)合體實例
封送類、結(jié)構(gòu)體和聯(lián)合體實例
封送類
在.NET Framework中,類是引用類型,而結(jié)構(gòu)體是值類型。對于類而言,它們只能通過COM互操作來封送,并且總是作為接口封送。
當托管類傳遞給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)定義的方法,它負責將ManagedClass
對象轉(zhuǎn)換成COM接口指針傳遞給非托管代碼。
封送結(jié)構(gòu)體
結(jié)構(gòu)體作為值類型,在跨平臺調(diào)用時也需要適當?shù)姆馑吞幚怼?/p>
為了確保結(jié)構(gòu)體成員按照預期的方式被解釋,通常會在結(jié)構(gòu)體上應用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 }; // 復制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)存位置。
當需要傳遞這個聯(lián)合體到非托管代碼時,可以直接使用上述定義,因為.NET運行時知道如何正確地封送聯(lián)合體中的成員。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#調(diào)用非托管動態(tài)庫中的函數(shù)方法
這篇文章主要介紹了C#調(diào)用非托管動態(tài)庫中的函數(shù)方法,本文講解創(chuàng)建一個非托管動態(tài)庫,然后在C#中調(diào)用它,需要的朋友可以參考下2015-02-02C#中數(shù)組、ArrayList、List、Dictionary的用法與區(qū)別淺析(存取數(shù)據(jù))
在工作中經(jīng)常遇到C#數(shù)組、ArrayList、List、Dictionary存取數(shù)據(jù),但是該選擇哪種類型進行存儲數(shù)據(jù)呢?很迷茫,今天小編抽空給大家整理下這方面的內(nèi)容,需要的朋友參考下吧2017-02-02Windows窗體的.Net框架繪圖技術(shù)實現(xiàn)方法
這篇文章主要介紹了Windows窗體的.Net框架繪圖技術(shù)實現(xiàn)方法,非常實用,需要的朋友可以參考下2014-08-08