Как проверить, поддерживает ли контейнер несколько соединений? - PullRequest
1 голос
/ 27 января 2009
  • Реализован класс Sink - для получения уведомлений о событиях от COM-сервера
  • Интерфейс событий происходит от IDispatch

У меня проблема, из-за которой IConnectionPoint :: Advise вызов возвращает E_NOTIMPL . Это может быть связано с тем, что точка подключения допускает только одно подключение - MSDN .

Примечание:

  • COM-сервер отключен
  • Чистая реализация C ++

EDIT:

S8.tlh : C ++ исходный эквивалент библиотеки типов Win32 S8.tlb:

struct __declspec(uuid("090910c3-28c3-45fe-861d-edcf11aa9788"))
IS8SimulationEvents : IDispatch
{

    // Methods:
    HRESULT S8SimulationReset ( );
    HRESULT S8SimulationEndRun ( );
    HRESULT S8SimulationCustomEvent (
        BSTR * TextInfo );
    HRESULT S8SimulationOpened ( );
    HRESULT S8SimulationEndTrial ( );
    HRESULT S8SimulationOEMEvent (
        BSTR * TextInfo );
    HRESULT S8SimulationReadyToClose ( );
    HRESULT S8SimulationUserMessage (
        long * Answer,
        BSTR * TextMsg,
        long ValidAnswers );
};

Реализация Class Sink - для обработки уведомлений о событиях:

class Sink : public IS8SimulationEvents
{
public:
Sink(){
    m_dwRefCount = 0;
};
~Sink(){};
/*
* IS8SimulationEvent interface functions
*/
HRESULT S8SimulationEndTrial()
{
    cout << "Simulation complete." << endl;
    return S_OK;;
};

HRESULT S8SimulationOpened()
{
    cout << "Simulation open." << endl;
    return S_OK;
};

HRESULT S8SimulationReadyToClose()
{
    cout << "Simulation ready to close" << endl;
    return S_OK;
};

ULONG STDMETHODCALLTYPE AddRef()
{
    m_dwRefCount++;
    return m_dwRefCount;
};

ULONG STDMETHODCALLTYPE Release()
{
    ULONG l;
    l = m_dwRefCount--;

    if (0 == m_dwRefCount)
    {
        delete this;
    }

    return m_dwRefCount;
};

HRESULT STDMETHODCALLTYPE QueryInterface(
                                        REFIID iid ,
                                        void **ppvObject)
{
    m_dwRefCount++;
    *ppvObject = (void *)this;
    return S_OK;
};

HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo)
{
    return E_NOTIMPL;
};

HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
                                        REFIID riid,
                                        LPOLESTR *rgszNames,
                                        UINT cNames,
                                        LCID lcid,
                                        DISPID *rgDispId)
{
    return E_NOTIMPL;
};

HRESULT STDMETHODCALLTYPE GetTypeInfo(
                                    unsigned int iTInfo,
                                    LCID lcid,
                                    ITypeInfo FAR* FAR* ppTInfo)
{
    return E_NOTIMPL;
};

HRESULT STDMETHODCALLTYPE Invoke(
                                DISPID dispIdMember,
                                REFIID riid,
                                LCID lcid,
                                WORD wFlags,
                                DISPPARAMS FAR* pDispParams,
                                VARIANT FAR* pVarResult,
                                EXCEPINFO FAR* pExcepInfo,
                                unsigned int FAR* puArgErr)
{
    HRESULT hresult = S_OK;
    if (pDispParams)
    {
        switch (dispIdMember) {
        case 1:
            return S8SimulationEndTrial();
        case 2:
            return S8SimulationOpened();
        case 3:
            return S8SimulationReadyToClose();
        default:
            return E_NOTIMPL;
        }

    }
    return E_NOTIMPL;
}
private:
    DWORD m_dwRefCount;
