0

In my C++ program I use a COM class which is implemented in a VB6 COM DLL. Let's call this class CETicketRA. This class has a property AppliedPromotion of type IPositionPromotion. IPositionPromotion is an interface defined by the same VB6 COM DLL. It has various properties and methods which I try to access from C++.

Given the following code:

IDispatch* pETicketRA = NULL;
DISPPARAMS dispParams = {0};
VARIANT result;
VariantInit(&result);
// Left out: some code to set pETicketRA ...

OLECHAR* strAppliedPromotion = L"AppliedPromotion";
DISPID dispIDAppliedPromotion = -1;
HRESULT hr = pETicketRA->GetIDsOfNames(IID_NULL, &strAppliedPromotion, 1, LOCALE_SYSTEM_DEFAULT, &dispIDAppliedPromotion);
hr = pETicketRA->Invoke(dispIDAppliedPromotion, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &result, NULL, NULL);
IDispatch* pPromo = NULL;
hr = result.pdispVal->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>(&pPromo));
VariantClear(&result);

Now I try to read the property Foobar of IPositionPromotion:

OLECHAR* strFoobar = L"Foobar";
DISPID dispIDFoobar = -1;
hr = pPromo->GetIDsOfNames(IID_NULL, &strFoobar, 1, LOCALE_SYSTEM_DEFAULT, &dispIDFoobar);

Unfortunately the last call fails with DISP_E_UNKNOWNNAME.

Has anyone succeeded to call VB6 interface members from C++ (or C#)?

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Timo Kunze
  • 135
  • 1
  • 6
  • In C# you can do it VB6-style with `dynamic`. For C++, http://stackoverflow.com/q/11670175/11683 might help. – GSerg Jul 28 '16 at 18:15
  • Not sure if the COM regulations are tighter, but usually C++ mangles the names of functions causing dynamic errors when trying to access the object at runtime. _IF_ that is the case, be sure to `extern "C"` as required. – M4rc Jul 28 '16 at 18:52
  • @GSerg: I tried dynamic already, it does not work. But I found out something: In the VB6 COM DLL, in the classes that implement `IPositionPromotion`, the methods that implement the `IPositionPromotion` interface usually are declared as `Private`. They are named `IPositionPromotion_Foobar`. If I change them from `Private` to `Public`, I can call `IPositionPromotion_Foobar` on the `pPromo` object. But this is a quite ugly "solution". – Timo Kunze Jul 29 '16 at 19:21
  • @TimoKunze They are supposed to private, this is VB6's convention for implementing interfaces and event handlers. – GSerg Jul 29 '16 at 20:47

1 Answers1

0

VB6 uses explicit interface implementation. Methods of implemented interface do not become a part of the implementing object's public interface, and in order to call them you need to explicitly ask for the interface. You can ask IDispatch out of that interface later if you wish, but you need to query for the interface first, because IDispatch you get from the object itself and IDispatch you get from the interface implemented by this object will be different IDispatches.

So when you have:

' IInterface.cls
Public Sub Method()
End Sub
' Class1.cls
Implements IInterface

Private Sub IInterface_Method()
  MsgBox "!"
End Sub

and you want to create an instance of Class1 and call Method(), the following will not work:

' Complile-time error: method not found
Dim c As Class1
Set c = New Class1

c.Method
' Run-time error: Object does not support this property or method
Dim c As Object    ' IDispatch
Set c = New Class1 ' QueryInterface for IDispatch from Class1

c.Method

And the following will work:

Dim c As IInterface
Set c = New Class1

c.Method  ' Early binding
Dim c As IInterface
Set c = New Class1

Dim c_as_idispatch As Object   ' IDispatch
Set c_as_idispatch = c         ' QueryInterface for IDispatch from IInterface

c.Method  ' Late binding

Your C++ code is identical to the second non-working example above.

To fix it, first QueryInterface for IPositionPromotion, then query IDispatch off that.

GSerg
  • 76,472
  • 17
  • 159
  • 346
  • Got it working with a small adjustment, yeah! I declared the `IPositionPromotion` interface in C++, derived from `IDispatch`. I used OleView to get the IID of the interface, as the ProgID refers to the CLSID of the coclass. With this combination, I indeed can `QueryInterface` the `result.pdispVal` object for `IPositionPromotion`. Then I indeed can `QueryInterface` this one for `IDispatch`. This object does not know any `Foobar` method, but why should I use `IDispatch` when I can use the `IPositionPromotion` interface? I can use it to call `Foobar` and it works! Thanks a lot! – Timo Kunze Jul 30 '16 at 22:47