2014-09-23 187 views
1

给定COM接口的名称作为字符串,我如何获得相应的IID,以便我可以调用QueryInterface()?从C++的接口名称中获取IID? (VS 2010自动化)

例如:

// Attempt to cast IDispatch referenced by pDisp to an ICommandBarButton 

char *interface_name = "ICommandBarButton"; 
IID iid; 

<<< code to get the iid for interface_name goes here >>> 
hr = pDisp->QueryInterface(iid, &interface); 

当然这是假设接口名称是唯一的全系统的,如果他们不那么需要更多的上下文。上下文是我有一个用于自动化VS 2010的脚本引擎,并且需要根据从脚本中读取的接口名称在字符串之间进行转换。我已经有了一个IDispatch *用于投射物体。

编辑:

用户阿尔夫评论说,我不应该要做到这一点,我很高兴没有。使用ITypeLib,我确定我的IDispatch(由CommandBarControls.Add(msoButton)创建)是一个CommandBarControl。我需要一个用于CommandBarButton的IDispatch,以便可以访问按钮的属性,例如Style属性 - CommandBarControl IDispatch无法识别此属性。我的IDispatch,AFAIK上支持的接口有:

Interface:CommandBarControl GUID:43FD5911-7BAC-4BDC-AB6C-2DE65B5C0233 
    Interface:IDispatch GUID:00020400-0000-0000-C000-000000000046 
    Interface:IUnknown GUID:00000000-0000-0000-C000-000000000046 

生成如下所示。这里没有列出CommandBarButton,所以如果只使用IDispatch的运行时机制来演示如何执行此操作,就会爱上某人。

实验代码:

void 
GetTypeInfo(ITypeInfo *pTypeInfo, int indent, char *&p) 
{ 
    BSTR  olename; 
    TYPEATTR *typeattr; 
    HRESULT  hr; 

    hr = pTypeInfo->GetDocumentation(MEMBERID_NIL, &olename, NULL, NULL, NULL); 
    if (hr == S_OK) 
    { 
     for (int i = 0; i < indent; i++) 
      *p++ = ' '; 
     p += sprintf(p, "Interface:"); 
     int len = SysStringLen(olename); 
     for (int i = 0; i < len; i++) 
      *p++ = (char)olename[i]; 
     *p++ = ' '; 
     SysFreeString(olename); 
    } 

    hr = pTypeInfo->GetTypeAttr(&typeattr); 
    if (hr == S_OK) 
    { 
     p += sprintf(p, " GUID:"); 
     for (int i = 0; i < 4; i++) 
      p += sprintf(p, "%02X", ((unsigned char*)&typeattr->guid.Data1)[3-i]); 
     *p++ = '-'; 
     for (int i = 0; i < 2; i++) 
      p += sprintf(p, "%02X", ((unsigned char*)&typeattr->guid.Data2)[1-i]); 
     *p++ = '-'; 
     for (int i = 0; i < 2; i++) 
      p += sprintf(p, "%02X", ((unsigned char*)&typeattr->guid.Data3)[1-i]); 
     *p++ = '-'; 
     for (int i = 0; i < 2; i++) 
      p += sprintf(p, "%02X", typeattr->guid.Data4[i]); 
     *p++ = '-'; 
     for (int i = 2; i < 8; i++) 
      p += sprintf(p, "%02X", typeattr->guid.Data4[i]); 
     *p++ = '\n'; 
     for (int i = 0; i < typeattr->cImplTypes; i++) 
     { 
      HREFTYPE reftype; 
      ITypeInfo *pTypeInfo2; 
      hr = pTypeInfo->GetRefTypeOfImplType(i, &reftype); 
      if (hr == S_OK) 
      { 
       hr = pTypeInfo->GetRefTypeInfo(reftype, &pTypeInfo2); 
       if (hr == S_OK) 
       { 
        GetTypeInfo(pTypeInfo2, indent + 2, p); 
        pTypeInfo2->Release(); 
       } 
      } 
     } 
     pTypeInfo->ReleaseTypeAttr(typeattr); 
    } 
} 


void 
GetDispatchInfo(IDispatch *pDisp) 
{ 
    char  buffer[16384]; 
    char  *p = buffer; 
    UINT  ticount; 
    HRESULT  hr; 

    hr = pDisp->GetTypeInfoCount(&ticount); 
    if (hr == S_OK) 
    { 
     for (UINT ti = 0; ti < ticount; ti++) 
     { 
      ITypeInfo *pTypeInfo; 
      hr = pDisp->GetTypeInfo(ti, 0, &pTypeInfo); 
      if (hr == S_OK) 
      { 
       GetTypeInfo(pTypeInfo, 0, p); 
       pTypeInfo->Release(); 
      } 
     } 
    } 
    *p = 0; 
    OutputDebugString(buffer); 
} 
+0

通常的interface-uuid关联机制只是编译时间。脚本支持基于IDispatch和类型库。您不需要为此执行QueryInterface(IDispatch本身除外),您可以使用IDispatch的运行时机制。这就是它的目的。为什么不使用它。 – 2014-09-23 22:16:31

+0

谢谢Alf,我修改了这个问题。 – Chungzuwalla 2014-09-23 23:00:44

+1

这是不可能的。 COM关心的唯一事情是{guid}。接口的名字是程序员从来没有正确使用的逃离细节。编程方便,当你必须与另一个程序交互时,它很快就会消失。大家都称之为IMyInterface,或者是一些没有灵感的变化。这是行不通的,接口必须是全局唯一的。 GU在guid中。 – 2014-09-23 23:54:58

回答

2

OK,基于上述意见,我认为原来的问题(转换接口名称为GUID全球)是不可能的。

换句话说,在Visual Basic解释器,用命令提出像这样的:

control = commandBar.Controls.Add(MsoControlType.msoControlButton) 
button = DirectCast(control, CommandBarButton) 

依靠比查找在某些系统范围的表中的字符串“CommandBarButton的”其他东西。而且这似乎是IDispatch及其关联类型库的运行时机制内的某个地方。大概有一种方法来复制VB在这里做的事情,使用一些类型的库巫术。但是,这并不是什么问原来的问题....

编辑:

我找到了一个解决办法,以我的问题,并张贴在回答对我相关的问题:

IDispatch returns DISP_E_UNKNOWNNAME for CommandBarButton.Style

在简而言之,查询IDispatch的IUnknown,然后再次查询Iisnkatch以查找IDispatch,返回一个不同的IDispatch,它看起来是最派生类(在这种情况下是CommandBarButton)。没有需要的类型库伏都教。 希望这可以帮助别人。

+1

道具在找到答案后给出答案。 – Medinoc 2014-12-16 13:42:28

0

如果接口已注册(通常用于编组),那么您可以在注册表中的HKCR \ Interface下找到它。不幸的是,那里的接口是由IID注册的,所以如果你想从名字中找到IID,你必须做一个线性搜索。

即使如此,它不能保证工作(接口注册不是强制性的,我甚至不知道当注册接口名称时)。

+1

调试器已经这样做:) – 2014-10-28 22:54:28