1

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

IInspectable
  • 46,945
  • 8
  • 85
  • 181
Paul
  • 5,524
  • 1
  • 22
  • 39
  • *"everything works as it should (apart from the queryinterface call"* - If a `QueryInterface` call fails, it returns a `NULL` pointer. And now you are dereferencing your `icpc` pointer, when calling `FindConnectionPoint`. – IInspectable Sep 08 '16 at 14:56
  • @IInspectable sorry if my wording is a bit off, the `queryinterface` seems to succeed (dwError equals ERROR_SUCCESS after the call) i have also checked for a nullptr to make sure, its not a nullptr – Paul Sep 08 '16 at 14:58
  • Why don't you [edit](http://stackoverflow.com/posts/39393303/edit) your question, so that it doesn't lie to use anymore? As an aside, your error handling is wrong. It is comparing against a constant, that isn't an `HRESULT` (`ERROR_SUCCESS`), and shouldn't be comparing for equality anyway. See [Error Handling in COM](https://msdn.microsoft.com/en-us/library/windows/desktop/ff485842.aspx) for a primer. – IInspectable Sep 08 '16 at 15:06
  • @IInspectable excuse me? i know you are trying to help but if you would read the whole passus: "apart from the queryinterface call i am using this exact code in other Projects too, working fine" you would notice that its more of a comprehension error on your side and not me "lying" – Paul Sep 08 '16 at 15:07
  • That sentence doesn't compile to make any sense. I stopped reading after *"apart from the queryinterface call"*. Don't you use punctuation where you live? – IInspectable Sep 08 '16 at 15:09
  • @IInspectable ... you notice using a punctuation mark at that point would alter the meaning completely? just because it would then mean what you thought it meant after stopping to read at half of the sentence? the code up until the findconnectionpoint call works absolutely fine, got it? Thanks for the link btw, S_OK equals ERROR_SUCCESS so that part works fine as is too – Paul Sep 08 '16 at 15:20
  • I see, so this is a capitalization bug then. You start a brand new sentence but decide to start it with a lower case letter (*"apart"*). Whatever, you still haven't grokked, why your error handling is wrong. – IInspectable Sep 08 '16 at 15:21
  • @IInspectable is this grammaroverflow? let´s let this rest... i notice what you are saying regarding the error handling but while you are correct the fact is that the numerical value of `S_OK` is the same as `ERROR_SUCCESS` so the comparison works out and is not related to the problem which caused me to open this question. – Paul Sep 08 '16 at 15:25
  • Do not compare for equality. Use `SUCCEEDED` and `FAILED` macros. – IInspectable Sep 08 '16 at 15:27
  • `ERROR_SUCCESS` only works because it happens to have the same numeric value as the correct constant for a general success code, `S_OK`; in this case, 0. No other COM error or status code has this property. Use the right constant anywhere now to avoid errors later (for instance, if you accidentally write `dwError == ERROR_INVALID_PARAMETER` instead of `dwError == E_INVALIDARG`). – andlabs Sep 08 '16 at 16:28

1 Answers1

3

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.
IInspectable
  • 46,945
  • 8
  • 85
  • 181