Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Построение иерархии объектов DCOM сервера.

1.8K
24 ноября 2008 года
Arkady
153 / / 18.12.2007
Здравствуйте,
Использую CBuilder 6 для построение DCOM сервера. Как и учат в "CBuilder Энциклопедия программиста" и других подобных книгах, создаю Automation Object из закладки ActiveX, вопросов это всё никаких не вызывает. Но все тестовые примеры, во всех статьях и книгах, всё это всегда строится на одном интерфейсе одного объекта.
Проблема у меня следующая.
Допустим есть Interface1 и Interface2. При этом Interface1 должен содержать атрибут — Interface2. Клиент должен иметь возможность только создать объект, реализующий Interface1. А через него достучаться до Interface2, как до атрибута созданного объекта.
При этом он не должен иметь возможность получить Interface2 до того, как получит Interface1. При этом хорошо бы, чтобы класс, реализующий Interface2, имел доступ до данных класса, реализующего Interface1 (т.е. являлся его составляющим).

Как же это сделать? Мучаюсь с четверга...

С уважением, Аркадий.
1
24 ноября 2008 года
kot_
7.3K / / 20.01.2000
Цитата: Arkady

Клиент должен иметь возможность только создать объект, реализующий Interface1. А через него достучаться до Interface2, как до атрибута созданного объекта.


Если я вас правильно понял - то вы пытаетесь и рыбку съесть и гедонистические удовольствия получить. :)
В вашем случае используйте паттерн "Фабрика классов" - по крайней мере спросонья мне кажется это удачной идеей.

1.8K
24 ноября 2008 года
Arkady
153 / / 18.12.2007
Цитата: kot_
Если я вас правильно понял - то вы пытаетесь и рыбку съесть и гедонистические удовольствия получить. :)
В вашем случае используйте паттерн "Фабрика классов" - по крайней мере спросонья мне кажется это удачной идеей.



По-моему это не совсем то.
Я имел ввиду такое.
Есть два интерфейса

 
Код:
interface IReturn : public IDispatch
{
    virtual HRESULT AsString(BSTR* Str/*[out]*/) = 0;
    virtual HRESULT AsINT(VARIANT* INT/*[out]*/) = 0;
};
interface IDouble : public IDispatch
{
    virtual HRESULT DoubleIt(VARIANT Num/*[in]*/) = 0;
    virtual HRESULT get_Result(IReturn** Num/*[out]*/) = 0;
};

Первый умеет выводить строчку или число, а второй удваивает введенное число и предоставляет пользователю первый интерфейс, чтобы тот мог выбрать, в каком виде он хочет получить результат (строчкой или числом). Это пример.

Очевидно, что первый интерфейс клиент не должен получить без второго, потому что сам по себе он не имеет смысла.
Но клиент должен иметь возможность получить первый интерфейс и уметь получить через него второй интерфейс, чтобы увидеть результат вычислений.
При этом класс, реализующий второй интерфейс, должен как-то иметь доступ до действий первого.

Вне DCOM и type library - это обычное дело, почти все классы устроены таким образом, но как тут сделать всё это правильно я не знаю, в статьях и книгах не нашел...
14
24 ноября 2008 года
Phodopus
3.3K / / 19.06.2008
А что мешает унаследовать класс от двух интерфейов, а фабрике классов разрешить создавать лишь объекты одного из них? А потом через QueryInterface получать и второй?
1.8K
24 ноября 2008 года
Arkady
153 / / 18.12.2007
Цитата: Phodopus
А что мешает унаследовать класс от двух интерфейов, а фабрике классов разрешить создавать лишь объекты одного из них? А потом через QueryInterface получать и второй?



Честно говоря, Фабрику классов реализую там не я, её, вроде как, предоставляет мне Борланд, а как сказать ему, чтобы он не давал создавать первый интерфейс не представляю. Как это сделать?
Если убрать у CoClass галочку "Can Create" или добавить "Hidden" или и то, и то - ничего не меняется, клиент как мог, так и может загружать этот объект сразу.

Кроме того, надо, чтобы первый интерфейс был именно property второго, насколько я понимаю, это отметает вариант получать первый интерфейс через QueryInterface от второго, только как property второго.
А значит, чтобы следовать нотации КОМ, эти интерфейсы должны быть реализованы разными объектами (потому что иначе они обязаны получать друг друга через QueryInterface).

11
24 ноября 2008 года
oxotnik333
2.9K / / 03.08.2007
вобще то свойство описывается в виде геттера и сеттера
в вижуале это выглядит примерно так:
 
Код:
interface IDouble : public IDispatch
{
[propget, id(1), helpstring("property Sett")] HRESULT Sett([out, retval]  IReturn** pVal);
    [propputref, id(1), helpstring("property Sett")] HRESULT Sett([in] IReturn* newVal);
};
1.8K
24 ноября 2008 года
Arkady
153 / / 18.12.2007
Цитата: oxotnik333
вобще то свойство описывается в виде геттера и сеттера
в вижуале это выглядит примерно так:
 
