0
votes

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?

1
RegisterInterfaceInGlobal() and GetInterfaceFromGlobal() require an Interface ID (IID). However, Pd_OCX_fControl.GetClsid() looks like a function to retrieve the class ID (CLSID).Aurora
256 is normal. Actually marshaling the interface requires the component to help out, it needs to create a registry key that tells COM how it should be done. A subkey of the HKLM\Software\Wow6432Node\Classes\Interface key, named with the IID of the interface. ActiveX controls rarely do this, they expect to only ever be usable and actually used on the UI thread. Never ignore the return value of these calls, they tell you why they failed.Hans Passant
Thanks, Aurora, Hans. Actually calling from the marshaled interface from GIT table ( GetInterfaceFromGlobal) returns E_UNEXPECTED Catastrophic failure. Aurora, I read that CLSID and REFIID are actually the same. But you seem to be right. How do I get a REFIID or GUID from a standard ActiveX installed in the system?user3070144
@user3070144 You'll need to look for the IID in the registry, or use a tool, such as oleview, which lists all installed controls.Aurora
Guys (Aurora), I did use oleview.ext to find out the Interface IID, and can now both register and retrieve the marshaled interface. However, since ActiveX has been provided by a third party, I don't know how to invoke any functions on it. All I have is an MFC wrapper class with wrapper method callingInvokeHelper() callls inside. How can I use it to help me execute methods on the marshaled interface? It can't be true that no one has not tried to marshal some third party ActiveX controls?!!user3070144

1 Answers

0
votes

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)