【问题标题】:Advise of Connection Point calls QueryInterface with IID_IMarshal建议连接点使用 IID_IMarshal 调用 QueryInterface
【发布时间】:2012-01-16 16:33:38
【问题描述】:

我正在尝试在现有 COM 组件中构建连接点。我从 CCmdTarget 派生类并在类声明和实现中调用 MFC 宏,如 MSDN 中所述。组件已正确构建、链接和运行。但是,当我调试客户端应用程序时,我看到以下问题:

客户端定位正确的组件,找到连接点容器和合适的连接点;但是 Advise 方法无法建立连接。 假定此 Advise 使用 IID__IAdHocPresenceEvents 调用 QueryInterface。 不明白为什么这会用 IID_IMarshal 调用 QueryInterface。 后来这成为在 ClientSink::OnAdHocPresenceQuery 没有收到事件的原因

所以,请帮助我解决此问题或提示在其他地方查找问题。

提前致谢, 霍沃


class ClientSink : public _IAdHocPresenceEvents
{
private:
DWORD       m_dwRefCount;
public:
ClientSink();
virtual ~CClientSink();

STDMETHODIMP OnAdHocPresenceQuery(int Result)
{
    CString strTemp ("OnAdHocPresenceQuery");
    AfxMessageBox(strTemp);
    return S_OK;
};

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
HRESULT hr = S_OK;

if (iid == IID_IUnknown)
{
    m_dwRefCount++;
    *ppvObject = (IUnknown *)this;
}
else if (iid == IID__IAdHocPresenceEvents)
{   
    m_dwRefCount++;
    *ppvObject = (_IAdHocPresenceEvents *)this;
}
else
{
    *ppvObject = NULL;
    hr = E_NOINTERFACE;
}
return hr;
}

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

ULONG STDMETHODCALLTYPE Release()
{
ULONG l;
l  = m_dwRefCount--;
if ( 0 == m_dwRefCount)
{
    delete this;
}
return l;
}

};




int SendRequest() 
{
CLSID clientCLSID;
if (FAILED(CLSIDFromProgID(A2BSTR("SMC.SMCLink"), &clientCLSID)))
{
    clientCLSID = SMC::CLSID_SMCLink;
}

LPUNKNOWN lpUnk;
SMC::ISMCLink* m_pSMCLink = NULL;

if (m_pSMCLink == NULL)
{
    if (GetActiveObject(clientCLSID, NULL, &lpUnk) == NOERROR)
    {
        hr = lpUnk->QueryInterface(SMC::IID_ISMCLink, (LPVOID*)&m_pSMCLink);
        lpUnk->Release();
    }
}

if(hr != S_OK)
{
    return -1;
}

DWORD                       dwAdvise = 0; //variable,shown here for completeness
IConnectionPoint            *pCntPoint = NULL;
IConnectionPointContainer   *pConnPtContainer = NULL;

//check if this interface supports connectible objects
hr = m_pSMCLink->QueryInterface(IID_IConnectionPointContainer,(void **)&pConnPtContainer);
if ( !SUCCEEDED(hr) )
{
    return hr;
}

// find the specific connection point
hr = pConnPtContainer->FindConnectionPoint(IID__IAdHocPresenceEvents, &pCntPoint);
if ( !SUCCEEDED(hr) )
{
    return hr;
}

//we are done with the connection point container interface
pConnPtContainer->Release();

IUnknown *pSinkUnk = NULL;
CSink *pSink = NULL;

pSink = new CSink;
if ( NULL == pSink )
{
      return E_FAIL;
}

//Get the pointer to CSink's IUnknown pointer
hr = pSink->QueryInterface (IID_IUnknown,(void **)&pSinkUnk);
if ( !SUCCEEDED(hr) )
{
    return hr;
}

// It is assumed that this should call the QueryInterface with IID__IAdHocPresenceEvents
// Do not understand why this calls the QueryInterface with IID_IMarshal
// Later this becomes reason for not getting event at ClientSink::OnAdHocPresenceQuery
hr = pCntPoint->Advise(pSinkUnk, &dwAdvise);
if ( !SUCCEEDED(hr) )
{
    return hr;
}

hr = m_pSMCLink->RequestService(BSTR("hov@moco"));


pCntPoint->Unadvise(dwAdvise); //disconnect from server
pCntPoint->Release();

return hr;
}



[ 
helpstring("Interface to control My Product"),
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
dual,
oleautomation
]
interface ISMCLink : IDispatch
{
// ...
HRESULT RequestService([in] BSTR user);
// ...
};

//  Primary dispatch interface for My Component
[ uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) ]
dispinterface IDispSMCLink
{
interface ISMCLink;
};

[
helpstring("ISMCLink2, Interface to access My Product"),
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
dual,
oleautomation
]
interface ISMCLink2 : ISMCLink
{
//..
};



[ uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), version(1.0) ]
library SMC
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
    uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
    helpstring("_IAdHocPresenceEvents Interface")
]
interface _IAdHocPresenceEvents : IUnknown
{
    [id(1), helpstring("method OnAdHocPresenceQuery")] HRESULT OnAdHocPresenceQuery(int Result);
};

#include "ISMCLink.idl"

[ uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) ]
coclass SMCLink
{
    dispinterface IDispSMCLink;
    [default] interface ISMCLink;
    interface ISMCLink2;
    [default, source] interface _IAdHocPresenceEvents;
};
};


