现有的普通 C++ class 是否可以在不转换为 COM class 的情况下实现 IDL 接口?
Can an existing plain C++ class implement IDL interface without turning into a COM class?
我有一个 COM 对象,CProvider,使用 ATL 实现。此 class 包含另一个 class、CProviderInfo,并维护此内部 class 类型对象的静态向量。
这是它的样子:
//-------------
// CProvider.h
//-------------
//
// COM object class
//
class ATL_NO_VTABLE CProvider :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CProvider, &CLSID_Provider>,
public Interface1,
public Interface2
{
public:
BEGIN_COM_MAP(CProvider)
COM_INTERFACE_ENTRY(Interface1)
COM_INTERFACE_ENTRY(Interface2)
END_COM_MAP()
//
// The inner class
//
class CProviderInfo
{
public:
CProviderInfo();
CComBSTR m_strName;
GUID m_guidRegistration;
};
private:
//
// static vector of inner class type
//
static vector<CProviderInfo> m_vProviderInfo;
};
我想做的是在 CProvider 上引入一种方法,returns 静态向量的副本 m_vProviderInfo。尝试按照 COM 规则进行游戏,为此我引入了一个新的 IDL 接口 IProviderInfoRetriever:
//---------
// IDL file
//---------
//
// IProviderInfoRetriever interface
//
[
// uuid, version ... etc.
]
interface IProviderInfoRetriever : IUnknown
{
HRESULT GetProviderInfo(
[out, retval] SAFEARRAY(IProviderInfo*) *ppProviderInfo);
}
//
// The interface of the class holding the info
//
[
// uuid, version ... etc.
]
interface IProviderInfo : IUnknown
{
[propget]
HRESULT Name(
[out, retval] BSTR *pbstrName);
[propget]
HRESULT Registration(
[out, retval] GUID *pguidRegistration);
}
我的计划是让 CProvider 实现 IProviderInfoRetriever 有效地复制静态向量的内容 m_vProviderInfo 到 IProviderInfoRetriever::GetProviderInfo().
的输出 SAFEARRAY
我的问题是:是否可以让内部 class CProviderInfo 实现 IProviderInfo?这会破坏创建 CProviderInfo 类型局部变量的现有代码吗?
我做了一些广泛的研究,答案很简单:是的,但这并不容易。在不破坏依赖于上述 C++ class.
的现有代码的情况下,您极不可能只拥有一个普通的 C++ class inherit/implement 一个在 IDL 中定义的接口
首先,如果你使用ATL的工具将你的C++class转换成COMclass,你会突然发现这个C++class已经变得抽象了由于引入了所有纯虚函数 ATL 宏。因此,至少,您将通过 ATL 宏将 IUnknown
的 AddRef()
、Release()
和 QueryInterface()
作为纯虚拟添加到您的 C++ class功能,例如
class ATL_NO_VTABLE CProviderInfo:
public CComObjectRootEx<CComMultiThreadModel>,
public IProviderInfo
{
public:
BEGIN_COM_MAP(CProviderInfo)
COM_INTERFACE_ENTRY(IProviderInfo)
END_COM_MAP() // This line adds IUnknown's AddRef(), Release(),
// and QueryInterface() as pure virtual functions.
// ...
};
仅此一项就会破坏用于创建 C++ 实例的任何现有代码 class,无论它们是在堆栈上还是在堆上(使用 new 运算符)。所以,最终你有 2 个选择:
使用 ATL 的工具将您的 C++ class 变成 COM class。
这会将您的 C++ class 变成抽象 class。您必须修改源代码中创建 C++ class 对象的所有位置,以改用 ATL 的 classes,即 CComObject
、CComObjectStack
... 等
Inherit/Implement直接用IDL手动定义的接口
这将需要根据您的接口提供您自己的 IUnknown
、IDispatch
或两者的实现,以及由您的接口本身定义的任何方法的实现。此选项的优点是不太可能破坏代码库中 C++ class 的任何现有用途。
然而,在没有 ATL 的情况下滚动您自己的 COM 接口实现并不总是那么容易,尤其是当您的 C++ class 曾经涉及复杂的场景时,例如互操作。
我有一个 COM 对象,CProvider,使用 ATL 实现。此 class 包含另一个 class、CProviderInfo,并维护此内部 class 类型对象的静态向量。
这是它的样子:
//-------------
// CProvider.h
//-------------
//
// COM object class
//
class ATL_NO_VTABLE CProvider :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CProvider, &CLSID_Provider>,
public Interface1,
public Interface2
{
public:
BEGIN_COM_MAP(CProvider)
COM_INTERFACE_ENTRY(Interface1)
COM_INTERFACE_ENTRY(Interface2)
END_COM_MAP()
//
// The inner class
//
class CProviderInfo
{
public:
CProviderInfo();
CComBSTR m_strName;
GUID m_guidRegistration;
};
private:
//
// static vector of inner class type
//
static vector<CProviderInfo> m_vProviderInfo;
};
我想做的是在 CProvider 上引入一种方法,returns 静态向量的副本 m_vProviderInfo。尝试按照 COM 规则进行游戏,为此我引入了一个新的 IDL 接口 IProviderInfoRetriever:
//---------
// IDL file
//---------
//
// IProviderInfoRetriever interface
//
[
// uuid, version ... etc.
]
interface IProviderInfoRetriever : IUnknown
{
HRESULT GetProviderInfo(
[out, retval] SAFEARRAY(IProviderInfo*) *ppProviderInfo);
}
//
// The interface of the class holding the info
//
[
// uuid, version ... etc.
]
interface IProviderInfo : IUnknown
{
[propget]
HRESULT Name(
[out, retval] BSTR *pbstrName);
[propget]
HRESULT Registration(
[out, retval] GUID *pguidRegistration);
}
我的计划是让 CProvider 实现 IProviderInfoRetriever 有效地复制静态向量的内容 m_vProviderInfo 到 IProviderInfoRetriever::GetProviderInfo().
的输出 SAFEARRAY我的问题是:是否可以让内部 class CProviderInfo 实现 IProviderInfo?这会破坏创建 CProviderInfo 类型局部变量的现有代码吗?
我做了一些广泛的研究,答案很简单:是的,但这并不容易。在不破坏依赖于上述 C++ class.
的现有代码的情况下,您极不可能只拥有一个普通的 C++ class inherit/implement 一个在 IDL 中定义的接口首先,如果你使用ATL的工具将你的C++class转换成COMclass,你会突然发现这个C++class已经变得抽象了由于引入了所有纯虚函数 ATL 宏。因此,至少,您将通过 ATL 宏将 IUnknown
的 AddRef()
、Release()
和 QueryInterface()
作为纯虚拟添加到您的 C++ class功能,例如
class ATL_NO_VTABLE CProviderInfo:
public CComObjectRootEx<CComMultiThreadModel>,
public IProviderInfo
{
public:
BEGIN_COM_MAP(CProviderInfo)
COM_INTERFACE_ENTRY(IProviderInfo)
END_COM_MAP() // This line adds IUnknown's AddRef(), Release(),
// and QueryInterface() as pure virtual functions.
// ...
};
仅此一项就会破坏用于创建 C++ 实例的任何现有代码 class,无论它们是在堆栈上还是在堆上(使用 new 运算符)。所以,最终你有 2 个选择:
使用 ATL 的工具将您的 C++ class 变成 COM class。
这会将您的 C++ class 变成抽象 class。您必须修改源代码中创建 C++ class 对象的所有位置,以改用 ATL 的 classes,即
CComObject
、CComObjectStack
... 等Inherit/Implement直接用IDL手动定义的接口
这将需要根据您的接口提供您自己的
IUnknown
、IDispatch
或两者的实现,以及由您的接口本身定义的任何方法的实现。此选项的优点是不太可能破坏代码库中 C++ class 的任何现有用途。然而,在没有 ATL 的情况下滚动您自己的 COM 接口实现并不总是那么容易,尤其是当您的 C++ class 曾经涉及复杂的场景时,例如互操作。