2015-10-15 117 views
1

當定義在C#COM類您通常有這樣的簽名:返回成功代碼

void Login(string user,string password) 

的AUTOMAGIC COM互操作包裝意味着從C++調用時:

  • 拋出一個異常被轉換到故障HRESULT
  • 返回沒有東西轉換成回國S_OK

但是,如果要返回S_OK以外的成功代碼,該怎麼辦?如S_FALSE還是一些自定義的「成功,但...」的價值?

注意:我在C#中定義類,並想知道如何控制COM互操作。不在C#中基於IDL中的現有接口實現類。

+0

[從C#COM DLL返回小號\ _FALSE]的可能的複製( http://stackoverflow.com/questions/2592684/returning-s-false-from-ac-sharp-com-dll) – user1

+0

它與我所問的標題相同,但實際上是一個非常不同的問題(就像我理解它) - 他正在從IDL工作 - > C# –

回答

2

HRESULT通常是僅有錯誤代碼的數據。它很少用於傳達成功; S_FALSE是唯一明確定義的例外。在S_FALSE的情況下,它通常僅當結果類型是COM布爾型(VARIANT_BOOL)和HRESULT被映射到S_FALSE當返回(下)是用VARIANT_FALSE(和S_OKVARIANT_TRUE)。

對於COM和.Net/COM邊界錯誤(from here),維基百科也談到了HRESULT;

在.NET Framework中,從本機過渡到託管代碼時,HRESULT/IErrorInfo錯誤代碼會轉換爲CLR異常;並且CLR異常在從受管理的本地COM代碼轉換時轉換爲HRESULT/IErrorInfo錯誤代碼。

雖然沒有定論,但肯定不會重新執行該HRESULT通常被視爲一個錯誤代碼的事實。訪問IErrorInfo可能會提供更多的數據,但我不確定它會如您所期望或期望的那樣。

This MSDN article確實提供了更多關於如何映射COM錯誤和異常的信息,並再次支持錯誤代碼;

COM方法通過返回HRESULT報告錯誤; .NET方法通過拋出異常來報告它們。運行時間處理兩者之間的轉換。 .NET Framework中的每個異常類都映射到HRESULT。

要支持「成功代碼」,您可以使用額外的[out]參數。如果代碼不在您的控制範圍內,您可以編寫一個精簡的COM對象來爲您映射該對象,然後在.Net對象中使用該對象。

或者,你可以使用PreserveSigAttribute但據我所知,它不會翻譯錯誤例外,所以你需要做的是自己(一個測試來驗證這個建議)。使用[PreserveSig]註解該方法應該可以做到。

+1

你提出一個很好的例子,S_FALSE是一個異常,並且最好避免。我在這裏注意到它特別指出「不能區分定期返回兩個或更多不同成功代碼的COM方法,例如S_OK或S_FALSE。」 https://msdn.microsoft.com/en-us/library/bb164625.aspx –

2

您必須在方法聲明中使用[PreserveSig]屬性。這意味着字面意思是它保留了方法簽名並防止類型庫導出器重寫它以使其與COM兼容。返回類型必須int以保持其與HRESULT兼容。

簡單爲您例如:

void Login(string user, string password); 

變爲:

[PreserveSig] 
    int Login(string user, string password); 

更令人費解的,當它是方法與非void返回類型。然後您必須按照類型庫導出器的方式重寫它。將其添加爲關鍵字ref的額外參數。所以:

bool Login(string user, string password); 

變爲:

[PreserveSig] 
    int Login(string user, string password, ref bool success); 

記住S_FALSE的值是1,而不是0。

+0

現在,不執行對HRESULT的.NET異常的automagic編組,是嗎?所以我的C#方法不應該在發生失敗的情況下拋出異常,而是始終使用C風格的方法?如果拋出什麼會發生什麼? –