Search code examples
c++vb.netcom

How to get derived interface without having a property/function that returns it (OLE/COM)


I'm interfacing with a VB application using a C++ client code. I'm totally a novice in this (I'm just a Chemical Engineer), so please excuse me if the question is dumb.

So the following code in VB is required to access "BackDoor" interface, I can get all other interfaces because I follow the hierarchy (like strm = hyApp.ActiveDocument.Flowsheet.Streams.Item(strmName)

But as you can see in below code, the BackDoor interface was equaled to ProcessStream interface!! I don't understand this and don't know how to implement in in C++... Could you please help?

Code in VB:

Function GetMassExergy(strmName As String) As Double

GetMassExergy = EmptyValue_enum.HEmpty 'initialize to empty

Dim strm As ProcessStream

Dim bd As BackDoor

Dim corrNamesVar As TextFlexVariable

Dim corrNames() As String

Dim i As Integer

Dim exergMoniker As String

Dim exerg As RealVariable

Dim Bval As Double

strm = hyApp.ActiveDocument.Flowsheet.Streams.Item(strmName)

bd = strm

corrNamesVar = bd.BackDoorTextVariable("HysysCorrelation.300.[]:Name.0").Variable

corrNames = corrNamesVar.Values

For i = 0 To corrNames.Count - 1

If corrNames(i) = "Mass Exergy" Then

Exit For

End If

Next i

If i = corrNames.Count Then

'failed to find Mass Exergy Correlation

Exit Function

End If

exergMoniker = String.Format("HysysCorrelation.300.{0}:ExtraData.550.0", i)

exerg = bd.BackDoorVariable(exergMoniker).Variable

Bval = exerg.GetValue("kJ/kg")

GetMassExergy = Bval

End Function 

Code in C++ :

 void ConnectToHYSYS::GetBackDoor() {
//HyStream is already acquired using Hierarchy 
IDispatch* hyStream;
// Try to Query BackDoor from hyCase interface
    HRESULT hr = hyStream->QueryInterface(__uuidof(hyBackDoor), (void**)&hyBackDoorDisp);

//Last hr returns S_OK
    if (SUCCEEDED(hr))
    {
        cout << "Got the BackDoor safely" << endl;
        //Get BackDoor Text Variable, 

            VARIANT result;
            VariantInit(&result);
// Try to Get a property from BackDoor interface (to make sure that it returned //an actual interface)
            hr = COMMethod(DISPATCH_PROPERTYGET, &result, hyBackDoorDisp, L"BackDoorTextVariable", 1, "HysysCorrelation.300.[]:Name.0");
            CheckForHr(hr);
            BackDoorTextVariable = result.pdispVal;
            if (SUCCEEDED(hr))
            {
                cout << "Got the BackDoor Text Variable safely" << endl;

            }

            if (FAILED(hr)) {
                cout << "Couldnt get the BackDoor Text Variable" << endl;

            }
    }

        if (FAILED(hr)) {
            cout << "Couldnt get the BackDoor" << endl;
        }

}

The following is COMMethod that I use to access properties inside interfaces (it works properly with all other interfaces)

    HRESULT ConnectToHYSYS::COMMethod(int nType, VARIANT * pvResult, IDispatch * pDisp, LPOLESTR ptName, int cArgs...)
{
    if (!pDisp) return E_FAIL;

    va_list marker;
    va_start(marker, cArgs);

    DISPPARAMS dp = { NULL, NULL, 0, 0 };
    DISPID dispidNamed = DISPID_PROPERTYPUT;
    DISPID dispID;
    char szName[200];


    // Convert down to ANSI
    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);

    // Get DISPID for name passed...
    HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
    if (FAILED(hr)) {
        return hr;
    }
    // Allocate memory for arguments...
    VARIANT * pArgs = new VARIANT[cArgs + 1];
    // Extract arguments...
    for (int i = 0; i < cArgs; i++) {
        pArgs[i] = va_arg(marker, VARIANT);
    }

    // Build DISPPARAMS
    dp.cArgs = cArgs;
    dp.rgvarg = pArgs;

    // Handle special-case for property-puts!
    if (nType & DISPATCH_PROPERTYPUT) {
        dp.cNamedArgs = 1;
        dp.rgdispidNamedArgs = &dispidNamed;
    }

    // Make the call!
    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);
    if (FAILED(hr)) {
        return hr;
    }

    // End variable-argument section...
    va_end(marker);
    delete[] pArgs;
    return hr;
}

The line where I make the call is the only one that returns an error "0x80020008 Bad variable type"... I mean last hr line I wrote in COMMethod "hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);"


Solution

  • Both Mr. Igor and Mr. Acelent answers were successful (Sorry don't know how to accept a comment as an answer from Mr. Igor so I will just copy it here and accept it as an answer for anyone else facing the same problem.

    pArgs[i] = va_arg(marker, VARIANT); This exhibits undefined behavior, as the actual argument you pass to COMMethod is not in fact a VARIANT: COMMethod(..., 1, "HysysCorrelation.300.[]:Name.0"); – Igor Tandetnik

    Thank you everyone..