How does one determine that an interface is attributed with the 'source' IDL attribute, that is, that it is an event interface? Of course, one could do a text comparison search on all the interface names in a Type Library looking for the 'Events' string in an interface name, such as 'Events' found in DMSFlexGridEvents, which is interface index # 27 in the MSFlexGridLib, but that somehow doesn't seem like a high quality solution. I'm aware that the Type Library interfaces contain methods to accomplish this, but they simply don't work, or there is no adequate documentation to describe how they can be made to work.
For example, the ITypeInfo interface contains the GetImplTypeFlags method which should return an enum as below...
HRESULT ITypeInfo::GetImplTypeFlags
(
unsigned int index,
int* pImplTypeFlags
);
Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface or base interface in a type description.
Parameters
index Index of the implemented interface or base interface for which to get the flags.
pImplTypeFlags On return, pointer to the IMPLTYPEFLAGS enumeration.
And the IMPLTYPEFLAGS enumeration is as follows...
IMPLTYPEFLAGS
Defined as follows:
#define IMPLTYPEFLAG_FDEFAULT 0x1
#define IMPLTYPEFLAG_FSOURCE 0x2
#define IMPLTYPEFLAG_FRESTRICTED 0x4
#define IMPLTYPEFLAG_FDEFAULTVTABLE 0x800
Value Description
IMPLTYPEFLAG_FDEFAULT The interface or dispinterface represents the default for the source or sink.
IMPLTYPEFLAG_FSOURCE This member of a coclass is called rather than implemented.
IMPLTYPEFLAG_FRESTRICTED The member should not be displayed or programmable by users.
IMPLTYPEFLAG_FDEFAULTVTABLE Sinks receive events through the VTBL.
The IMPLTYPEFLAG_FSOURCE is exactly what I am looking for, but there is no documented way to retrieve it. Well, perhaps I should rephrase that. There is no documented way to retrieve it that works. So I guess what I am asking for is the undocumented way to retrieve it that works, because I'm quite aware that both Jose's and the PowerBASIC COM Browsers retrieve this info.
If one were to simply go by Microsoft's documentation to retrieve this info (which is how I routinely do things) one could write a program such as this....
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
#include <cstdio>
const IID LIBID_Component = {0x5E9E78A0,0x531B,0x11CF,{0x91,0xF6,0xC2,0x86,0x3C,0x38,0x5E,0x30}}; //MSFlexGridLib 1, 0
int main(void)
{
BSTR strLibName,strInterfaceName;
ITypeInfo* pTypeInfo=NULL;
TYPEATTR* pTypeAttr=NULL;
ITypeLib* pTypeLib=NULL;
HREFTYPE pRefType=NULL;
int pImplTypeFlags=0;
int iTypeInfoCount=0;
TYPEKIND pKind;
HRESULT hr;
CoInitialize(NULL);
hr=LoadRegTypeLib(LIBID_Component,1,0,0,&pTypeLib); //Load MSFlexGridLib
if(SUCCEEDED(hr))
{
hr=pTypeLib->GetDocumentation(-1,&strLibName,NULL,NULL,NULL); //Get Name Of Lib
wprintf(L"strLibName = %s\n",strLibName);
SysFreeString(strLibName);
hr=pTypeLib->GetTypeInfoType(27,&pKind); //Get pKind for index 27, i.e., DMSFlexGridEvents
printf("pKind = %u\n",pKind);
if(pKind==4)
printf("pKind = TKIND_DISPATCH\n");
hr=pTypeLib->GetDocumentation(27,&strInterfaceName,NULL,NULL,NULL); //Get Name of index 27, i.e., DMSFlexGridEvents
wprintf(L"strInterfaceName = %s\n",strInterfaceName);
SysFreeString(strInterfaceName);
hr=pTypeLib->GetTypeInfo(27,&pTypeInfo); //Get ITypeInfo* for index 27, i.e., DMSFlexGridEvents
if(SUCCEEDED(hr))
{
hr=pTypeInfo->GetImplTypeFlags(0,&pImplTypeFlags); //This method call will fail for every index except
if(SUCCEEDED(hr)) //zero. The method call will succeed for an index of
{ //zero in terms of S_OK, but will fail to retrieve any
printf("The Method Call ITypeInfo::GetImplTypeFlags() Succeeded, But It Really Failed!!!!\n"); //number other than zero.
printf("\npImplTypeFlags = %d\n",pImplTypeFlags);
}
pTypeInfo->Release();
}
pTypeLib->Release();
}
CoUninitialize();
getchar();
return 0;
}
/*
strLibName = MSFlexGridLib
pKind = 4
pKind = TKIND_DISPATCH
strInterfaceName = DMSFlexGridEvents
The Method Call ITypeInfo::GetImplTypeFlags() Succeeded, But It Really Failed!!!!
pImplTypeFlags = 0
*/
Even though my call to ITypeInfo::GetImplTypeFlags() returned a success code, it failed to retrieve the information as can be seen above in pImplTypeFlags = 0. But even if that did work it presupposes knowledge of which interface is the events interface, which is index 27 in the MSFlexGridLib. It should be possible to interrogate the CoClasses for this information. For example, index 28 in the MSFlexGridLib is CoClass MSFlexGrid as follows...
coclass MSFlexGrid
{
[default] interface IMSFlexGrid;
[default, source] dispinterface DMSFlexGridEvents;
};
The second interface there, i.e., [default, source] dispinterface DMSFlexGridEvents, is marked with the source attribute. It should be possible to obtain that information first, then use it to do whatever one wants to do with it. But that doesn't work either. I am able to index into the CoClass and obtain the BSTR name 'DMSFlexGridEvents', but when I get a ITypeInfo* for it I end up with the same success that is really a failure as shown above. Here is that program and its output...
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
#include <cstdio>
#define MAX_NAMES 48
const IID LIBID_Component = {0x5E9E78A0,0x531B,0x11CF,{0x91,0xF6,0xC2,0x86,0x3C,0x38,0x5E,0x30}}; // MSFlexGridLib 1, 0
int main(void)
{
ITypeInfo* pTypeInfo=NULL;
TYPEATTR* pTypeAttr=NULL;
ITypeLib* pTypeLib=NULL;
HREFTYPE pRefType=NULL;
int iTypeInfoCount=0;
TYPEKIND pKind;
BSTR strName;
HRESULT hr;
CoInitialize(NULL);
hr=LoadRegTypeLib(LIBID_Component,1,0,0,&pTypeLib);
if(SUCCEEDED(hr))
{
hr=pTypeLib->GetDocumentation(-1,&strName,NULL,NULL,NULL);
wprintf(L"%s\n",strName);
SysFreeString(strName);
hr=pTypeLib->GetTypeInfoType(28,&pKind);
printf("pKind = %u\n",pKind);
if(pKind==TKIND_COCLASS)
printf("Index #28 Is A CoClass\n");
hr=pTypeLib->GetDocumentation(28,&strName,NULL,NULL,NULL);
wprintf(L"strName = %s\n",strName);
SysFreeString(strName);
hr=pTypeLib->GetTypeInfo(28,&pTypeInfo); // Get TYPEINFO* For CoClass MSFlexGrid; index 28
if(SUCCEEDED(hr)) // Then get TYPEATTR*; TYPEATTR::cImplTypes;
{ // Number of implemented interfaces.
hr=pTypeInfo->GetTypeAttr(&pTypeAttr); // There are two ( 0 ) IMSFlexGrid and ( 1 ) DMSFlexGridEvents
printf("pTypeAttr->cImplTypes = %u\n",pTypeAttr->cImplTypes); // << that <<< returns 2.
hr=pTypeInfo->GetRefTypeOfImplType(1,&pRefType);
if(SUCCEEDED(hr))
{
ITypeInfo* pRefTypeInfo=NULL;
hr=pTypeInfo->GetRefTypeInfo(pRefType,&pRefTypeInfo);
if(SUCCEEDED(hr))
{
hr=pRefTypeInfo->GetDocumentation(-1,&strName,NULL,NULL,NULL);
wprintf(L"%s\n",strName);
SysFreeString(strName);
int pImplTypeFlags=0;
hr=pRefTypeInfo->GetImplTypeFlags(0,&pImplTypeFlags);
if(SUCCEEDED(hr))
{
printf("pRefTypeInfo->GetImplTypeFlags(1,&pImplTypeFlags) Succeeded!\n");
printf("pImplTypeFlags = %d\n",pImplTypeFlags);
}
pRefTypeInfo->Release();
}
}
pTypeInfo->ReleaseTypeAttr(pTypeAttr);
pTypeInfo->Release();
}
pTypeLib->Release();
}
CoUninitialize();
getchar();
return 0;
}
/*
MSFlexGridLib
pKind = 5
Its A CoClass
strName = MSFlexGrid
pTypeAttr->cImplTypes = 2
DMSFlexGridEvents
pRefTypeInfo->GetImplTypeFlags(1,&pImplTypeFlags) Succeeded!
pImplTypeFlags = 0
*/
So I'll end this with the question I asked in my first sentence. How does one determine that an interface is an event (source) interface without performing the dubious activity of searching text strings of interface names for 'Events'?
Quote
hr=pTypeInfo->GetTypeAttr(&pTypeAttr); // There are two ( 0 ) IMSFlexGrid and ( 1 ) DMSFlexGridEvents
printf("pTypeAttr->cImplTypes = %u\n",pTypeAttr->cImplTypes); // << that <<< returns 2.
This is what I use:
' ---------------------------------------------------------------------
' Gets the default events interfaces for each CoClass
' ---------------------------------------------------------------------
cImplTypes = @pTypeAttr.cImplTypes
FOR x = 0 TO cImplTypes - 1
lImplTypeFlags = 0
hr = pITypeInfo.GetImplTypeFlags(x, lImplTypeFlags)
IF hr <> %S_OK THEN EXIT FOR
pRefType = 0
hr = pITypeInfo.GetRefTypeOfImplType(x, pRefType)
IF hr <> %S_OK THEN EXIT FOR
hr = pITypeInfo.GetRefTypeInfo(pRefType, pImplTypeInfo)
IF hr <> %S_OK OR ISFALSE ISOBJECT(pImplTypeInfo) THEN EXIT FOR
hr = pImplTypeInfo.GetDocumentation(-1, bstrName, BYVAL %NULL, BYVAL %NULL, BYVAL %NULL)
IF hr <> %S_OK THEN EXIT FOR
pImplTypeInfo = NOTHING
szInterfaceName = bstrName
IF lImplTypeFlags = 1 THEN ' // Default interface
' --- Do something
ELSEIF lImplTypeFlags = 2 OR lImplTypeFlags = 3 THEN ' // Events interface / Default events interface
' --- Do something
END IF
NEXT
Thanks Jose (yet again). I'll give it a try first thing tomorrow. I was wondering if it might be something like that similiar to getting the base interface of an interface.