class SMCLink : public CCmdTarget
{
protected:

DECLARE_MESSAGE_MAP()
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()

// Connection point for ISMCLink interface
BEGIN_CONNECTION_PART(SMCLink, AdHocPresenceEvents)
    CONNECTION_IID(IID__IAdHocPresenceEvents)
END_CONNECTION_PART(AdHocPresenceEvents)

DECLARE_CONNECTION_MAP()

public:
SMCLink(void);
virtual ~SMCLink(void);

// to be OLE creatable, it must be DYNCREATE and OLECREATE
DECLARE_DYNCREATE(SMCLink)
DECLARE_OLECREATE(SMCLink)

// Generated OLE dispatch map functions
//{{AFX_DISPATCH(SMCLink)
afx_msg HRESULT RequestAdHocPresence(BSTR sipAddr);

//}}AFX_DISPATCH

BEGIN_DUAL_INTERFACE_PART(DualSMCLink, ISMCLink)
//..
    STDMETHOD(RequestService)(THIS_ BSTR user);
END_DUAL_INTERFACE_PART(DualSMCLink)
};



//..

BEGIN_MESSAGE_MAP(SMCLink, CCmdTarget)
//{{AFX_MSG_MAP(CAutoProxy)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

IMPLEMENT_DYNCREATE(SMCLink, CCmdTarget)

BEGIN_DISPATCH_MAP(SMCLink, CCmdTarget)
//{{AFX_DISPATCH_MAP(SMCLink)
//.. 
DISP_FUNCTION(SMCLink, "RequestService", RequestService, VT_ERROR, VTS_BSTR)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()


BEGIN_INTERFACE_MAP(SMCLink, CCmdTarget)
    INTERFACE_PART(SMCLink, IID_ISMCLink, DualSMCLink)
    INTERFACE_PART(SMCLink, IID_ISMCLink2, DualSMCLink)
    INTERFACE_PART(SMCLink, IID_IConnectionPointContainer, ConnPtContainer)
    END_INTERFACE_MAP()

BEGIN_CONNECTION_MAP(SMCLink, CCmdTarget)
    CONNECTION_PART(SMCLink, IID__IAdHocPresenceEvents, AdHocPresenceEvents)
END_CONNECTION_MAP()

SMCLink::SMCLink(void)
{
    // enable this object for OLE automation
    EnableAutomation();
    // enable this object for connection points
    EnableConnections();

}

//..

afx_msg HRESULT SMCLink::RequestService(BSTR sipAddr)
{
    HRESULT hr = E_FAIL;

int status = 1;
const CPtrArray* pConnections = m_xAdHocPresenceEvents.GetConnections ();
ASSERT (pConnections != NULL);
int nConnections = pConnections->GetSize ();
if (nConnections) {
    for (int i=0; i<nConnections; i++)
    {
        _IAdHocPresenceEvents* pInterface = (_IAdHocPresenceEvents*) (pConnections->GetAt (i));
        ASSERT (pInterface != NULL);

        // Outgoing!
        hr = pInterface->OnAdHocPresenceQuery (status);
    }
}
return hr;
}

// delegate standard IDispatch methods to MFC IDispatch implementation
DELEGATE_DUAL_INTERFACE(SMCLink, DualSMCLink)

STDMETHODIMP SMCLink::XDualSMCLink::RequestService(BSTR user)
{
    METHOD_PROLOGUE(SMCLink, DualSMCLink)

    return pThis->RequestService(user);
}

//..

【问题讨论】:

    标签: c++ com mfc connection


    【解决方案1】:

    IMarshal 被查询,因为 COM 需要编组进程之间的调用。虽然您显然可以自己实现接口,但没有必要为此烦恼。相反,请确保您的接口与 OLE 自动化兼容,并且在类型库上并且类型库已注册(您可以使用 COM/OLE Viewer 工具检查这一点。COM 将为您提供自动代理/存根对,并且不需要IMarshal 已实现。

    【讨论】:

    • 如何使界面与 OLE 自动化兼容?
    • 基本上你已经有这种方式了:[ ... oleautomation] interface ISMCLink2 : ISMCLink。除了使用真实方法进行更新外,还要注意可能出现的 IDL 编译器警告。
    • 我在我的界面声明中添加了 oleautomation。但问题依然存在。 [ uuid(715DFAA6-ED09-4e02-A4D4-820B11AE8324), helpstring("_IAdHocPresenceEvents 接口"), oleautomation ] interface _IAdHocPresenceEvents : IUnknown { [id(1), helpstring("方法 OnAdHocPresenceQuery")] HRESULT OnAdHocPresenceQuery(LONG Result); };
    • 另外,当 Outgoing interface 尝试调用方法 hr = pInterface->OnAdHocPresenceQuery (status);我看到错误:0xc0000005 “0x 处的指令
    • 您通常为传出事件接口声明dispinterface。 Visual Studio 将能够为您生成一个包装器(通过 IDE)来引发事件。或者以其他方式,使其至少派生自IDispatch。我现在不知道问题到底出在哪里,但调试器应该很清楚,你肯定做错了什么(也许又是一件小事)。
    猜你喜欢
    • 1970-01-01
    • 2011-11-05
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    • 2013-06-22
    • 2016-04-08
    • 2012-06-12
    相关资源
    最近更新 更多