本文介绍了IDispatch为CommandBarButton.Style返回DISP_E_UNKNOWNNAME的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Visual Studio加载项,其中包含用C ++实现的脚本引擎。
加载项只能使用 IDispatch 接口与Visual Studio进行通信。
我正在将它从VS 2005升级到VS 2010。



加载项创建了一系列 IDispatch: :Invoke()调用相当于这个Visual Basic:

  control = commandBar.Controls.Add MsoControlType.msoControlButton)
control.Caption =我的按钮
control.FaceId = 59


$ b b

在VS 2005中,这个过去工作。但在VS 2010中它不是。 GetIDsOfNames()为FaceId返回 DISP_E_UNKNOWNNAME



注意Caption(成功)是 CommandBarControl 的属性,而FaceId(失败)是 CommandBarButton 子类。按钮的 IDispatch * 的类名为 CommandBarControl 。所以我想我需要把 CommandBarControl IDispatch * 下载到 CommandBarButton IDispatch * 某种方式。



在Visual Basic中我可以写:

  button = DirectCast(control,CommandBarButton)
button.FaceId = 59

但我不知道什么 DirectCast ()在内部。



感谢

解决方案


首先,我发现如果我查询 IDispatch ICommandBarButton ,然后查询 IDispatch ,我得到一个不同的 IDispatch (在不同的地址),它识别 ICommandBarButton 属性。这让我如何找到由脚本给我的一些任意接口名称的IID(在这种情况下,字符串CommandBarButton)。



但更多实验,它看起来像我可以通过简单查询 IUnknown ,将 IDispatch 下降到最导出的类,然后查询 IDispatch



在问题中描述的情况下,返回的第二个 IDispatch * 一个不同的地址到第一个,并且类型 _CommandBarButton (注意下划线),其中原始类型 ICommandBarControl _CommandBarButton 似乎具有 CommandBarButton 的所有功能。 (请参见)



我现在将此代码包含在我的例程中它返回一个IDispatch对象到脚本引擎:

  / * 
*查询IUnknown,然后再次IDispatch。这意味着返回
*一个IDispatch为大多数派生类,从而暴露所有方法和
*属性,并在过程中返回一个不同的IDispatch到
*原始(多个分派接口同一对象)。
*
*例如,调用ICommandBarControls.Add(msoControlButton)将为CommandBarControl基类返回
* IDispatch,而不是
* CommandBarButton类。将IDispatch转换为IUnknown并返回后,
*我们得到一个_CommandBarButton的IDispatch,它看起来几乎是
*,但不是一个CommandBarButton。也就是说,CommandBarButton从
* _CommandBarButton继承
*只是它的每个属性和方法 - 当然所有我们感兴趣的。
* /
HRESULT hr;
IUnknown * unknown;
hr = dispatch-> QueryInterface(IID_IUnknown,(void **)& unknown);
if(hr == S_OK)
{
IDispatch * dispatch2 = NULL;
unknown-> QueryInterface(IID_IDispatch,(void **)& dispatch2);
if(hr == S_OK)
{
dispatch-> Release();
dispatch = dispatch2;
}
unknown-> Release();
}


I have a Visual Studio add-in, which contains a scripting engine implemented in C++.The add-in can only communicate with Visual Studio using IDispatch interfaces.I am in the process of upgrading it from VS 2005 to VS 2010.

The add-in makes a series of IDispatch::Invoke() calls equivalent to this Visual Basic:

control = commandBar.Controls.Add(MsoControlType.msoControlButton)
control.Caption = "My button"
control.FaceId = 59

In VS 2005, this used to work. But in VS 2010 it doesn't. GetIDsOfNames() returns DISP_E_UNKNOWNNAME for "FaceId".

Note that "Caption" (which succeeds) is a property of CommandBarControl, and "FaceId" (which fails) is a property of the CommandBarButton subclass. The classname for the button's IDispatch* is CommandBarControl. So I think I need to downcast the CommandBarControl IDispatch* to a CommandBarButton IDispatch* somehow.

In Visual Basic I could write:

button = DirectCast(control, CommandBarButton)
button.FaceId = 59

But I don't know what DirectCast() does internally. If I did I'd probably be close to solving this.

Thanks

解决方案

Just answering my own question here... bleah.

First I discovered that if I query the IDispatch for ICommandBarButton, then query that for IDispatch, I get a different IDispatch (at a different address) which recognises the ICommandBarButton properties. That left me with how to find the IID of some arbitrary interface name given to me by the script (in this case, the string "CommandBarButton").

But after more experimenting, it looks like I can downcast an IDispatch to the most derived class by simply querying for IUnknown, then querying that for IDispatch again. No other IIDs or trickery needed.

In the situation I described in the question, The second IDispatch* returned is a different address to the first, and is of type _CommandBarButton (note the underscore) where the original was of type ICommandBarControl. _CommandBarButton seems to have all the functionality of CommandBarButton. (See http://technet.microsoft.com/en-us/microsoft.visualstudio.commandbars.commandbarbutton%28v=vs.90%29)

I now include this code in my routine which returns an IDispatch object to the script engine:

/*
 * Query for IUnknown, then for IDispatch again.  This APPEARS to return
 * an IDispatch for the most derived class, thus exposing all methods and
 * properties, and in the process returns a different IDispatch to the
 * original (multiple dispatch interfaces on the same object).
 *
 * For example, calling ICommandBarControls.Add(msoControlButton) returns
 * an IDispatch for the CommandBarControl base class, not the
 * CommandBarButton class.  After casting IDispatch to IUnknown and back,
 * we get an IDispatch for _CommandBarButton, which appears to be almost,
 * but not quite, a CommandBarButton.  That is, CommandBarButton inherits
 * just about every one of its properties and methods from
 * _CommandBarButton -- certainly all the ones we're interested in anyway.
 */
HRESULT hr;
IUnknown *unknown;
hr = dispatch->QueryInterface(IID_IUnknown, (void**)&unknown);
if (hr == S_OK)
{
    IDispatch *dispatch2 = NULL;
    unknown->QueryInterface(IID_IDispatch, (void**)&dispatch2);
    if (hr == S_OK)
    {
        dispatch->Release();
        dispatch = dispatch2;
    }
    unknown->Release();
}

这篇关于IDispatch为CommandBarButton.Style返回DISP_E_UNKNOWNNAME的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-17 15:12