COM客户端的C ++类继承COM服务器的类接口,使用RAII

时间:2018-02-09 12:59:00

标签: c# c++ com atl

我有这个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的正确性仍有一些疑问,但比以前好多了。

0 个答案:

没有答案