.NET Interop 中的隱含方法簽章轉譯
為了保持與程式設計語言不相關,Windows COM 系統和許多 Windows API 都會傳回稱為 HRESULT
的 4 位元組整數型別,以指出 API 成功或失敗,以及失敗的一些相關資訊。 需要傳遞至呼叫者的其他值會透過做為「out」參數的指標參數「傳回」,而且通常是簽章中的最後一個參數。 C# 和 Visual Basic 等程式設計語言傳統上會將失敗程式碼轉譯為例外狀況,以符合失敗在該語言中通常的傳播方式,並預期 Interop 方法簽章不會包含 HRESULT
。 若要將方法簽章轉譯為原生簽章,執行階段會將方法的傳回值移至具有多一層間接取值 (換句話說,讓它成為受控簽章傳回型別的指標) 的額外「out」參數,並假設傳回值為 HRESULT
。 如果受控方法傳回 void
,則不會新增其他參數,而且傳回值會變成 HRESULT
。 例如,請參閱下列兩個轉譯為相同原生簽章的 C# COM 方法:
int Add(int a, int b);
void Add(int a, int b, out int sum);
HRESULT Add(int a, int b, /* out */ int* sum);
COM 中的 PreserveSig
C# 中的所有 COM 方法預設都會使用轉譯的簽章。 若要在沒有簽章轉譯和處理 HRESULT
值的情況下使用和匯出方法,請將 PreserveSigAttribute 新增至 COM 介面方法。 當屬性套用至方法時,不會對簽章執行任何轉譯,而且不會針對失敗 HRESULT
的值擲回例外狀況。 這同時適用於內建 COM 和來源產生的 COM。 例如,請參閱下列具有 PreserveSig
屬性及其對應原生簽章的 C# 方法簽章。
[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);
如果方法可能會傳回不是失敗但必須以不同的方式處理的不同 HRESULT
值,這會非常有用。 例如,當方法未失敗但只傳回部分結果時,某些方法可能會傳回 S_FALSE
值,而當方法傳回所有結果時,可能會傳回 S_OK
值。
PreserveSig
與 P/Invoke
DllImportAttribute 屬性也有類似 PreserveSigAttribute
的 bool PreserveSig
欄位,但預設為 true
。 若要指出執行階段應該轉譯受控簽章並處理傳回的 HRESULT
,請將 DllImportAttribute
中的 PreserveSig
欄位設定為 false
。 例如,請參閱下列相同原生方法的兩個 P/Invoke 簽章,其中一個將 PreserveSig
設定為 false
,另一個則保留為預設值 true
。
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true, PreserveSig = false)]
public static extern void SHAutoComplete(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true)]
public static extern int SHAutoCompleteHRESULT(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);
注意
來源產生的 P/Invoke,其使用的 LibraryImportAttribute 沒有 PreserveSig
欄位。 產生的程式碼一律會假設原生和受控簽章相同。 如需詳細資訊,請參閱來源產生的 P/Invoke。
手動處理 HRESULT
值
當呼叫 PreserveSig
方法傳回 HRESULT
時,如果 HRESULT
表示失敗,您可以使用 ThrowExceptionForHR 方法來擲回對應的例外狀況。 同樣地,在實作 PreserveSig
方法時,您可以使用 GetHRForException 方法傳回 HRESULT
,指出例外狀況的對應值。
將 HRESULT 封送處理為結構
使用 PreserveSig
方法時,int
必須是 HRESULT
的受控型別。 不過,使用自訂 4 位元組結構做為傳回型別,可讓您定義協助程式方法和屬性,以簡化 HRESULT
的使用。 在內建封送處理中,這會自動運作。 若要在來源產生封送處理中使用結構取代 int
做為 HRESULT
的受控表示法,請新增具有 Error 作為引數的 MarshalAsAttribute 屬性。 這個屬性的存在會將 HRESULT
的位元重新解譯為結構。