2013-03-05 58 views
3

我正在使用C#來調用DLL函數。在interop方法中傳遞`ref struct`參數的`null`引用

[DllImport("MyDLL.dll", SetLastError = true)] 
public static extern uint GetValue(
     pHandle handle, 
     ref somestruct a, 
     ref somestruct b); 

如何通過參數3的null參考?

當我嘗試,我得到一個編譯時錯誤:

Cannot convert from <null> to ref somestruct.

我也試過IntPtr.Zero

+0

它是'ref'參數?那麼你爲什麼不告訴我們確切的方法簽名? 'somestruct'真的是一個結構還是一個類? – 2013-03-05 06:50:55

+0

修復它。它是一個結構 – user1964059 2013-03-05 06:52:06

+0

可以這篇文章http://msdn.microsoft.com/en-us/library/1t3y8s4s(v=vs.80).aspx幫助你嗎? – 2013-03-05 06:59:49

回答

4

你有兩個選擇:

  1. somestruct一類,將函數簽名:

    [DllImport("MyDLL.dll", SetLastError = true)] 
    public static extern uint GetValue(
        pHandle handle, somestruct a, somestruct b); 
    

    通常,這不能改變任何東西,但你可以通過一個null作爲值ab。到ref

    [DllImport("MyDLL.dll", SetLastError = true)] 
    public static extern uint GetValue(
        pHandle handle, IntPtr a, IntPtr b); 
    

    現在你可以調用函數與IntPtr.Zero,除了somestruct類型的對象:

  2. 添加另一個過載的功能,這樣

    GetValue(myHandle, ref myStruct1, ref myStruct2); 
    GetValue(myHandle, IntPtr.Zero, IntPtr.Zero); 
    
0

This answer建議使SomeStruct成爲一類。我想展示一個實現這個想法,看起來很好地工作...即使當你不能改變SomeStruct的定義(例如,當它是一個預定義的類型,如System.Guid;另請參閱this answer)。

  1. 定義一個通用的包裝類:

    [StructLayout(LayoutKind.Explicit)] 
    public sealed class SomeStructRef 
    { 
        [FieldOffset(0)] 
        private SomeStruct value; 
    
        public static implicit operator SomeStructRef(SomeStruct value) 
        { 
         return new SomeStructRef { value = value }; 
        } 
    } 
    

    這裏的基本思想是相同的boxing

  2. 您的互操作方法定義更改爲以下:然後

    [DllImport("MyDLL.dll", SetLastError = true)] 
    public static extern uint GetValue(
        pHandle handle, 
        ref SomeStruct a, 
        [MarshalAs(UnmanagedType.LPStruct)] SomeStructRef b); 
    

第三個參數b將是 「可空」。由於SomeStructRef是參考類型,因此您可以傳遞null參考。您還可以傳遞SomeStruct值,因爲存在從SomeStructSomeStructRef的隱式轉換運算符。並且(至少在理論上),由於[StructLayout]/[FieldOffset]編組指令,因此SomeStructRef的任何實例都應該像實際實例SomeStruct一樣進行編組。

如果有人是互操作專家,我會很高興能驗證這種技術的可靠性。

0

另一個明顯的解決方案是求助於unsafe代碼和改變互操作方法聲明這樣:

[DllImport("MyDLL.dll", SetLastError = true)] 
unsafe public static extern uint GetValue(
     pHandle handle, 
     ref somestruct a, 
     somestruct* b); 

注意,該方法現在被標記unsafe,並且該參數已經從ref somestruct改變爲somestruct*

這具有以下含義:

  • 的方法,只能從一個unsafe上下文中調用。例如:

    somestruct s; 
    unsafe { GetValue(…, …, &s); } // pass a struct `s` 
    unsafe { GetValue(…, …, null); } // pass null reference 
    
  • 爲了使上述工作,unsafe代碼必須被允許用於項目(無論是在項目設置,或通過/unsafe命令行編譯器開關)。

  • 使用unsafe會導致無法驗證的IL代碼。 IIRC,這意味着加載這個程序集需要完全信任(在某些情況下可能會有問題)。