Код:
interface IDouble : public IDispatch
{
[propget, id(1), helpstring("property Sett")] HRESULT Sett([out, retval]  IReturn** pVal);
    [propputref, id(1), helpstring("property Sett")] HRESULT Sett([in] IReturn* newVal);
};


Спасибо, как получить свойство - проблемы не вызывает. Вопрос вызывает, как сделать так, чтобы класс, являющийся свойством, нельзя было создать извне. Чтобы интерфейс IReport можно было получить ТОЛЬКО дернув его, как свойство интерфейса IDouble..

14
24 ноября 2008 года
Phodopus
3.3K / / 19.06.2008
Цитата: Arkady
Честно говоря, Фабрику классов реализую там не я, её, вроде как, предоставляет мне Борланд, а как сказать ему, чтобы он не давал создавать первый интерфейс не представляю. Как это сделать?
Если убрать у CoClass галочку "Can Create" или добавить "Hidden" или и то, и то - ничего не меняется, клиент как мог, так и может загружать этот объект сразу.


Вроде так или так:
1. Убрать создание лишней фабрики при инициализации
2. Унаследоваться от борландовской фабрики и переопределить ее методы создания (сейчас названий не вспомню)

Цитата: Arkady

Кроме того, надо, чтобы первый интерфейс был именно property второго, насколько я понимаю, это отметает вариант получать первый интерфейс через QueryInterface от второго, только как property второго.
А значит, чтобы следовать нотации КОМ, эти интерфейсы должны быть реализованы разными объектами (потому что иначе они обязаны получать друг друга через QueryInterface).


Как я вижу решение - так это первый интерфейс будет порождаться от второго либо через QueryInterface, либо через property. Помоему так это самая что ни на есть нотация КОМ. Хотя в ней даже без свойств обходятся.

1.8K
24 ноября 2008 года
Arkady
153 / / 18.12.2007
А как убрать создание лишней фабрики при инициализации? %)

