注册C++;带有C#COM服务器的接收器 我想注册一个带有Exchange接口的C++接收器,因此登记一个C应用程序的事件。

注册C++;带有C#COM服务器的接收器 我想注册一个带有Exchange接口的C++接收器,因此登记一个C应用程序的事件。,c#,c++,outlook,com,interop,C#,C++,Outlook,Com,Interop,C#应用程序是Outlook的外接程序,充当COM服务器,支持传入和传出接口。该服务器的客户端是包含下沉的C++应用程序,我也在开发。p> 我通过注册运行对象表上的ADIN(RoT),从C++应用程序中的Road检索指针,然后调用传入接口的方法,来获得COM服务器(ADIN)的传入接口。p> 当试图将C++接收器登记到AdIn的相关接口的ICONNECTURE点时,问题发生。p> 以下缩减代码显示了我的加载项(C#COM服务器): 接口MyInterface和_IEvents的.idl如下所示:

C#应用程序是Outlook的外接程序,充当COM服务器,支持传入和传出接口。该服务器的客户端是包含下沉的C++应用程序,我也在开发。p> 我通过注册运行对象表上的ADIN(RoT),从C++应用程序中的Road检索指针,然后调用传入接口的方法,来获得COM服务器(ADIN)的传入接口。p>

当试图将C++接收器登记到AdIn的相关接口的ICONNECTURE点时,问题发生。p> 以下缩减代码显示了我的加载项(C#COM服务器):

接口MyInterface和_IEvents的.idl如下所示:

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    uuid(a817e7a2-43fa-11d0-9e44-00aa00b6770a),
    dual,   
    pointer_default(unique)
]
interface IComponentRegistrar : IDispatch
{
    [id(1)] HRESULT Attach([in] BSTR bstrPath);
    [id(2)] HRESULT RegisterAll();
    [id(3)] HRESULT UnregisterAll();
    [id(4)] HRESULT GetComponents([out] SAFEARRAY(BSTR)* pbstrCLSIDs, [out] SAFEARRAY(BSTR)* pbstrDescriptions);
    [id(5)] HRESULT RegisterComponent([in] BSTR bstrCLSID);
    [id(6)] HRESULT UnregisterComponent([in] BSTR bstrCLSID);
};

[
    object,
    uuid(6C032E68-4DF7-49BE-9949-88F8AADD3D40),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IMyInterface : IDispatch
{
    [id(1)] void IncomingInterfaceMethod();
};

[
    uuid(D3E30009-BF30-4BFD-BF4D-88306D90CA0F),
    version(1.0),
    custom(a817e7a1-43fa-11d0-9e44-00aa00b6770a,"{43B9624D-0143-438F-A5B1-7CC09F733476}")
]
library MyComLib
{
    importlib("stdole2.tlb");
    [
        uuid(43B9624D-0143-438F-A5B1-7CC09F733476)      
    ]
    coclass CompReg
    {
        [default] interface IComponentRegistrar;
    };

    [
        uuid(D2A0BE8B-BB05-4472-9976-D17AD5EBDABD)      
    ]
    dispinterface _IEvents
    {
        properties:
        methods:
            [id(1)] void Event1();
    };

    [
        uuid(76ED50BC-5DE0-43DA-83FA-5CD44E88B481)
    ]
    coclass MyInterface
    {
        [default] interface IMyInterface;
        [default, source] dispinterface _IEvents;
    };
};
这在ATL项目中定义,并内置到.dll中并注册。这将在addin C#项目中引用

最后,C++ APP接收器头看起来像这样:

class MySink : public _IEvents
{
public:
    ...

    STDMETHOD_(ULONG, AddRef)()
    {
        InterlockedIncrement(&m_refCount);

        return m_refCount;
    }

    STDMETHOD_(ULONG, Release)()
    {
        InterlockedDecrement(&m_refCount);

        if (m_refCount == 0)
        {
            delete this;
            return 0;
        }

        return m_refCount;
    }

    STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject)
    {
        if (riid == IID_IUnknown)
        {
            *ppvObject = (IUnknown*)this;
            AddRef();
            return S_OK;
        }

        if ((riid == IID_IDispatch) || (riid == __uuidof(_IEvents)))
        {
            *ppvObject = (IDispatch*)this;
            AddRef();
            return S_OK;
        }

        return E_NOINTERFACE;
    }

    STDMETHOD(GetTypeInfoCount)(UINT* /*pctinfo*/)
    {
        return E_NOTIMPL;
    }

    STDMETHOD(GetTypeInfo)(UINT /*itinfo*/, LCID /*lcid*/, ITypeInfo** /*pptinfo*/)
    {
        return E_NOTIMPL;
    }

    STDMETHOD(GetIDsOfNames)(REFIID /*riid*/, LPOLESTR* /*rgszNames*/, UINT /*cNames*/, LCID /*lcid*/, DISPID* /*rgdispid*/)
    {
        return E_NOTIMPL;
    }

    STDMETHOD(Invoke)(
        DISPID dispidMember,
        REFIID /*riid*/,
        LCID /*lcid*/,
        WORD /*wFlags*/,
        DISPPARAMS* pdispparams,
        VARIANT* /*pvarResult*/,
        EXCEPINFO* /*pexcepinfo*/,
        UINT* /*puArgErr*/)
    {
        return m_eventCB(dispidMember, pdispparams);
    }

    bool SetupConnectionPoint(IMyInterface* myInterface);

private:
    bool CheckResult(HRESULT hr, std::wstring errMsg);

    ULONG m_refCount;
    EventCB m_eventCB;
    DWORD m_eventCookie = 0u;
    IConnectionPoint* m_connectionPoint = nullptr;
    IUnknown* m_ftm = nullptr;
};
以下是MySink的来源:

