Search code examples
multithreadingvisual-c++mfcactivexmarshalling

Marshalling ActiveX through Global Interface Table


I have been trying to do a basic ActiveX component marshalling for across thread access. I do it through a Global Interface Table (GIT) . I have a simple MFC dialog to which I add an arbitrary AciveX control such as IDC_PDF. Inserting activeX control to MFC dialog in C++

After that I add the variable representing this control to the code. This effectively adds a pdf1.h and pdf1.cpp to the project. At initialization of the dialog inside OnInitDialog() I try to marshal the interface to this ActiveX component so that it could be used from another thread without STA apartment violation.

bool CLMC_mfcDlg::CreateMarshalledController()
{

    ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    CComPtr<IGlobalInterfaceTable> pGIT;

    // get pointer to GIT
    CoCreateInstance(CLSID_StdGlobalInterfaceTable,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IGlobalInterfaceTable,
        (void **)&pGIT);

    // get IID and IUnknown interface pointer
    REFIID iid = Pd_OCX_fControl.GetClsid();
    IUnknown* active_x_pointer = Pd_OCX_fControl.GetControlUnknown();

    // register interface inside the GIT
    if (active_x_pointer != NULL) {
        HRESULT hr = pGIT->RegisterInterfaceInGlobal(active_x_pointer, iid, &dwCookie);
        if (SUCCEEDED(hr))
        {
            // OK, wir haben das interface im GIT registriert
            assert(dwCookie != 0);
        }
        else
            dwCookie = 0;

        //pGIT->Release();
    }
    else
        dwCookie = 0;
    active_x_pointer->Release();
    return dwCookie!=0;
}

As a result the value of the dwCookie is set to 256, which though not 0, still feels like an error value. When I try to get the marshalled interface from another thread. The marshalled interface received is 0x0000.

bool CLMC_mfcDlg::FetchMarshalledController()
{
    HRESULT res = ::OleInitialize(NULL);

    switch (res)
    {
    case S_OK:
        break;
    case OLE_E_WRONGCOMPOBJ:
    case RPC_E_CHANGED_MODE:
        return false;
    }
    CComPtr<IGlobalInterfaceTable> pThreadGIT;
    CoCreateInstance(CLSID_StdGlobalInterfaceTable,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IGlobalInterfaceTable,
        (void **)&pThreadGIT);
    REFIID iid = Pd_OCX_fControl.GetClsid();
    pThreadGIT->GetInterfaceFromGlobal(
        dwCookie, iid, (void**)&pMarshalledOCX);


    pThreadGIT->RevokeInterfaceFromGlobal(dwCookie);
    return pMarshalledOCX != nullptr;
}

What am I doing wrong? I am working with a standard ActiveX, using standard marshalling patern. Anybody got this to work?


Solution

  • Aurora was correct. To get a proper IID you need to find the interface in registry using oleview.exe: oleview.exe

    you use the finding to define interface IID in your code:

    static REFIID const intf_id
            = { 0x5CD5C9C3, 0x0CD7, 0x453A,{ 0x8D, 0x27, 0xE3, 0xBB, 0x32, 0xB7, 0xEA, 0xFC } };
    

    you get the interface pointer for it like this:

    IUnknown * pUnknown = CBaldorOCXCard.GetControlUnknown();
    // get _DMintControllerCtrl interface pointer
    void* IMint = NULL;
    pUnknown->QueryInterface(intf_id, (void **)&IMint);
    

    The interface pointer and IID can now be used in marshaling.

    (The problem how you work with this interface pointer without a wrapper class:) Still looking for answer)