我有这个ATL COM服务器,它是用VS2017 C ++构建并正确注册的,而C ++中的客户端也使用相同的工具构建。
现在这个COM服务器实际上是用C#
构建的 客户端可以注册一个回调函数,但要做到这一点,它必须实现当然定义和注册的INotificationListener COM接口。
只是想知道是否可以简单地继承COM接口类,实现所有必要的抽象函数并使用常规C ++ RAII?
以前当COM服务器在C ++中时,这似乎是偶然的。当我们在C#中使用新的COM服务器时,这在C ++ COM客户端中爆炸了。因此,我切换到另一种方法来创建监听器。
我将把一个COM客户端代码片段放在哪里,但是我怀疑这是否是正确和/或正确的方法。
下面的代码片段更正了,不再是用户普通的C ++类RAII实例化,而是使用COM / ATL方法。如果COM服务器是C#
,则常规C ++ RAII不起作用class SomeNotificationListener : public INotificationListener
{
public:
SomeNotificationListener()
: m_nRefCount(0)
{
}
virtual ~SomeNotificationListener()
{
}
// IUnknown abstract function implementation
// now that COM server is in C# and we use ATL/COM to
// create INotificationListener object,
// this function gets called many times
// the trick to make it work was to reject unknown interfaces by
// returning E_NOINTERFACE
HRESULT __stdcall QueryInterface(const IID &riid, void **ppObj) override
{
if (riid == __uuidof(INotificationListener))
{
*ppObj = static_cast<INotificationListener*>(this);
AddRef();
}
else if (riid == IID_IUnknown)
{
*ppObj = static_cast<IUnknown*>(this);
AddRef();
}
else
{
*ppObj = nullptr;
return E_NOINTERFACE;
}
return S_OK;
}
// IUnknown abstract function implementation
// never gets called
ULONG __stdcall AddRef(void) override
{
return InterlockedIncrement(&m_nRefCount);
}
// IUnknown abstract function implementation
// never gets called (good as this code which calls "delete this" would
// cause undefined behavior if combined with RAII
// this is copied from some COM samples
// typical Release() implementation
ULONG __stdcall Release(void) override
{
long nRefCount = 0;
nRefCount = InterlockedDecrement(&m_nRefCount);
// this part also created problems if COM server was in C#
// 'delete this' very dangerous and not the way to go if you use
// ATL/COM smart pointers
//if (0 == nRefCount)
// delete this;
return nRefCount;
}
// this is the function that is used by COM server to notify client
// INotificationListener abstract function implementation
// it DOES get called
HRESULT __stdcall Notify(
/*[in]*/ unsigned long dwCount,
/*[in]*/ BSTR * psAddresses,
/*[in]*/ VARIANT * pvarValues,
/*[in]*/ DATE * pdtTimestamps) override
{
// just stub code here
// setting a break point on next line does work
return S_OK;
}
private:
long m_nRefCount;
};
int main()
{
HRESULT hr = CoInitialize(NULL);
// open context
// upon closing curly brace, all COM smart pointers will be freed
{
// here's our listener object on client side
// after some experiments, it seemed the best to create using COM smartptr
INotificationListener fnListener(new SomeNotificationListener());
auto uid = __uuidof(SomeRequestFactory);
IRequestFactoryPtr rfPtr(uid);
// notification request from COM server
auto notify = rfPtr->CreateNotificationRequest();
// here client registers listener
// fnListener is COM smartptr
notify->SetListener(fnListener);
// COM server's Subscribe will call Notify()
// on INotificationListener interface
// since SomeNotificationListener implements all abstract functions
// from INotificationListener, Notify() does indeed get called
notify->Subscribe();
// all COM smart ptrs cleared
}
CoUninitialize();
return 0;
}
现在这似乎工作正常。对QueryInterface的正确性仍有一些疑问,但比以前好多了。