Accessing Hidden VB Interfaces

The Microsoft KnowledgeBase article Q193018 in MSDN lists the problem that Visual C++
programs cannot access hidden Visual Basic interfaces that are defined with an
underscore ( _ ) as the first letter in the name, such as the Visual Basic
Collection interface declared in MSVBVM60.DLL.

This article will depict the simple solution for this
task of using VB hidden object interface in VC project. I will show how to
import VB Collection object from VB Control to VC application.

This is a common situation. For example, if you are
making an ActiveX control in VB , and this control uses the VB Collection object
in order to stor several items. There might be a situation in which you would
like to have a way to access this object from a VC application.

There are several steps to make things work:

The first step is to make ActiveX control. This example
shows a simple ActiveX control which has a collection of Cars. the cars
have a CarId which identifies them. The control keeps a VB Collection Object to
store all the Cars Id’s. We would like to get this Collection from VC
application.

The control has two interface functions

AddCar(car as Integer) which adds a car to
the collection

and Cars(ByRef cars as Variant), which reterns a
reference to the cars collection.

1) bulid the project in order to produce
CarControlProject.ocx, and register the control in your computer using
RegSvr32.exe utility.

2) Open new Dialog based VC application. and put this
Control on the dialog. Add member variable to your dialog which will be with
type CUserControl.

3) Now, we would like to get the collection of cars that
this control holds. This is tricky and requires several steps:

1) Find out what is the IID of the requested object. In
our example we would like to receive a pointer to _Collection object. Open the
OLE-COM viewer and display the information of all available interfaces. look for
the interface _Collection.

There are probably several _Collection interfaces. look
for the one which is declared as VisualBasic For Applications Component.

3) generate an .idl file for the object and run MIDL to
compile this interface.

Here there are no shortcuts. we have to write the
interface. However we do not have to do it from scratch. we can use information
retreived from the OLE-COM viewer.

Here is the .idl file that I wrote for _Collection
object. using the information from OLE-COM viewer. save this file as
Collection.idl

NOTE: The interface ID – IID must be as the one you saw
in the OLE-COM map viewer. Cut and Past the IID from the OLE-COM viewer tool to
avoid mistakes.

import "oaidl.idl";

import "ocidl.idl";
[
 object,
 // The uuid was taken from OLE-COM viewer.
 uuid(A4C46780-499F-101B-BB78-00AA00383CBB),
 helpcontext(0x000f7886),
 dual,
 pointer_default(unique)
]

 interface _Collection : IDispatch
 {
  [id(
   helpcontext(0x000f7903)]  HRESULT Item([in]
   VARIANT* Index, [out][retval] VARIANT *Item);

  [id(2), helpcontext(0x000f7901)]  HRESULT Add(
  [in] VARIANT* Item, [in, optional] VARIANT* Key,
  [in, optional] VARIANT* Before,
  [in, optional] VARIANT* After);

  [id(3), helpcontext(0x000f7902)]
  HRESULT Count([retval][out] long *count);

  [id(4), helpcontext(0x000f7904)]
  HRESULT Remove([in] VARIANT* Index);
 };

compile this file using MIDL compiler. The compiler will
generate the files which are needed in order to use this interface in our VC
application.

first Collection_i.c the definition of the IID of the
interface. – add it to the project, in order that the linker will find the IID
symbol.

and the Collection.h file. Header file for the
_Collection interface.

4) Now, we wish to invoke the Cars member of our Control.
This method will give us a refrence to the Connection object.

Pass the method a pointer to Variant object.

#include "Collection.h"

COleVariant vrCars;

HRESULT hr;

interface _Collection *ICol;

 m_myCar.Cars(&vrCars);

vrCars.ChangeType(VT_UNKNOWN);

5) Use QueryInterface to get The requested interface
pointer. In our case, a pointer to the _Colleciton interface

hr = vrCars.punkVal->QueryInterface(IID__Collection,
(void **) &ICol);

6) Use this pointer to access the Collection.

long l;

// Call the Collection count method
ICol->Count(&l);

for (long i=0;i < l ; i ++)
{
 // Get all the Items of the Collection.
 COleVariant vrIndex;

 COleVariant vrValue;

 vrIndex.ChangeType(VT_I4);

 vrIndex.lVal = i;

 vrValue.ChangeType(VT_BSTR);

 _bstr_t bstr(vrValue.bstrVal,true);

 m_listCars.AddString(bstr);
}

Downloads

Download demo project – 8 Kb

More by Author

Must Read