2016-07-25 140 views
1

我有以下COM類型:Project,ContainerItemNodeProject有一個Append函數的集合屬性,該函數接受ContainerItem s。在C++中鑄造COM類型

在C#中,使用類型庫,我可以送Node對象到Append功能和庫按預期工作:

var prj = new Project(); 
var node = new Node(); 
prj.collection.Append(node); 

在C++中我嘗試了直接的指針強制期待這是C#在做,但它結束了一個錯誤:

ProjectPtr prj; 
prj.CreateInstance(__uuidof(Project)); 
NodePtr node; 
node.CreateInstance(__uuidof(Node)); 
prj->collection->Append((ContainerItem**)&node.GetInterfacePtr()); 

是否有一種具體的方式來這些類型的COM指針轉換爲C++?我錯過了什麼?

+2

C風格轉換在COM接口上無效,您必須使用QueryInterface()。 C#自動執行它,但你必須在C++中自己完成。 –

+0

'Append'將'ContainerItem **'作爲參數看起來不太可能。這是沒有道理的。 「Append」的聲明是什麼? 'Node'和'ContainerItem'之間有什麼關係? –

+0

@IgorTandetnik定義是Container :: Append(ContainerItem **,long *),第二個參數可以爲null。我不知道Node和ContainerItem之間的關係,因爲它沒有在編譯器通過COM DLL創建的.tli文件中表示。 – tunc

回答

1

COM鑄造與QueryInterface()方法來完成。查詢對象是否支持接口(基於GUID),如果支持接口,則內部參考計數器遞增(請參閱AddRef()),並返回指向接口的指針。 MSDN has more detail on the inner workings

C++並不像C#那樣直接支持「COM cast」的代碼生成,但其實現非常簡單。

struct bad_com_cast : std::runtime_error { 
    bad_com_cast() : std::runtime_error("COM interface not supported") {} 
}; 

template <class To, class From> 
To* qi_cast(From* iunknown) 
{ 
    HRESULT hr = S_OK; 
    To* ptr = NULL; 
    if (iunknown) { 
     hr = iunknown->QueryInterface(__uuidof(To), (void**)(&ptr)); 
     if (hr != S_OK) { 
      throw bad_com_cast(); // or return NULL 
     } 
    } 
    return ptr; 
} 

使用上述「鑄造」,樣品可以實施如下:

ContainerItem* ci = qi_cast<ContainerItem>(node); 
prj->collection->Append(&ci); 

如果正在使用ATL庫,你可以使用ATL::CComQIPtr<>直接獲得相當於語義;

auto ci = CComQIPtr<ContainerItem>(node); 
if (ci) { 
    // ... 
} 
0

就像@HansPassant評論,我只好用QueryInterface函數:

ContainerItem* ci = nullptr; 
node.QueryInterface(__uuidof(ContainerItem), ci); 
prj->collection->Append(&ci);