枚举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
}

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

原文地址:https://www.cnblogs.com/fangkm/p/1599418.html