IDispatch returns DISP_E_UNKNOWNNAME for CommandBarButton.Style

痞子三分冷 提交于 2019-12-11 17:27:16

问题


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


回答1:


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();
}


来源:https://stackoverflow.com/questions/25965753/idispatch-returns-disp-e-unknownname-for-commandbarbutton-style

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!