2014-09-22 2 views
0

У меня есть надстройка Visual Studio, которая содержит механизм сценариев, реализованный на C++. Надстройка может взаимодействовать только с Visual Studio с использованием интерфейсов IDispatch. Я нахожусь в процессе модернизации его из VS 2005 в VS 2010.IDispatch возвращает DISP_E_UNKNOWNNAME для CommandBarButton.Style

надстройка делает серию IDispatch::Invoke() вызовов эквивалентно следующему Visual Basic:

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

В VS 2005, это используется работать. Но в VS 2010 это не так. GetIDsOfNames()DISP_E_UNKNOWNNAME для "FaceId".

Обратите внимание, что «Caption» (который успешно завершен) является свойством CommandBarControl, а «FaceId» (который не работает) является свойством подкласса CommandBarButton. Имя класса для кнопки IDispatch*: CommandBarControl. Поэтому я думаю, что мне нужно как-то понизить CommandBarControl IDispatch* до CommandBarButton IDispatch*.

В Visual Basic я мог бы написать:

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

Но я не знаю, что делает DirectCast() внутренне. Если бы я это сделал, я, вероятно, был бы близок к решению этого.

Благодаря

+0

радостях нескольких интерфейсов диспетчерских –

+0

Благодаря Matt ... Несколько интерфейсов IDispatch, на самом деле ?? Разве это не означает, что MS нарушает свои собственные правила, что объект может иметь только один интерфейс IDispatch? Мое понимание: «разрешено только одно IDispatch (использование QueryInterface с IDispatch всегда должно возвращать тот же интерфейс)» (http://www.codeguru.com/cpp/com-tech/atl/atl/article.php/ c47/Multiple-Dispatch-Interfaces-in-ATL.htm) – Chungzuwalla

+0

Разрешено несколько интерфейсов отправки, но некоторые языки не могут получить к ним доступ. Вот почему иногда советуют не использовать несколько двойных интерфейсов.В C++, например, вы указываете IID с запросом интерфейса, поэтому вы можете иметь IDispatch *, но вы можете запросить 'IID_IFoo'. Если у объекта есть 'IFoo' как двойной интерфейс, то это работает. –

ответ

0

Просто отвечая на мой собственный вопрос здесь ... bleah.

Сначала я обнаружил, что если я запросить IDispatch для ICommandBarButton, то запрос, что для IDispatch, я получаю другую IDispatch (на другой адрес), который распознает ICommandBarButton свойства. Это оставило меня с тем, как найти IID некоторого произвольного имени интерфейса, данного мне сценарием (в этом случае строка «CommandBarButton»).

Но после большего количества экспериментов, похоже, я могу свести IDispatch к самому производному классу, просто запросив IUnknown, а затем снова запросит его для IDispatch. Никаких других ИИИ или обмана не требуется.

В ситуации, я описал в вопросе, второй IDispatch* возвращается другой адрес к первому, и имеет тип _CommandBarButton (обратите внимание, подчеркивание), где первоначально был типа ICommandBarControl. _CommandBarButton, похоже, имеет всю функциональность CommandBarButton. (См http://technet.microsoft.com/en-us/microsoft.visualstudio.commandbars.commandbarbutton%28v=vs.90%29)

теперь я включить этот код в моей процедуре, которая возвращает объект IDispatch к двигателю сценария:

/* 
* 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(); 
} 
+0

PS: мне непонятно, показывает ли это, что модель VS 2010 нарушает правила QueyInterface. В правилах (http://msdn.microsoft.com/en-us/library/aa910647.aspx) говорится, что набор интерфейсов для объекта «Он должен быть рефлексивным», если клиент, содержащий указатель на один интерфейс, успешно запрашивает другой, запрос через полученный указатель для первого интерфейса должен быть успешным ». Который, я полагаю, не говорит, что указатель на первый интерфейс должен быть ТОЛЬКО как начальный указатель - только то, что вызов преуспевает, то есть верный интерфейс возвращается. – Chungzuwalla

Смежные вопросы