Проект с IReport и IDouble мона сделать за 3 мнуты тому, кто умеет, там же не вопрос кодинга. Если его сделать - это будет первое место в интернете, где есть пример проекта, где клиент не может создать IReport без IDouble.
Правда, конечно, хотелось бы, чтобы это всё-таки был не один объект, поддерживающий кучу интерфейсов, а именно их иерархия объектов... неужели нельзя это сделать, запретив создавать объекты пользователю? =(
Флаг Can Create просто так не работает, что надо сделать, чтобы заработал? :(
246
25 ноября 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady

...
Как же это сделать?
...



по моему надо почитать литературу на тему - агрегирование

1.8K
25 ноября 2008 года
Arkady
153 / / 18.12.2007
Цитата: GIZMO
по моему надо почитать литературу на тему - агрегирование



В таком случае даже если реально это несколько объектов, для клиента это всё равно будет как один объект, имеющий 40 интерфейсов.

А нужно, чтобы и пользователь видел эти два интерфейса, как несколько объектов, один из которых он может получить только через другой.

Кроме того, даже если бы агрегирование подходило (в некоторых местах это подойдет), как оно устроено я знаю, а вот как сказать билдеру агрегировать один объект через другой - я не знаю и не помню, чтобы когда-либо где-то натыкался на статью об этом.

14
25 ноября 2008 года
Phodopus
3.3K / / 19.06.2008
Цитата: Arkady
А как убрать создание лишней фабрики при инициализации? %)


Тут я ошибся. Убирая создание фабрики лишаешься возможности не только создавать объект извне, но и изнутри (создание тоже идет через фабрику, слегка иным способом но все же). Вот что у меня получилось на скорую руку. Проект на дельфи, билдера нет и в ближайшем будущем не предвидится. Надеюсь сумеешь переделать. Пришлось подменять DllGetClassObject.

246
25 ноября 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady
Кроме того, даже если бы агрегирование подходило (в некоторых местах это подойдет), как оно устроено я знаю, а вот как сказать билдеру агрегировать один объект через другой - я не знаю и не помню, чтобы когда-либо где-то натыкался на статью об этом.



см. исходники (документацию) ATL

1.8K
25 ноября 2008 года
Arkady
153 / / 18.12.2007
Это всё полезно, но побочно.

Вот как я бы сделал в жизни:
Код:
interface IReturn
{
    virtual HRESULT AsString(BSTR* Str/*[out]*/) = 0;
    virtual HRESULT AsINT(VARIANT* INT/*[out]*/) = 0;
};
interface IDouble
{
    virtual HRESULT DoubleIt(VARIANT Num/*[in]*/) = 0;
    virtual HRESULT get_Result(IReturn** Ret/*[out]*/) = 0;
};

class CReturn : public IReturn
{
private:
  int m_X;
public:
  void Init(int X);
   
public: //Interface
    virtual HRESULT AsString(BSTR* Str/*[out]*/);
    virtual HRESULT AsINT(VARIANT* INT/*[out]*/);
/*думаю реализация понятна и приводить смысла нет*/
};

class CDouble : public IDouble
{
private:
  int m_Y;
  CReturn m_Return;

public: //Interface
    virtual HRESULT DoubleIt(VARIANT Num)
    {
        m_Y = Num.intVal + Num.intVal;
        return S_OK;
    }
    virtual HRESULT get_Result(IReturn** Ret/*[out]*/)
    {
        m_Return.Init(m_Y);
        *Ret = static_cast<IReturn*>Ret;
        return S_OK;
    }
};

При этом пользователь может получить интерфейс IReturn только через IDouble. И никак иначе. И при этом из одного класса в другой идёт передача данных (потому, что они связаны).

Теперь представим, что оба вышепредставленных интерфейса - находятся в Type Library. И надо реализовать то же самое, только теперь это будет транслироваться по сети и иметь автоматизацию.
Но у меня не получается уже который день. =(

Неужели получить такую картину невозможно? Почему-то мой автоматически создаваемый CoClass оказывается виртуальным (в нем не реализован метод AddRef, если я хочу сделать его экземпляром другого класса, но всё в порядке, если я через фабрику пытаюсь его создать клиентом).
В результате нужно получить аналог изложенного выше кода. И чтобы пользователь от сервера мог получить только IDouble.

Никакая агрегация не нужна, множественное наследование не нужно, всё это хорошо, пригодится, но для решения вот этой простой задачи (она наверняка простая) этого недостаточно.
Как же получить вот то же самое, только DCOM? Я же видел объекты КОМ чужие, они все устроены таким образом. Значит это возможно же.

Вот тут я создал проект, добавил в него 2 раза Automation Object, сделал интерфейсы IDouble и IResult, реализовал их (всё как в примере выше).
Но Result не сделал членом Double, потому что он почему-то абстрактный, хотя фабрика классов его реализовывает. Если кто-то может, с этим проектом это займет минуту, измените его так, чтобы Result можно было получить через Double, и нельзя было получить иначе. Там всё готово, надо сделать только эти действия.
14
26 ноября 2008 года
Phodopus
3.3K / / 19.06.2008
Короче походу я и второй раз перемудрил. Создай те же 2 Automation Object, сделай интерфейсы IDouble и IResult, реализуй их а потом замени родителя TResult на TAutoIntfObject и почитай по нему справку. Походу это то что тебе хочется.
1.8K
26 ноября 2008 года
Arkady
153 / / 18.12.2007
Цитата: Phodopus
Короче походу я и второй раз перемудрил. Создай те же 2 Automation Object, сделай интерфейсы IDouble и IResult, реализуй их а потом замени родителя TResult на TAutoIntfObject и почитай по нему справку. Походу это то что тебе хочется.



Похоже на то, судя по его описанию, он реализует всё, что нужно.
Поскольку он не является шаблоном, я просто дописываю его так:

 
Код:
class ATL_NO_VTABLE TResultImpl :
  public CComObjectRootEx<CComMultiThreadModel>,
  public CComCoClass<TResultImpl, &CLSID_Result>,
  public IDispatchImpl<IResult, &IID_IResult, &LIBID_DoubleLib>,
  public TAutoIntfObject


Так вот, это дает следующие ошибки.
 
Код:
[C++ Error] DESCRIPTIONIMPL.H(25): E2267 First base must be VCL class
  [C++ Error] DESCRIPTIONIMPL.H(25): E2367 Can't inherit RTTI class from non-RTTI base 'TAutoIntfObject'
  [C++ Error] DESCRIPTIONIMPL.H(31): E2251 Cannot find default constructor to initialize base class 'TAutoIntfObject'

Похоже этот класс не RTTI и не VCL (и почему-то это не дает ему быть предком).

У него есть только такой конструктор:
 
Код:
__fastcall TAutoIntfObject(const _di_ITypeLib TypeLib, const GUID &DispIntf);

При этом _di_ITypeLib - это результат макроса, который как-то определяет тип интерфейса (DECLARE_DINTERFACE_TYPE(ITypeLib)), но как - не описано. Т.е. что туда передавать не понятно.

И вообще в описании указано, что это Дельфевый класс, отсюда, думаю, и все эти ошибки.
14
27 ноября 2008 года
Phodopus
3.3K / / 19.06.2008
Еще глянь макрос OBJECT_ENTRY_NON_CREATEABLE
1.8K
04 декабря 2008 года
Arkady
153 / / 18.12.2007
Цитата: Phodopus
Еще глянь макрос OBJECT_ENTRY_NON_CREATEABLE



Это, похоже, то, что нужно, только всё равно такие объекты отказываются создаваться, т.к. содержат абстрактные методы...
В итоге тоже то, что я описал в 14м сообщении тут не построишь...

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог