Я читал о различных шаблонах проектирования COM, подробно описанных в Поваренной книге программиста COM , а также о некоторых связанных SO-потоках, в частности , обсуждающих композицию и множественное наследование .Возможно, из-за того, что я слишком плохо знаком с C ++ и COM, возможно, мне не хватает замечаний, высказанных в различных источниках, поэтому вот мой вопрос, выраженный в одном предложении:
Могу ли я расширить интерфейс, сгенерированный MIDL дляВнутреннее использование DLL и, если да, то как правильно обрабатывать проблему алмаза / параллельную иерархию с учетом ограничений MIDL / COM?
Грязные детали ...
Надеемся, что поможет другим определитьгде мое замешательство может быть, вот мои предположения:
1) COM не поддерживает виртуальное наследование, а допускает только множественное наследование только через интерфейсы.
2) Несмотря на то, что COM не может его видеть, для меня не должно быть незаконным использование неподдерживаемого наследования C ++, если я не ожидаю, что оно будет открыто предоставлено COM.
3) Поскольку MIDL допускает только одиночное наследование интерфейсов, если у меня параллельная иерархия, мне нужно объединить их для кокласса.
4) MIDL, по-видимому, не объявляет сам кокласс, поэтому мне нужно было бы написать .h файл, объявляющий фактический класс, и я могу расширять его по мере необходимости, понимая, что потребители COM не могут его использовать (и этоХОРОШО).
То, что я хочу сделать, - это иметь базовый объект (я еще не решил, будет ли он абстрактным или нет, хотя я думаю, что это будет сейчас), который обрабатывает большинство деталей реализации и делегирует некоторые конкретныефункциональность для подклассов.Клиент обычно использует подклассы.Итак,
project.idl
import "oaidl.idl"
import "ocidl.idl"
[
object,
uuid(...),
dual,
oleautomation
]
interface IBase : IDispatch {
//stuff I want to show to COM
};
[
object,
uuid(...),
dual,
oleautomation
]
interface IChild1 : IBase {
//stuff (in addition to base) I want to show to COM
};
[
object,
uuid(...),
dual,
oleautomation
]
interface IChild2 : IBase {
//stuff (in addition to base) I want to show to COM
};
[
uuid(...),
version(...),
]
library myproject {
importlib("stdole32.tlb");
interface IBase;
interface IChild1;
interface IChild2;
[
uuid(...),
]
coclass Base {
[default]interface IBase;
interface IOle*; //include other IOle* interfaces required for the functionality
};
[
uuid(...),
]
coclass Child1 {
[default]interface IChild1;
interface IOle*; //those are delegated to the base members
};
[
uuid(...),
]
coclass Child2 {
[default]interface IChild2;
interface IOle*; //those are delegated to the base members
};
};
base.h
#include base_h.h //interfaces generated by MIDL
// I assume I need to re-include IOle* because IBase has no relationship
// and C++ wouldn't know that I want the object base to also have those
// interfaces...
class base : public IBase,
public IOle* {
//handle all IUnknown, IDispatch and other IOle* stuff here
//as well as the common implementations as appropriate
};
child1.h
#include base.h
//I'm not sure if I need to re-include the IOle* interfaces...
//I also assume that by inheriting base, child1 also inherits its interface
class Child1 : public Base,
public IChild1 {
//specific details only, let base handle everything else.
};
child2.h
#include base.h
//I'm not sure if I need to re-include the IOle* interfaces...
class Child2 : public Base,
public IChild2 {
//specific details only, let base handle everything else.
};
Концептуально создание нового дочернего * объекта всегда будет означать создание базового объекта, поскольку base будетТребуется обработать детали реализации, поэтому я подумал, что база также должна позаботиться о подсчете QueryInterface & Reference, но я запутался в следующих моментах:
1) компилятор жалуется на неоднозначность членов из-запараллельной иерархии;IUnknown повторно реализован несколько раз из моего пользовательского интерфейса и из дополнительных интерфейсов IOle *.Документация предполагает, что ожидается, что на самом деле необходима только одна реализация для каждого объекта, но я не понимаю, как бы я решил проблемы с компилятором, и я чувствую, что выполнение приведения типов как-то неправильно?Мне также интересно, если я должен виртуально унаследовать все интерфейсы, которые кажутся действительными для C ++, хотя у COM такого понимания нет, но это не должно волновать (?).
2) Однако, если я объявляю все унаследованные интерфейсы как виртуальные в файлах .h, компилятор затем жалуется, что унаследованные члены не допускаются, когда я пытаюсь реализовать QueryInterface в Base class.cpp.Я погуглил эту ошибку, но не ясно, что она пытается мне сказать.
РЕДАКТИРОВАТЬ: Я ответил на свой вопрос. У Intel была документация для этой ошибки, которую я изначально не щелкал по ссылке, предполагая, что она может не относиться к Visual Studio.Хотелось бы, чтобы я это сделал, но теперь я понимаю, почему я получаю эту ошибку, поскольку я пытался выполнить всю реализацию в Base ::, а не IUnknown :: или IDispatch ::.Теперь возникает новый вопрос, который может прояснить мой первоначальный и главный вопрос - как отложить реализацию от IUnknown (и других) до Base и работать только с Base, если это вообще возможно?Кажется, что если я просто использую IUnknown :: xxx, он больше не сможет получить доступ к закрытым членам Базы, что, как мне кажется, вполне разумно, так что это может быть не тем, что я хочу.Я попытался объявить все другие интерфейсы, кроме собственного базового, как виртуальные, но на самом деле это не так.(Опять же, возможно, моя неопытность не видела очевидного решения.)
3) QueryInterface Base не может привести base к потомку, что является разумной жалобой, поэтому я предполагаю, что мне все равно придется переопределить QI для всех дочерних элементов, но я могу делегировать обратно в QI базы, как только я определю, что запрошенные интерфейсы не являются ребенок. Как ни странно, компилятор настаивает на том, что дочерний * класс является абстрактным из-за отсутствия элементов для IUnknown & IDispatch, но разве база уже не реализована, и, следовательно, дочерний элемент также должен иметь эти члены?
Различные ошибки компилятора заставляют меня беспокоиться о том, что моя неопытность по отношению к одному или обоим языкам и фреймворкам приводит меня к ошибочным предположениям о том, как я могу проектировать COM-объекты, иерархию наследования и детали реализации, и я определенно что-то упускаю Вот. Любые указатели, даже пощечина будет очень цениться.
Спасибо!