...

// myInterface is retrieved from ROT and then passed here    
bool MySink::SetupConnectionPoint(IMyInterface* myInterface)
{
    // Don't know if this is necessary
    CoCreateFreeThreadedMarshaler(this, &m_ftm);

    HRESULT hr;
    IConnectionPointContainer*  pIConnectionPointContainerTemp = nullptr;
    hr = myInterface->QueryInterface(IID_IConnectionPointContainer, (void**)&pIConnectionPointContainerTemp);


    if (!CheckResult(hr, L"Failed to retrieve ConnectionPointContainer") || !pIConnectionPointContainerTemp)
    {
        return false;
    }

    pIConnectionPointContainerTemp->FindConnectionPoint(__uuidof(_IEvents), &m_connectionPoint);
    pIConnectionPointContainerTemp->Release();
    pIConnectionPointContainerTemp = nullptr;

    if (m_connectionPoint)
    {
        m_connectionPoint->Advise(this, &m_eventCookie);
    }
    else
    {
        return false;
    }

    return true;
}

bool MySink::CheckResult(HRESULT hr, std::wstring errMsg)
{
    if (FAILED(hr))
    {
        // Used for logging
        _com_error comError(hr);

        return false;
    }

    return true;
}
MySink::SetupConnection()似乎正在使用填充的m_connectionPoint和对其调用的Advise()。在调试ADIN和调用C++应用程序中的InCopyTrimeMeMeDoEd()时,EVET1仍然是NULL,因此不被调用。我猜MySink和加载项之间的注册工作不正常,因此Event1始终为空。运行时可调用包装器可能有问题


<>我必须重构代码,因此可能有命名错误。

您可以考虑实现ATL或在客户端中,而不是创建自己的接收器。查看教程中的示例。感谢有用的教程
...

// myInterface is retrieved from ROT and then passed here    
bool MySink::SetupConnectionPoint(IMyInterface* myInterface)
{
    // Don't know if this is necessary
    CoCreateFreeThreadedMarshaler(this, &m_ftm);

    HRESULT hr;
    IConnectionPointContainer*  pIConnectionPointContainerTemp = nullptr;
    hr = myInterface->QueryInterface(IID_IConnectionPointContainer, (void**)&pIConnectionPointContainerTemp);


    if (!CheckResult(hr, L"Failed to retrieve ConnectionPointContainer") || !pIConnectionPointContainerTemp)
    {
        return false;
    }

    pIConnectionPointContainerTemp->FindConnectionPoint(__uuidof(_IEvents), &m_connectionPoint);
    pIConnectionPointContainerTemp->Release();
    pIConnectionPointContainerTemp = nullptr;

    if (m_connectionPoint)
    {
        m_connectionPoint->Advise(this, &m_eventCookie);
    }
    else
    {
        return false;
    }

    return true;
}

bool MySink::CheckResult(HRESULT hr, std::wstring errMsg)
{
    if (FAILED(hr))
    {
        // Used for logging
        _com_error comError(hr);

        return false;
    }

    return true;
}