Нарушение доступа к записи памяти при вызове FindConnectionPoint

Я пытаюсь подписаться на события MBN. Вот мой код:

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;
}
}
}

Так как документации (imho) немного не хватает, я сосредоточился на некоторых примерах кода, которые я нашел в сети. пока я не позвоню FindConnectionPoint все работает как надо. При звонке FindConnectionPoint я получаю запись Access Violation в память, так что я думаю, что проблема с моим IConnectionPoint указатель, который объявлен как в нескольких примерах кода, которые я нашел.

Надеюсь, кто-то с немного большим надзором сможет помочь с этим. заранее спасибо

1

Решение

Код, извлекающий IConnectionPointContainer неправильно:

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

Этот код возвращает IMbnInterfaceManager интерфейс, но интерпретирует его как IConnectionPointContainer, Когда он продолжает выполняться icpc->FindConnectionPoint это действительно вызывает случайный метод интерфейса IMbnInterfaceManager1.

Чтобы решить эту проблему, код должен быть изменен на это:

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

Еще проще и безопаснее пользоваться IID_PPV_ARGS макро. Он выводит идентификатор интерфейса, соответствующий типу указателя:

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

1 Это не совсем случайно. FindConnectionPoint это вторая запись в IConnectionPointContainer интерфейс, то есть пятая запись в V-таблице (с учетом 3 IUnknown методы). То же самое место в IMbnInterfaceManager занят GetInterfaces метод. Его первый аргумент является параметром [out], поэтому он объясняет нарушение прав доступа при записи.

3

Другие решения

Других решений пока нет …