Paul Paul - 2 months ago 12
C++ Question

Access violation writing memory when calling FindConnectionPoint

I am trying to subscribe to MBN Events. Here is my code:

void subscribeToMbnEvents()
{

dwError = CoInitializeEx(NULL, COINIT_MULTITHREADED);
SAFEARRAY* mbnInterfaces;
CComPtr<IMbnInterfaceManager> intMgr = NULL;
dwError = CoCreateInstance(CLSID_MbnInterfaceManager, NULL, CLSCTX_ALL, IID_IMbnInterfaceManager, (void**)&intMgr);
if (dwError != ERROR_SUCCESS)
{
CoUninitialize();
std::cout << getTimeStamp() << " failed to initialize IMbnInterfaceManager \n";
}

dwError = intMgr->GetInterfaces(&mbnInterfaces);
if (dwError != ERROR_SUCCESS)
{
CoUninitialize();
std::cout << getTimeStamp() << " failed to get MBN Interfaces \n";
}

if (dwError == ERROR_SUCCESS)
{
LONG indexOfFirstMBNInterface;
dwError = SafeArrayGetLBound(mbnInterfaces, 1, &indexOfFirstMBNInterface);
if (dwError != ERROR_SUCCESS)
{
std::cout << getTimeStamp() << " failed to get first index of MBN Interface \n";
}

CComPtr<IMbnInterface> MbnInt = NULL;
dwError = SafeArrayGetElement(mbnInterfaces, &indexOfFirstMBNInterface, (void*)(&MbnInt));
if (dwError != ERROR_SUCCESS)
{
std::cout << getTimeStamp() << " failed to get MBN Interface \n";
}

IConnectionPointContainer* icpc;
dwError = intMgr->QueryInterface(IID_IMbnInterfaceManager, (void**)&icpc);
if (dwError != ERROR_SUCCESS)
{
std::cout << "Error querying interface" << std::endl;
}

IConnectionPoint *icp;

dwError = icpc->FindConnectionPoint(IID_IMbnInterfaceEvents, &icp);
if (dwError != ERROR_SUCCESS)
{
std::cout << "Error finding connection point" << std::endl;
}
}
}


Since the documentation is (imho) a Little bit lacking i oriented myself at some code samples i found on the net. up until i call
FindConnectionPoint
everything works as it should. When calling
FindConnectionPoint
i get an Access Violation writing to Memory so i guess the Problem is with my
IConnectionPoint
pointer which is declared as in multiple code examples i found.

Hopefully someone with a Little bit more oversight is able to help with this. Thanks in advance

Answer

The code retrieving the IConnectionPointContainer is wrong:

IConnectionPointContainer* icpc;
dwError = intMgr->QueryInterface(IID_IMbnInterfaceManager, (void**)&icpc);
//                               ^^^^^^^^^^^^^^^^^^^^^^^^ wrong interface ID
if (dwError != ERROR_SUCCESS) 
{ 
    std::cout << "Error querying interface" << std::endl; 
}

This code returns an IMbnInterfaceManager interface, but reinterprets it as an IConnectionPointContainer. When it continues to execute icpc->FindConnectionPoint it really is calling a random interface method of IMbnInterfaceManager1.

To address this issue, the code needs to be changed to this:

IConnectionPointContainer* icpc = nullptr;
HRESULT hr = intMgr->QueryInterface(IID_ConnectionPointContainer, (void**)&icpc);
if (FAILED(hr)) 
{ 
    std::cout << "Error querying interface" << std::endl; 
}

It's easier and safer yet to use the IID_PPV_ARGS macro. It deduces the interface ID that matches the pointer type:

HRESULT hr = intMgr->QueryInterface(IID_PPV_ARGS(&icpc));


1 It's not entirely random. FindConnectionPoint is the second entry in the IConnectionPointContainer interface, i.e. the fifth entry in the v-table (accounting for the 3 IUnknown methods). The same spot in the IMbnInterfaceManager is occupied by the GetInterfaces method. It's first argument is an [out] parameter, so that explains the access violation on write.