Я пытаюсь подписаться на события 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
указатель, который объявлен как в нескольких примерах кода, которые я нашел.
Надеюсь, кто-то с немного большим надзором сможет помочь с этим. заранее спасибо
Код, извлекающий 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
это действительно вызывает случайный метод интерфейса IMbnInterfaceManager
1.
Чтобы решить эту проблему, код должен быть изменен на это:
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], поэтому он объясняет нарушение прав доступа при записи.
Других решений пока нет …