2016-07-25 143 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);