2013-10-16 100 views
0

我嘗試調用代碼int size = Marshal.SizeOf(typeof(MyStruct)),但它拋出以下異常:爲什麼我不能爲此C#結構執行Marshal.SizeOf()?

類型「MYSTRUCT」不能被封送一個非託管的結構;無法計算出有意義的大小或偏移量。

我的結構如下:

[StructLayout(LayoutKind.Sequential)] 
public struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.U4)] 
    public UInt32 version; 
    [MarshalAs(UnmanagedType.FunctionPtr)] 
    public IntPtr Start; 
    [MarshalAs(UnmanagedType.FunctionPtr)] 
    public IntPtr Stop; 
    // And a bunch more IntPtr, all declared the same way. 
} 

的結構應該被傳遞到C-土地,那裏的C代碼將使用其內容作爲函數指針。我看不到如何計算大小會失敗,任何人都可以幫忙?

回答

3

UnmanagedType.FunctionPtr要求該字段爲委託類型。在結構被封送後,它將成爲C端的函數指針。使用[MarshalAs]是多餘的,代表已經像這樣被封送。因此,大致爲:

[StructLayout(LayoutKind.Sequential)] 
public struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.U4)] 
    public UInt32 version; 
    public Action Start; 
    public Func<bool> Stop; 
    // etc.. 
} 

更改委託類型匹配相應的C函數指針的函數簽名。您經常必須聲明自己的委託類型,因此您可以爲其賦予[UnmanagedFunctionPointer]屬性以匹配C函數的調用約定。通常是CallingConvention.Cdecl,而不是Stdcall的默認值。

當你像這樣初始化一個結構時,你必須非常小心。您創建並分配給這些字段的委託對象必須在別處引用,以防止它們被垃圾收集。通過將它們存儲在類對象中,只要C代碼可以撥打電話,將它們存儲在一個靜態變量中或通過明確添加一個帶有GCHandle.Alloc()的引用,就可以保證這些類對象能夠正常播放。類別對象有許多拍攝方式你的腳,祝你好運:) :)

+0

感謝您的反饋。我目前通過執行'Marshal.GetFunctionPointerForDelegate(無論)'來填充結構體。由於各種原因,我想保留結構成員爲'IntPtr' - 如果我只是刪除'[MarshalAs(UnmanagedType.FunctionPtr)]'將兼容? – FusterCluck

+1

使用GetFunctionPointerForDelegate()不會改變答案中的任何內容,但同樣的問題也適用。是的,就像將該字段聲明爲委託類型一樣,您也不需要IntPtr上的[MarshalAs]。 –

相關問題