public:
void SetupConnectionPoint (IS8Simulation *pis8)
{

    HRESULT hresult;
    IConnectionPointContainer *pContainer = NULL;
    IConnectionPoint *pConnection = NULL;
    IUnknown *pSinkUnk = NULL;
    Sink *pSink = NULL;
    DWORD dwAdvise;

    dwAdvise = 0;

    hresult = pis8->QueryInterface(
                        __uuidof(IConnectionPointContainer),
                        (void **) &pContainer);

    if (SUCCEEDED(hresult))
    {
        cout << "IConnectionPointContainer inteface supported." << endl;
    } else {
        cerr << "Error: No such interface supported." << endl;
        exit (hresult);
    }

                                    __uuidof(IS8SimulationEvents),
                                    &pConnection); 

    switch (HRESULT_CODE(hresult)) {
        case NOERROR:
            cout << "Obtained valid interface pointer." << endl;
            break;
        case E_POINTER:
            cerr << "Invalid pointer: the address is not valid." << endl;
            exit (hresult);
            break;
        case CONNECT_E_NOCONNECTION:
            cerr << "This connectable object not support the "
                    "outgoing interface specified." << endl;
            exit (hresult);
            break;
        case E_UNEXPECTED:
        default:
            cerr << "Catastrophic failure." << endl;
            exit (hresult);
            break;
    }

    pContainer->Release();


    hresult = pSink->QueryInterface(
                            __uuidof(IUnknown),
                            (void **)&pSinkUnk);

    if (FAILED(hresult))
    {
        exit (EXIT_FAILURE);
    }

    hresult = pConnection->Advise(
                            pSinkUnk,
                            &dwAdvise);

    switch (HRESULT_CODE(hresult)) {
        case NOERROR:
            cout << "The connection has been established and "
                    "*dwAdvise has the connection token." << endl;
            break;
        case E_POINTER:
            cerr << "Invalid pointer: "
                    "the value pSinkUnk or dwAdvise is not valid." << endl;
            exit (hresult);
            break;
        case CONNECT_E_ADVISELIMIT:
            cerr << "The connection point has already reached "
                    "its limit of connections and cannot accept "
                    "any more." << endl;
            exit (hresult);
            break;
        case CONNECT_E_CANNOTCONNECT:
            cerr << "The sink does not support the interface "
                    "required by this connection point." << endl;
            exit (hresult);
            break;
        case E_NOTIMPL:
            break;
            case E_UNEXPECTED:
            default:
        cerr << "Catastrophic failure." << endl;
        exit (hresult);
        break;
    }
    return;
}
};

EDIT:

Реализация IUnknown Интерфейс в Раковина Класс

ULONG STDMETHODCALLTYPE AddRef()
{
    m_dwRefCount++;
    return m_dwRefCount;
};

ULONG STDMETHODCALLTYPE Release()
{
    ULONG l;
    l = m_dwRefCount--;

    if (0 == m_dwRefCount)
    {
        delete this;
    }

    return m_dwRefCount;
};

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
    m_dwRefCount++;
    *ppvObject = (void *)this;
    return S_OK;
};

Вопрос:

  • Как проверить, поддерживает ли контейнер несколько соединений?
  • Если требуется дополнительная информация, пожалуйста, прокомментируйте соответственно.

Ответы [ 4 ]

1 голос
/ 27 января 2009

Пожалуйста, прочитайте статью MSDN снова.

 A connection point that allows only one interface
 can return E_NOTIMPL FROM the IConnectionPoint::EnumConnections method
EnumConnections : E_NOTIMPL 
The connection point does not support enumeration.

IConnectionPoint :: Для ответа требуется совет

CONNECT_E_ADVISELIMIT

когда точка подключения уже достигла своего предела подключений и больше не может принимать.

-

Michael

0 голосов
/ 01 февраля 2009

Решено:

  • Использование чистого C ++
  • Нет ATL

При следующей реализации из QI :

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
    if (iid == __uuidof(IUnknown) || iid == __uuidof(IS8SimulationEvents))
    {
        *ppvObject = (IS8SimulationEvents*)this;
    } else {
        *ppvObject = NULL;
        return E_NOINTERFACE;
    }
    m_dwRefCount++;
    return S_OK;
};
0 голосов
/ 30 января 2009

COM-библиотека вызывает QI для стольких интерфейсов, как IUnknown, IMarshall и т. Д., Когда вызывается Advise call in.

Как указал Майкл в отношении статьи MSDN, в нем говорится, что он возвращает E_NOTIMPL только для API EnumConnections, а не для Advise. Я подозреваю, что QI вернул E_NOTIMPL. Так что попробуйте отследить Advise API. И вы узнаете о неудаче QI.

0 голосов
/ 29 января 2009

AtlAdvise должен заставить точку соединения вызывать QI на приемнике событий. Вы не можете быть уверены, ЧТО или сколько раз это может вызвать QI.

Предложение. Чтобы определить правильный интерфейс события, обратитесь к чему-то похожему в разделе событий.

void GuidToString(PTCHAR s, LPGUID piid )
{
_stprintf(s, _T("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
    piid->Data1, piid->Data2,
    piid->Data3,
    piid->Data4[0], piid->Data4[1],
    piid->Data4[2], piid->Data4[3],
    piid->Data4[4], piid->Data4[5],
    piid->Data4[6], piid->Data4[7]);
    // Outputdebugstr (s)
}

ТАКЖЕ приемник событий QueryInterface должен делать что-то вроде

if (iid == IID_IUnknown || iid == IID_AppEvents)
     *ppObj = (AppEvents*)this;

Таким образом, он возвращает только правильный интерфейс.

...