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);
}

Comments
How to return Variant data as array from activex dll/exe to VC client
Posted by Legacy on 01/09/2002 12:00amOriginally posted by: ashutosh
Replyproblem with _recordset like
Posted by Legacy on 01/02/2002 12:00amOriginally posted by: Antonio Ramirez
ReplyProblem with Add !!!
Posted by Legacy on 05/18/2001 12:00amOriginally posted by: Daren
Your walk though has been very useful , but alas I still have a problem that you may be able to help me with ....
I am currently unable to Add items into the collection from VC++ !
I am creating a COleVariant vrItem and giving it an int and defining 3 COleVariants as VT_EMPTY , and passing all 3 into the collections ->Add method ... but alas the item is not being appened to the collection .... and no error surfaces either ...
Please could someone help me ...
MTIA Daren 'Well and Truely Stuck'
Reply