枚举COM指针所能查询的接口

鄙人最近从事COM开发,基本上得到一COM接口就要QueryInterface另外一个接口,都能获取到哪些接口就要查文档了。如果有个函数传入一接口指针,能输出其支持的所有接口那就好了。接口的注册表项位于HKEY_CLASSES_ROOT\Interface中,每个子项的名称都是以接口IID命名,其默认值就是接口的字符串名称。

先写个函数查注册表中接口IID对应的接口名称:

/*
* 获取COM接口的名称,返回获取成功与否
* 接口名为GUID注册表项默认的值
*/
template
< int  t_nSize >
ATLINLINE BOOL GetInterfaceName( REFIID riid, TCHAR (
& szName)[t_nSize] )
{
    BOOL  bRet  
=   FALSE;
#ifdef   USER_ATL_
    
// CRegKey版本
    CRegKey  regKey;
    OLECHAR szGuid[
64 ];
    ::StringFromGUID2(riid, szGuid, 
sizeof (szGuid) / sizeof (OLECHAR));
    TCHAR szSubKey[
128 ];
    wsprintf( szSubKey, _T(
" Interface\\%s " ), COLE2T(szGuid) );
    
if ( ERROR_SUCCESS  ==  regKey.Open( HKEY_CLASSES_ROOT, szSubKey,  KEY_QUERY_VALUE ) )
    {
        ULONG cb 
=   127 ;
        
if ( ERROR_SUCCESS  ==  regKey.QueryStringValue( NULL, szName,  & cb) )
        {
            bRet  
=   TRUE;
        }
        regKey.Close();
    }
#else
    
// API版本:
    OLECHAR szGuid[ 64 ];
    ::StringFromGUID2(riid, szGuid, 
sizeof (szGuid) / sizeof (OLECHAR));
    TCHAR szSubKey[
128 ];
    wsprintf( szSubKey, _T(
" Interface\\%s " ), COLE2T(szGuid) );

    HKEY hKey;
    
if ( ERROR_SUCCESS  ==  ::RegOpenKeyEx( HKEY_CLASSES_ROOT, szSubKey,  0 , KEY_QUERY_VALUE,  & hKey) )
    {
        DWORD dwType;
        DWORD dwSize 
=  t_nSize  *   sizeof (TCHAR);
        
if ( ERROR_SUCCESS  ==  ::RegQueryValueEx(hKey, NULL, NULL,  & dwType, reinterpret_cast < LPBYTE > (szName),  & dwSize) )
        {
            bRet  
=   TRUE;
        }
        ::RegCloseKey(hKey);
    }
#endif
    
return  bRet;
}

读注册表分别用了API版本和ATL的CRegKey版本(大家不要BS,鄙人一向信奉多练练手没害处)。

之后遍历注册表项HKEY_CLASSES_ROOT\Interface,获取每个接口的IID,如果传入的COM接口QueryInterface这个接口成功,则支持该接口,输出其接口名称。

 

/*
* 枚举接口所有名称
*/
ATLINLINE 
void  ScanInterface( IUnknown  * pUnk )
{
    
if ( pUnk == NULL )  return ;

#ifdef   USER_ATL_
    CRegKey  regKey;

    
if ( ERROR_SUCCESS  ==  regKey.Open( HKEY_CLASSES_ROOT, _T( " Interface " ), KEY_QUERY_VALUE  |  KEY_ENUMERATE_SUB_KEYS ) )
    {
        TCHAR szGuid[
128 ];
        DWORD dwIndex 
=   0 ;
        DWORD dwSize 
=  _countof(szGuid)  *   sizeof (TCHAR);
        
while ( ERROR_SUCCESS  ==  regKey.EnumKey( dwIndex, szGuid,  & dwSize ) ) 
        {
            IID iid;
            ::IIDFromString( CT2OLE(szGuid), 
& iid );

            CComPtr
< IUnknown >  spUnk;
            
if ( SUCCEEDED( pUnk -> QueryInterface( iid, (LPVOID * ) & spUnk ) ) ) 
            {
                TCHAR szName[
128 ];
                
if ( GetInterfaceName( iid, szName ) )
                {
                    AtlTrace( _T(
" %s\n " ), szName );
                }
            }
            dwSize 
=  _countof(szGuid)  *   sizeof (TCHAR);
            dwIndex
++ ;
        }

        regKey.Close();
    }
#else
    HKEY hKey;
    
if ( ERROR_SUCCESS  ==  ::RegOpenKeyEx( HKEY_CLASSES_ROOT, _T( " Interface " ),  0 , KEY_QUERY_VALUE  |  KEY_ENUMERATE_SUB_KEYS,  & hKey) ) 
    {
        TCHAR   szGuid[
128 ];
        DWORD   dwIndex 
=   0 ;
        DWORD   dwSize 
=  _countof(szGuid)  *   sizeof (TCHAR);

        
while ( ERROR_SUCCESS  ==  ::RegEnumKeyEx(hKey, dwIndex, szGuid,  & dwSize, NULL, NULL,NULL, NULL ) ) 
        {
            IID iid;
            ::IIDFromString( CT2OLE(szGuid), 
& iid);

            CComPtr
< IUnknown >  spUnk;
            
if ( SUCCEEDED( pUnk -> QueryInterface( iid, (LPVOID * ) & spUnk ) ) ) 
            {
                TCHAR szName[
128 ];
                
if ( GetInterfaceName( iid, szName ) )
                {
                    AtlTrace( _T(
" %s\n " ), szName );
                }
            }

            dwSize 
=  _countof(szGuid)  *   sizeof (TCHAR);
            dwIndex
++ ;
        }
        ::RegCloseKey(hKey);
    }

#endif
}

 

至此已经完成,当然这种方案缺点在于还有很多定制的接口并没有在注册表中注册,因此不够彻底。不过有胜于无了

你可能感兴趣的:(com)