2017-04-10 87 views
0

我想公開一個返回IEnumerable的方法,但是我無法通過C++代碼來使用它。我讀this SO的問題,但它是關於IEnumerator而不是IEnumerableCOM - 在C++中使用IEnumerable

[ComVisible(true), 
    Guid("myguid")] 
[InterfaceType(ComInterfaceType.InterfaceIsDual)] 
public interface IDbReader 
{ 
    IEnumerable GetUsers(); 
} 

[ComVisible(true), 
    Guid("myguid2")] 
[ProgId("MyDbReader.DbReader")] 
internal class DbReader : IDbReader 
{ 
    IEnumerable GetUsers() => new List<string>() { "User1", "User2" }; 
} 

在C++:

#import "MyDbReader.tlb" named_guids raw_interfaces_only 

... 

CComPtr<IDbReader> myreader; // created through a factory 
CComPtr<IEnumerable> users; 
myreader->GetUsers(&users); 

users->GetEnumerator(); // The compiler says: pointer to incomplete class is not allowed 

此外,編譯器看到IDbReader::IEnumerable,而不是使用標準IEnumerable

我錯過了什麼?

感謝,

回答

1

你如何到達C++代碼並不是很清楚,你通常會使用#import指令來導入由C#項目生成的類型庫。它應該類似於:

#import "c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.tlb" 
using namespace mscorlib; 
#import "CSharpLibrary.tlb" 
using namespace CSharpLibrary; 

假設C#項目名稱是「CSharpLibrary」。這會生成從_com_ptr_t派生的智能指針類型,它們與附加的Ptr的接口具有相同的名稱。利用引用計數的優勢,接口函數調用失敗以C++異常報告,而不是難以處理的HRESULT錯誤代碼。

附加的細節,確實很難診斷從wonky編譯錯誤消息,但從IntelliSense可見的是,.NET類型庫導出器將System.Collections.IEnumerator轉換爲IEnumVARIANT *。所以基本的代碼應該是這樣的:

try { 
    IEnumerablePtr users = myreader->GetUsers(); 
    IEnumVARIANTPtr enumusers = users->GetEnumerator(); 
    _variant_t vuser; 
    while (SUCCEEDED(enumusers->Next(1, &vuser, NULL))) { 
     BSTR user = vuser.bstrVal; 
     // etc... 
    } 
} 
catch (_com_error& ex) { 
    // Handle or report runtime error... 
} 

未經檢驗的,應該是在球場。正如鏈接問題所述,通過讓C#接口暴露IEnumerator而不是IEnumerable,可以避免對GetEnumerator()的額外調用。您可以閱讀更多關於this MSDN article中使用的C++編譯器支持類的信息。

+0

不幸的是,我需要使用'#import「CSharpLibrary.tlb」named_guids raw_interfaces_only'指令(沒有標誌我有> 60錯誤)。這樣智能指針不會生成,但您仍然可以使用CComPtr 等。我將更新問題。 – peval27

+0

順便說一句,我錯過了'使用命名空間mscorlib;'並且出於任何原因它無法正常工作。這是一個奇怪的錯誤消息,不能幫助用戶解決問題。標記爲答案 – peval27

+0

Hmya,這是一種當編譯錯誤不明確時最終會出現的下降螺旋。而且你有一個以上的錯誤,讓它變得更加複雜。你不需要使用它。 –

0

嘗試使你的DbReader.GetUsers(...)執行公開,使其正確實現IDbReader接口。例如:

internal class DbReader : IDbReader 
{ 
    public IEnumerable GetUsers() => new List<string>() { "User1", "User2" }; 
} 

另外,還要確保你using System.Collections(爲IEnumerable)除了using System.Collections.Generic(爲List<T>)在C#代碼。