Здравствуйте chum, Вы писали:
C>Вопрос: сможет ли сервер вызывать методы других интерфейсов сервера?
Конечно, почему бы и нет.
C>И не только в то время, когда клиент обратился к серверу, а тогда, когда ему это надо.
Запросто, два коспонента обмениваются инерфейсами и взывают их методы тогда когда им это нужно.
C>Могут ли два компонента одновременно функционировать меняясь ролями? Обращаясь попеременно друг к другу, как к серверу? При этом, один из этих компонентов создан другим.
Да. Главное определиться кто из них главнее, чтобы не было путуницы и deadlock-ов.
C>Я попытался начать с простого, вы спрашиваете "зачем?" Я нарисовал глобальную картину, вы говорите: "сложно". Я не знаю, как еще объяснять. Как только я упрощаю, вы начинаете мыслить простыми категориями и опять спрашиваете: "зачем?". Замкнутый круг.
Тогда вернемся к началу.
C>При этом возникают некоторые вопросы: C>1. Как организовать взаимосвязь между сервером и GUI, когда они одновременно являются серверами и клиентами друг друга?
Тот кто первым создает объект и является клиентом. Он передает сереверу свой интерфейс (интерфейсы) и компоненты начинают взаимодействовать.
C>2. Как, например, реализовать GUI на VB?
Не понятно, что значит как? Садишься и пишешь.
C>Простая тестовая программа показывает, что при такой конфигурации VB не может создать немодальное окно приложения, а модальное окно приведет к deadlock'у сервера.
Ну так не создавай модальных окон.
C>3. Как инициализировать сервер, если он запущен как обычное приложени? Иными словами, если сервер имеет какой-то головной объект (скажем Application), то как и где его при этом создавать и удалять?
Как работате любой EXE COM server. Ты можешь указать что при зоздании нового экземпляра сервера не нужно запускать новы процесс а пользоваться сцществующим. Просто создаваемые экземпляры объектов, могут редиректить вызовы в какой-нить общий объект.
Что-то вроде.
// реальный класс выполняющий работу, создается при запуске приложенияclass CServer
{
protected:
CServer() {}
static CServer m_instance;
public:
CServer& GetInstance() { return m_instance; }
void DoSomething( DWORD dwParam );
};
// класс оболочка, создается при вызове CoCreateInstanceclass CServerWrapper
{
public:
CServerWrapper() {}
HRESULT DoSomething( DWORD dwParam ) // это метод COM интерфейса
{
CServer::GetInstance().DoSomething( dwParam );
retrun S_OK;
}
};
Здравствуйте chum, Вы писали:
C>Вот такая вот диспозиция в двух словах. При этом мне кажутся вполне очевидными следующие вещи:
Теперь понятно.
C>- ядро программы является сервером автоматизации
правильно.
C>- ядро программы является клиентом сервера, реализующего GUI программы
:no:
C>- сервер GUI должен иметь возможность обращаться к ядру
точно
C>- ядро должно иметь возможность обращаться к GUI (например, если требуется перерисовать GUI при добавлении нового словаря через интерфейсы ядра)
не совсем так
C>Теперь о проблемах реализации. Я не знаю как:
Если ты сделаешь GUI сервером, то я тебе искренне сочувствую.
GUI вообще можно не делать COM-объектом, только ядро. Ядро не должно знать никаких подробностей о клиентах, то ли это GUI, то ли что-то ещё. Для сообщения об изменении состояния внутри ядра следует посльзоваться событиями. Вот и всё. Т.е. тебе нужно твоё ядро завернуть в сервер автоматизации, exe или dll зависит от задачи.
Если нам не помогут, то мы тоже никого не пощадим.
GUI — это плохой термин когда речь идет о COM.
В твоих рассуждениях перепутаны понятия сервера и клиента (последнего понятия вообще нет, оно заменено словом GUI).
Привыкай приложение предоставляющее услуги – это сервер.
Потребляющее – клиент.
Причем если они меняются местами, то и роли (названия) меняются тоже.
Теперь о том как бы я подошел решению данной задачи:
Нужно разработать ядро которое должно заниматься непосредственно переводом. Данное ядро и должно быть сервером. Оно вообще не должно иметь GUI.
Создать отладочного клиента. На базе этого клиента должен отлаживаться интерфейс (программный) сервера. Ну, и это будет первый клиент.
Применение слова клиент позволит избежать путаницы (ну, и все обитатели этого форума будут понимать о чем идет речь.
По серверу: Сервер лучше создать в виде in-процессного (DLL), но все интерфейсы сервера должны отвечать требованиям oleautomation. Это с одной стороны даст возможность использовать данный сервер внутри процесса клиента (что даст значительное ускорение и экономию ресурсов). С другой стороны поддержка oleautomation позволит запускать такой сервер на удаленной машине (через COM+, присутствующий на W2k, или через суррогатный процесс).
Клиент должен общаться с сервером только через COM-интерфейс и предоставлять GUI для конечного пользователя. Все операции по поиску и т.п. должны производиться на сервере. Общение между сервером и клиентом должно осуществляться блоками небольшого размера. При этом блоки должны быть более-менее полноценными (не следует для каждого чиха лезть на сервер, так как это приведет к замедлению работы при использовании удаленного режима).
Приблизительный список методов (чисто для примера):
// Перевод слова.
HRESULT Translate([in] int Dictionary, [in] BSTR Word, [out] BSTR * TranslateCard);
HRESULT GetDictionaryList([out, retval] SAFEARRAY(BSTR)) * psa // Массив содержащий список словарей
// Список строк для заполнение списка в GUI-клиенте.
HRESULT GetList(
[in] int AlfabetWordPos, // Позиция слова в списке
[in] int MaxWordCount, // Количество строк в возвращаемом массива
[out, retval] SAFEARRAY(BSTR) * psa // Массив содержащий списак строк
Теперь на счет обновления словаря и т.п. ...
Такие операции осуществляются очень редко и обычно для пользователя проходят незаметно. Ничего страшного если пользователю придется нажать на кнопку "рефрешь" или перезагрузить программу.
Зато постоянная обратная связь с сервером, в случае если сервер загружается в отдельном процессе, и тем более на отдельной машине, приведет к неустойчивости работы сервера (ведь сервер станет клиентом для каждого клиента!), проблемам безопасностью (их конечно можно обойти, но времени на это уйдет море).
Если сервер предполагается использовать исключительно как in-процессный, то данный проблемы нивелируются или исчезают вовсе. Однако дизайн приложения лучше делать в расчете на распределенную работу.
В любом случае лучше идти по пути наименьшего сопротивления. Т.е. лучше создать сервер без обратной связи и уж если будет невмоготу, добавить такую возможность.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте chum, Вы писали:
C>Жалко, что нельзя реализовать пользовательский интерфейс программы в отдельноподключаемом компоненте. Это была одна из главных идей: дать пользователю сервера возможность "прилеплять" к нему свои собственные пользовательские интерфейсы. C>Можно, конечно, писать для каждого нового GUI новый сервер, его реализующий, который, в свою очередь, является клиентом ядра. Но тогда у каждой такой программы будет свой CLSID (или ProgID). А тут, собственно, идея была в том, чтобы этот сервер все время вызывался клиентами совершенно единообразно, вне зависимости от того, какой GUI к нему в данный момент "прилеплен".
Мда...
To IT & Vlad2:
Может нарисуете человеку картинку, шоб понятней было, вот мол сервер, вот его интерфейсы, а вот клиенты с GUI.
To chum:
Только не обижайся, но похоже тебе для начала нужно немного почитать о технологии COM, может тогда ты и сам все поймешь. Просто мне стало жалко IT и Vlada2, они так доходчиво все расписали и похоже впустую.
Здравствуйте chum, Вы писали:
C>Здравствуйте Willi, Вы писали:
C>Кроме того, если использовать что-то типа предложенных CServer и CServerWrapper и создавать в _tWinMain() экземпляр CServer, то непонятно: а кто будет создавать экземпляр CServerWrapper,
ClassFactory
C>Тогда нужно создавать экземпляр не CServer, а CServerWrapper.
Нет! CServer — один! CServerWrapper-ов — много.
Более того, помнится в ATL был макрос DECLARE_CLASS_FACTORY_SINGLETON или что-то в этом роде, так вот вместо механизма предложенного мной, можно воспользоваться этим макросом. Но что-то мне подсказывает что это будет некоторым нарушением правил игры.
C>Но как тогда сделать, чтобы ATL'евский контейнер компонентов учел этот созданный напрямую компонент? Я имею ввиду счетчик компонентов: его "ручками" увеличивать и уменьшать или это можно автоматизировать?
Не понимаю о чем ты.
C>Ну например: я запустил сервер как обычное приложение, а потом к нему кто-то подключился. Я приложение закрыл, но остался еще подключенный клиент. C>Как сделать, чтобы это все работало корректно?
О-о-о-о-й.
Наверняка в ATL есть механизмы которые не позволяют приложеию закрываться пока есть присоединенные клиенты. В крайнем случае ты и сам можешь иметь глобальный счетчик объектов и запрещать закрывать приложение пока он не станет равным нулю.
Прям как в том анекдоте: "Ты, Маугли, кого хочешь достанешь"
Не обижайся. Но у тебя действительно каша в голове. Надо бы почитать что-нить (ну например ATL Internals), примерчики посмотреть.
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте Аноним.
VD>Ты описываешь реализацию! Свое видение тык сызыть, а нужно было бы описать конкретную проблему! Т.е. задачу в челавеческих терминах. Что есть сервер (его предназначение)? Зачем сменный интерфейс? Чем интерфейс отличается от клиента? А то похоже, что ты путаешь понятие GUI и клиента. :(
Тысяча извинений за подпись Аноним — почему-то забыл залогиниться, а заметил уже когда послал сообщения.
К баранам:
Задача, так задача. Очень упрощенно.
Представьте себе программу. Например, электронный переводчик. Он имеет свой GUI и имеет ядро (локальный сервер автоматизации), которое "общается" со словарями и, вообще говоря, может переводить без всякого GUI, например через интерфейс IInterpreter. Итак, мы имеем программу-переводчик (типа Контекста или Лингво), которая может запускаться как обычное приложение, в котором можно набирать слова (или "бросать" в окно программы с помощью dran'n'drop) и переводить их. А можно, например, использовать как COM-сервер-переводчик из программы SuperInterpreter.
Теперь о смене GUI.
Представьте себе, что автор программы договорился с неким издательством о продаже вместе с их бумажным словарем его электронной версии, использующей вышеуказанное ядро. Этому варианту словаря ненужен очень сложный суперпользовательский интерфейс исходной программы. А просто это быстро написанное на VB некое "ведро" (типа Recycle Bin), которое висит поверх всего в углу экрана, и в которое можно "кидать" слова для перевода.
Вот такая вот диспозиция в двух словах. При этом мне кажутся вполне очевидными следующие вещи:
— ядро программы является сервером автоматизации
— ядро программы является клиентом сервера, реализующего GUI программы
— сервер GUI должен иметь возможность обращаться к ядру
— ядро должно иметь возможность обращаться к GUI (например, если требуется перерисовать GUI при добавлении нового словаря через интерфейсы ядра)
Теперь о проблемах реализации. Я не знаю как:
— организовать двухстороннее взаимодействие между ядром и GUI
— написать на ATL локальный сервер, который может запускаться как обычное приложение
Заранее благодарен.
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Есть необходимость написать EXE-сервер автоматизации с GUI.
При этом необходимо реализовать следующие особенности:
1. Сам сервер реализовать на ATL
2. GUI сервера реализовать в отдельном компоненте (для которого сам сервер является клиентом) на ATL, VB, MFC или чем-то еще и может, в принципе, выбираться сервером из нескольких компонентов, например категории SomeGUICat
3. Сервер должен иметь возможность обновлять ("перерисовывать" GUI), а GUI может вызывать методы сервера
4. Сервер может просто запускаться и функционировать как обычная программа (без COM-клиента сервера)
5. Сервер, по желанию клиента, может вообще не отображать свой GUI
Общая идея создания GUI-компонента такова:
Server::Run(BOOL fGUI)
{
...
if(fGUI)
{
GUI pGUI = NULL;
hresult = CreateInstance(..., &pGUI);
pGUI->Show(this); // to get GUI possibility to call the server
}
...
}
При этом возникают некоторые вопросы:
1. Как организоватьвзаимосвязь между сервером и GUI, когда они одновременно являются серверами и клиентами друг друга?
2. Как, например, реализовать GUI на VB? Простая тестовая программа показывает, что при такой конфигурации VB не может создать немодальное окно приложения, а модальное окно приведет к deadlock'у сервера.
3. Как инициализировать сервер, если он запущен как обычное приложени? Иными словами, если сервер имеет какой-то головной объект (скажем Application), то как и где его при этом создавать и удалять?
Если у кого-либо есть соображения по этим вопросом, буду очень признателен, если вы выскажетесь!
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: EXE-сервер с GUI
От:
Аноним
Дата:
20.01.02 09:20
Оценка:
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте chum, Вы писали:
VD>Ничего не понятно! Ты объясни что конкретно хочешь сделать и в чем проблемы?
Проблемы две. Скорее всего, они вызваны моим недостаточным знанием COM и ATL, и их решение для меня неочевидно. Итак:
1. Как реализовать локальный сервер (на ATL), GUI которого реализован другим компонентом (например, на MFC или VB)? Мне непонятно, как реализовать двухстороннюю связь между сервером и его GUI? Мне кажется, что connection point'ами тут не обойдешься (хотя, возможно я неправ). Кроме того, я написал простой тестовый сервер, котрый вызывал GUI-сервер, реализованный на VB в виде ActiveX DLL, и VB начал ругаться, что он не может создать при таком раскладе немодальное окно, а модальное окно "вгоняет в ступор" сервер.
2. Как написать на ATL локальный сервер, который можно запускать как обычное приложение, а не только "дергать" через COM? Код, сгенерированный визардом, вообще представляет собой программу, которая, будучи запущенной как приложение, висит в памяти и не дает никакой возможности себя закрыть, иначе как через task manager. Это, конечно, не проблема: можно изменить код так, что при пустой командной строке (без -embedding), программа будет завершать работу. Но кто мне скажет: в каком месте программы и как я должен инициализировать объекты сервера? Т. е., если, например, пользователь сервера автоматизации начинает работать с объектом Application, а потом получает через него все остальное, то где и как создавать объект Application, если EXE-шник запущен как обычное приложение? И где этот объект уничтожать? Причем, так, чтобы сервер завершил при этом работу (при условии отсутствия COM-клиентов).
Надеюсь, что теперь объяснил более толково. Прошу разъяснить мне "политику партии" по этим вопросам.
Re[3]: EXE-сервер с GUI
От:
Аноним
Дата:
20.01.02 09:39
Оценка:
Здравствуйте IT, Вы писали:
IT>Здравствуйте VladD2, Вы писали:
VD>>Ничего не понятно! Ты объясни что конкретно хочешь сделать и в чем проблемы?
IT>Скорее всего вот это — http://www.rsdn.ru/article/?com/autoatl.xml
Большое спасибо. Очень интересная статья. Но к сожалению, это не совсем то, что мне надо. Тут просто программа, написанная на MFC и имеющая некий GUI, предоставляет, с помощью ATL, интерфейсы автоматизации.
А мне надо, чтобы к серверу, написанному на ATL и реализующему всю прграммную логику, можно было подключать разные GUI (естественно: один GUI в любой момент времени), реализованные другими компонентами и имеющими, естественно, заранее известные ATL-серверу интерфейсы. Т.е., мне нужна двухсторонняя связь между ядром и GUI. Возможно ли реализвать ее только с помощью connection points? И сможет ли, например, кто-нибудь написать упрощенный GUI на VB, реализующий такую двухстороннюю связь?
Ты описываешь реализацию! Свое видение тык сызыть, а нужно было бы описать конкретную проблему! Т.е. задачу в челавеческих терминах. Что есть сервер (его предназначение)? Зачем сменный интерфейс? Чем интерфейс отличается от клиента? А то похоже, что ты путаешь понятие GUI и клиента.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте Аноним, Вы писали:
А>А мне надо, чтобы к серверу, написанному на ATL и реализующему всю прграммную логику, можно было подключать разные GUI (естественно: один GUI в любой момент времени), реализованные другими компонентами и имеющими, естественно, заранее известные ATL-серверу интерфейсы. Т.е., мне нужна двухсторонняя связь между ядром и GUI. Возможно ли реализвать ее только с помощью connection points? И сможет ли, например, кто-нибудь написать упрощенный GUI на VB, реализующий такую двухстороннюю связь?
Всё же я не совсем понял задачу.
Connection points — это лишь стандартизованный вариант подключения к событиям объекта, использующийся, грубо говоря, в Automation. Никто не мешает придумать свой, более подходящий к конкретной задаче механизм. Например, в OLE DB используется похожий, но свой механизм подключения к событиям объекта. В принципе, тебе просто нужно решить кто будет инициатором этого действа, затем нужно обменяться интерфейсами и вперёд.
Если нам не помогут, то мы тоже никого не пощадим.
Приношу свои извенения. В строках приведенных ниже массивы нужно называть не psa, а ppsa, т.е. указатель на указатель на Safe Array, отражаю тем самым, что это [out]-параметр.
VD>
Большое спасибо всем за участие! Special thanks to IT & VladD2.
Помощь была крайне полезной.
Жалко, что нельзя реализовать пользовательский интерфейс программы в отдельноподключаемом компоненте. Это была одна из главных идей: дать пользователю сервера возможность "прилеплять" к нему свои собственные пользовательские интерфейсы.
Можно, конечно, писать для каждого нового GUI новый сервер, его реализующий, который, в свою очередь, является клиентом ядра. Но тогда у каждой такой программы будет свой CLSID (или ProgID). А тут, собственно, идея была в том, чтобы этот сервер все время вызывался клиентами совершенно единообразно, вне зависимости от того, какой GUI к нему в данный момент "прилеплен".
Далее:
Я понимаю, что если, например, ядро реализовать inproc сервером, а основная программа с пользовательским интерфейсом будет для него клиентом, то мой второй вопрос отпадает сам собой. Но все-таки (в принципе), интересно узнать:
Как на ATL написать локальный сервер, который может запускаться и закрываться как обычное приложение? Где и как создавать и удалять объекты сервера?
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте chum, Вы писали:
C>Жалко, что нельзя реализовать пользовательский интерфейс программы в отдельноподключаемом компоненте. Это была одна из главных идей: дать пользователю сервера возможность "прилеплять" к нему свои собственные пользовательские интерфейсы.
Не совсем понятно, о чем страдания. Если у тебя будет сервер (ядро) реализующий некоторые интерфесы, кто угодно может лепить какие-угодно и на чем угодно свои GUI и использовать для собственно перевода твой сервер, дергая его интерфейсы.
C>Можно, конечно, писать для каждого нового GUI новый сервер, его реализующий, который, в свою очередь, является клиентом ядра. Но тогда у каждой такой программы будет свой CLSID (или ProgID).
А зачем программе — GUI быть сервером и иметь CLSID (или ProgID)?
C>А тут, собственно, идея была в том, чтобы этот сервер все время вызывался клиентами совершенно единообразно, вне зависимости от того, какой GUI к нему в данный момент "прилеплен".
Интерфейсы твоего сервера и будут стандартом для всех программ-GUI, которые его будут пользовать, вызывать его не единообразно они просто не будут иметь никакой физической возможности.
Здравствуйте Аноним, Вы писали:
А>2. Как написать на ATL локальный сервер, который можно запускать как обычное приложение, а не только "дергать" через COM? Код, сгенерированный визардом, вообще представляет собой программу, которая, будучи запущенной как приложение, висит в памяти и не дает никакой возможности себя закрыть, иначе как через task manager.
Вместе с WTL распостраняется мастер, который может создавать MDI, SDI или Dialog проги (exe), являющиеся серверами автоматизации. Можно создать такую прогу, в ней реализовать сервер и некий (тестовый) GUI работающий со своим же сервером. Те, кого не устраивает этот стандартный GUI напишут своего клиента, при этом используя твой сервер они будут запускать этот exe в "безинтерфейсном" варианте, весь код для этого мастер создает сам.
Здравствуйте Willi, Вы писали:
W>To IT & Vlad2: W>Может нарисуете человеку картинку, шоб понятней было, вот мол сервер, вот его интерфейсы, а вот клиенты с GUI.
Видимо, у меня не очень хорошо получается объяснить проблему. Очень трудно это сделать в рамках форума. Но я все-таки постараюсь. Прошу только принять во внимание, что программу-переводчик я привел только для примера! Реальное приложение иммет совсем другую специфику, на объяснение которой уйдет на порядок больше времени. Прошу всех, кто хочет помочь советом (я десйствительно очень ценю помощь), не зацикливаться на вопросе: зачем реализовывать GUI в отдельном компоненте. Лучше ответьте: как?
Попробую зайти с другой стороны. Хотите картинок, их есть у меня:
КЛИЕНТ_ПЕРЕВОДЧИКА /*1..n клиенты работают с переводчиком через CLSID_TRANSLATOR*/
|
| CLSID_TRANSLATOR (ITranslate)
v
СЕРВЕР_ПЕРЕВОДЧИК(ЯДРО) /*реализуется разработчиком ядра*/
|
| CLSID_GUIXXXXX (IGUI)
v
СЕРВЕР_GUI /*может быть реализован сторонним разработчиком*/
Специфика программы такова, что пользователю КЛИЕНТ_ПЕРЕВОДЧИКА может понадобиться видеть как окно КЛИЕНТ_ПЕРЕВОДЧИКА, так и окно СЕРВЕР_ПЕРЕВОДЧИКА (т.е. окно СЕРВЕРА_GUI). При этом, пользователь КЛИЕНТ_ПЕРЕВОДЧИКА (а вместе с ним и СЕРВЕР_ПЕРЕВОДЧИКА) воспртнимает окно СЕРВЕР_ПЕРЕВОДЧИКА как данность и может совершенно не догадывается, что оно где-то как-то отдельно.
СЕРВЕР_GUI может быть разработано кем угодно. Представьте себе, что кто-то (скажем фирма Translators Ltd.) разработал СЕРВЕР_ПЕРЕВОДЧИК(ЯДРО) и опубликовал интерфейс IGUI для сторонних разработчиков. Кто-то разработал КЛИЕНТ_ПЕРЕВОДЧИКА. А пользователь КЛИЕНТ_ПЕРЕВОДЧИКА время от времени лазает на сайт www.supertranslator.com, чтобы скачать и установить новую Контекст-оболочку, Лингво-оболочку или Мультилекс-оболочку (которые день и ночь пишут сторонние разработчики) для СЕРВЕР_ПЕРЕВОДЧИКА.
Теперь еще раз о двухсторонней связи СЕРВЕР_ПЕРЕВОДЧИК(ЯДРО)<--->СЕРВЕР_GUI:
Представьте, что пользователь КЛИЕНТ_ПЕРЕВОДЧИКА может захотеть перевести какое-то СЛОВО в документе КЛИЕНТ_ПЕРЕВОДЧИКА. Он жмет там какую-то кнопочку и СЛОВО летит из КЛИЕНТ_ПЕРЕВОДЧИКА в СЕРВЕР_ПЕРЕВОДЧИК(ЯДРО) (через ITranslate), а затем перевод отображается в окне СЕРВЕРА_GUI (через IGUI). А может набрать это СЛОВО прямо в окне СЕРВЕРА_GUI и оно полетит сначала в СЕРВЕР_ПЕРЕВОДЧИК(ЯДРО) (непонятно через какой интерфейс), а затем обратно полетит перевод (через IGUI).
Вот, собственно, в дух словах и все.
Так в каком месте технологии COM это все почитать?
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте chum, Вы писали:
C>Попробую зайти с другой стороны. Хотите картинок, их есть у меня: C> C>КЛИЕНТ_ПЕРЕВОДЧИКА /*1..n клиенты работают с переводчиком через CLSID_TRANSLATOR*/ C> | C> | CLSID_TRANSLATOR (ITranslate) C> v C>СЕРВЕР_ПЕРЕВОДЧИК(ЯДРО) /*реализуется разработчиком ядра*/ C> | C> | CLSID_GUIXXXXX (IGUI) C> v C>СЕРВЕР_GUI /*может быть реализован сторонним разработчиком*/
Бррррр
Не понимаю. Зачем нужен СЕРВЕР_GUI?
Ты пишешь ядро для перевода — некий COM server который предоставляет набор COM интерфейсов для перевода, получения синонимов, выбора словаря, внесения изменений в словари и т.п. а также, возможно, поддерживает механизм уведомления клиентов об изменениях в словарях, добавлении новых словарей и т.п.
Всё.
На этом можно останавливаться. Теперь дав подробное описание своих интерфейсов ты предлагаешь всем желающим писать клиентов твоего сервера — GUI оболочки для перевода. Ну и наверное сам пишешь приложение-оболочку которое пользуется этими же интерфейсами, дабы твой продукт мог существовать самостоятельно.
Здравствуйте Willi, Вы писали:
W>Бррррр W>Не понимаю. Зачем нужен СЕРВЕР_GUI?
W>Ты пишешь ядро для перевода — некий COM server который предоставляет набор COM интерфейсов для перевода, получения синонимов, выбора словаря, внесения изменений в словари и т.п. а также, возможно, поддерживает механизм уведомления клиентов об изменениях в словарях, добавлении новых словарей и т.п.
W>Всё.
W>На этом можно останавливаться. Теперь дав подробное описание своих интерфейсов ты предлагаешь всем желающим писать клиентов твоего сервера — GUI оболочки для перевода. Ну и наверное сам пишешь приложение-оболочку которое пользуется этими же интерфейсами, дабы твой продукт мог существовать самостоятельно.
W>Или я не догоняю?
W>С уважением, Willi.
Ну, грубо говоря, "не догоняете". Перечитайте еще раз предыдущее сообщение (22.01 19:08). И еще раз говорю: не зацикливайтесь на том, что это программа-переводчик (это упрощение, просто пример) и на вопросе "зачем это надо?". Исходный вопрос был "как?".
СЕРВЕР_GUI нужен, чтобы можно было менять пользовательский интерфейс программы без смены ядра и без изменения КЛИЕНТА_ПЕРЕВОДЧИКА (всех уже написанных КЛИЕНТОВ_ПЕРЕВОДЧИКОВ), которые обращаются к СЕРВЕРУ_ПЕРЕВОДЧИКУ через CLSID ядра! Ему нельзя подсовывать каждый раз новую реализацию GUI с агрегированным ядром и новым CLSID (или ProgID)!
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте chum, Вы писали:
C>Ну, грубо говоря, "не догоняете". Перечитайте еще раз предыдущее сообщение (22.01 19:08). И еще раз говорю: не зацикливайтесь на том, что это программа-переводчик (это упрощение, просто пример) и на вопросе "зачем это надо?". Исходный вопрос был "как?".
C>СЕРВЕР_GUI нужен, чтобы можно было менять пользовательский интерфейс программы без смены ядра и без изменения КЛИЕНТА_ПЕРЕВОДЧИКА (всех уже написанных КЛИЕНТОВ_ПЕРЕВОДЧИКОВ), которые обращаются к СЕРВЕРУ_ПЕРЕВОДЧИКУ через CLSID ядра! Ему нельзя подсовывать каждый раз новую реализацию GUI с агрегированным ядром и новым CLSID (или ProgID)!
У тебы в голове каша. Ты все переставляешь с ног на голову...
Если речь идет о скинах (я правильно понимаю) как в WinAmp-е, но зачем вообще о сервере говорить. Просто сказал бы нужен универсальный способ менять скины клиентов.
Если о чем другом, то... ну, короче ОЧЕНЬ_ПЛОХО_ОБЪЯСНЯЕШЬ!
Ты уж лучше попробуй довести до нас идею НАСТОЯЩЕГО проекта, а то этот пример явно не гадится.
Ну, зачем серверу, задача которого заниматься переводом, менять клиенту внешний вид?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте chum, Вы писали:
C>Ну, грубо говоря, "не догоняете". Перечитайте еще раз предыдущее сообщение (22.01 19:08).
Давай я лучше попробую это сообщение переписать
C>СЕРВЕР_GUI нужен, чтобы можно было менять пользовательский интерфейс программы без смены ядра и без изменения КЛИЕНТА_ПЕРЕВОДЧИКА (всех уже написанных КЛИЕНТОВ_ПЕРЕВОДЧИКОВ), которые обращаются к СЕРВЕРУ_ПЕРЕВОДЧИКУ через CLSID ядра! Ему нельзя подсовывать каждый раз новую реализацию GUI с агрегированным ядром и новым CLSID (или ProgID)!
Ok, у нас уже вырисовывается 3 компонента. Ядро, отображалка и некая управляющая программа. Функции ядра — переводить, искать, загружать, удалять, обновлять, делать любую другую полезную и не очень работу. При возникновении каких-то неординарных событий в ядре, о которых должны знать клиенты, это ярдо должно их информировать, например, посредством генерации событий. Ядро может использоваться управляющей программой, либо любой другой, которя знает его интерфейс. Желательно, что бы ядро не имело понятия о том, что творится вокруг и зачем его пользуют.
Отображалка. Одна или несколько, которая должна отображать то, что ей скажут. Для этого она должна реализовывать некий стандартный интерфейс, за который её будут дёргать и по которому она будет сообщать действия пользователя, который опять нажал какую-то левую кнопку. Она не должна иметь не малейшего понятия, откуда взяты те данные, которые она отображает. Её сказали нарисовать 'A' она должна нарисавать 'A', 'B' — 'B'. Если нажата кнопка anykey, она должна незамедлительно об этом сообщить.
Управляющая программа. Она знаёт всё, но не умеет ни делать что-то полезное, ни даже рисовать. Только управлять... этакий танагер, блин. Манагер, как ему и положено, должен управлять, одному давать команду попереводить чего-нибудь, другому поотображать как-нибудь.
В рузультате имеет модульную архитектуру и теперь уже можно решать как будет реализован каждый модуль. Влад совершенно чётко обрисовал как можно построить ядро и какие получить от этого бонусы. Про скины тоже упомянули, обычно их делают в виде плагинов и здесь тоже можно смело применять COM интерфейсы. Управляющая программа — дело фантазии.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, Вы писали:
IT>В рузультате имеет модульную архитектуру и теперь уже можно решать как будет реализован каждый модуль. Влад совершенно чётко обрисовал как можно построить ядро и какие получить от этого бонусы. Про скины тоже упомянули, обычно их делают в виде плагинов и здесь тоже можно смело применять COM интерфейсы. Управляющая программа — дело фантазии.
Все это замечательно. Пускай не ядро общается с GUI, а управляющая программа (manager). Manager (как и в моем случае ядро) будет клиентом компонента, реализующего GUI (можете не называть его сервером, если вам так не нравится, но раз он реализует какие-то интерфейсы, за которые его "дергает" manager, то это и будет сервер). Это не принципиально! Принципиально то, что более или менее сложный пользовательский интерфейс — это не скин! Это не просто "отображалка". Он предполагает обратную связь. Те же вышеупомянутые скины WinAmp'а просто меняют его внешний вид, но все управление (обратная связь) вне их компетенции! WinAmp не дает возможности сторонним разработчикам менять набор операций управления таким простым набором данных, как список песен. Вы не можете подключить к WinAmp'у свой хитрый способ пригрывания мелодий в очередности дат их написания!
Вы спросите меня: а при чем тут GUI? GUI тут не при чем. Здесь проблема вся в том, что нужен некий сервер, к которому присоединяются клиенты и работают с ним совершенно единообразным образом. И этот же сервер использует (уже в качестве клиента!) некий другой компонент с обратной связью.
Вы все говорите: давай поменяем местами сервер (ядро) и этот "другой" компонент. Благо сервер — величина постоянная, а этот "другой" — переменная. Но тогда разрывается связь между нашим первоначальным сервером и его клиентами!
Тут присутствует некая цепочка взаимодействий компонентов. А вы пытаетесь разбить эту цепочку на звенья и каждое отдельное звено реализовать простейшим образом. Проблема же в том, как создать сервер, который может иметь некие подключаемые (заменяемые) компоненты с обратной связью. Ключевое словосочетание здесь "обратная связь". Упомянутые plug-in'ы, насколько я понимаю, такой связи не имеют. Сервер просто сливает в них некие данные и получает результат обработки. Под обратной связью я понимаю возможность получения подключаемым компонентом от сервера некой дополнительной информации, помимо той, что сервер счел достаточным сообщить подключаемому компоненту при подключении. Может ли подключаемый компонент обращаться к серверу через его интерфейсы или это в принципе невозможно?
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте chum, Вы писали:
C>Тут присутствует некая цепочка взаимодействий компонентов. А вы пытаетесь разбить эту цепочку на звенья и каждое отдельное звено реализовать простейшим образом. Проблема же в том, как создать сервер, который может иметь некие подключаемые (заменяемые) компоненты с обратной связью. Ключевое словосочетание здесь "обратная связь". Упомянутые plug-in'ы, насколько я понимаю, такой связи не имеют. Сервер просто сливает в них некие данные и получает результат обработки. Под обратной связью я понимаю возможность получения подключаемым компонентом от сервера некой дополнительной информации, помимо той, что сервер счел достаточным сообщить подключаемому компоненту при подключении. Может ли подключаемый компонент обращаться к серверу через его интерфейсы или это в принципе невозможно?
Если я правильно понимаю, то тебе нужно что-то вроде модели взаимодействия инетерфейсов IStorage — IPersistStorage.
Т.е. ты получаешь у сервера некий интерфейс ( IPersistStorage )
и просишь его что-то сделать ( IPersistStorage::Load ),
подсовывая свой интерфейс ( IStorage ),
сервер в процессе выплнения того о чем ты его попросил, вызывает твои методы для выполнения элементарных действий.
Понятное дело названия интерфейсов даны только в качестве примера, чтобы проиллюстрировать механизм взаимодействия.
Если я опять не догнал, то тогда соглашуcь с VladD2, ОЧЕНЬ_ПЛОХО_ОБЪЯСНЯЕШЬ.
Здравствуйте Willi, Вы писали:
W>Если я правильно понимаю, то тебе нужно что-то вроде модели взаимодействия инетерфейсов IStorage — IPersistStorage.
W>Т.е. ты получаешь у сервера некий интерфейс ( IPersistStorage ) W>и просишь его что-то сделать ( IPersistStorage::Load ), W>подсовывая свой интерфейс ( IStorage ), W>сервер в процессе выплнения того о чем ты его попросил, вызывает твои методы для выполнения элементарных действий.
Ну, вроде того. Только вопрос не в том: сможет ли сервер вызывать методы IStorage клиента. Это не вопрос. Вопрос: сможет ли сервер вызывать методы других интерфейсов сервера? И не только в то время, когда клиент обратился к серверу, а тогда, когда ему это надо. Могут ли два компонента одновременно функционировать меняясь ролями? Обращаясь попеременно друг к другу, как к серверу? При этом, один из этих компонентов создан другим.
По поводу
W>ОЧЕНЬ_ПЛОХО_ОБЪЯСНЯЕШЬ
Я же не спрашиваю: как из указателя на IUnknown получить остальные интерфейсы сервера?
Тут все гораздо сложнее и в двух словах не объяснишь.
Я попытался начать с простого, вы спрашиваете "зачем?" Я нарисовал глобальную картину, вы говорите: "сложно". Я не знаю, как еще объяснять. Как только я упрощаю, вы начинаете мыслить простыми категориями и опять спрашиваете: "зачем?". Замкнутый круг.
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Ура! Кажется что-то начинает проясняться! Спасибо за терпение. Видимо мне надо было сразу начинать с [9] собощения :)
C>>2. Как, например, реализовать GUI на VB?
W>Не понятно, что значит как? Садишься и пишешь.
C>>Простая тестовая программа показывает, что при такой конфигурации VB не может создать немодальное окно приложения, а модальное окно приведет к deadlock'у сервера.
W>Ну так не создавай модальных окон.
Ну, дело в том, что я не силен в VB. Я просто для проверки своей идеи попробовал написать ActiveX DLL на VB с интерфейсом IGUI. И подсунул ему (этому ActiveX'у) указатель на интерфейс клиента. Из VB ActiveX отлаживается и запускается замечательно. А при попытке использования ее из клиента, VB ругнулся, что из этого хост-приложения не может быть создано немодальное окно, смените тип проекта на ActiveX EXE с модальным окном (не помню, как это сообщение звучит в оригинале). А я просто пытался в методе IGUI::Run() отобразить некую форму (SomeForm.Show()).
Что я делаю неправильно?
W>Как работате любой EXE COM server. Ты можешь указать что при зоздании нового экземпляра сервера не нужно запускать новы процесс а пользоваться сцществующим. Просто создаваемые экземпляры объектов, могут редиректить вызовы в какой-нить общий объект.
W>Что-то вроде.
W>
Ну я приблизительно так себе и представлял. Я только не пойму: в каком месте сгенерированного ATL-wizard'ом кода создавать (и удалять) экземпляр CServer? Полагаю, что где-то в _tWinMain(), если EXE-шник запушен без ключей командной строки. Или я ошибаюсь?
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте chum, Вы писали:
C>Ура! Кажется что-то начинает проясняться! Спасибо за терпение. Видимо мне надо было сразу начинать с [9] собощения
Я рад.
C>Ну, дело в том, что я не силен в VB. Я просто для проверки своей идеи попробовал написать ActiveX DLL на VB с интерфейсом IGUI. И подсунул ему (этому ActiveX'у) указатель на интерфейс клиента. Из VB ActiveX отлаживается и запускается замечательно. А при попытке использования ее из клиента, VB ругнулся, что из этого хост-приложения не может быть создано немодальное окно, смените тип проекта на ActiveX EXE с модальным окном (не помню, как это сообщение звучит в оригинале). А я просто пытался в методе IGUI::Run() отобразить некую форму (SomeForm.Show()).
C>Что я делаю неправильно?
Дело в том что я тоже не силен в VB.
C>Ну я приблизительно так себе и представлял. Я только не пойму: в каком месте сгенерированного ATL-wizard'ом кода создавать (и удалять) экземпляр CServer? Полагаю, что где-то в _tWinMain(), если EXE-шник запушен без ключей командной строки. Или я ошибаюсь?
Видимо так. На ATL я серьезного ничего не писал, так книжки читал и баловался немного. В проекте на MFC я бы это делал в InitInstance.
Здравствуйте Willi, Вы писали:
C>>Ну я приблизительно так себе и представлял. Я только не пойму: в каком месте сгенерированного ATL-wizard'ом кода создавать (и удалять) экземпляр CServer? Полагаю, что где-то в _tWinMain(), если EXE-шник запушен без ключей командной строки. Или я ошибаюсь?
W>Видимо так. На ATL я серьезного ничего не писал, так книжки читал и баловался немного. В проекте на MFC я бы это делал в InitInstance.
Кроме того, если использовать что-то типа предложенных CServer и CServerWrapper и создавать в _tWinMain() экземпляр CServer, то непонятно: а кто будет создавать экземпляр CServerWrapper, чтобы предоставить серверу (подключаемому компоненту) свои интерфейсы? Тогда нужно создавать экземпляр не CServer, а CServerWrapper. Но как тогда сделать, чтобы ATL'евский контейнер компонентов учел этот созданный напрямую компонент? Я имею ввиду счетчик компонентов: его "ручками" увеличивать и уменьшать или это можно автоматизировать?
Ну например: я запустил сервер как обычное приложение, а потом к нему кто-то подключился. Я приложение закрыл, но остался еще подключенный клиент.
Как сделать, чтобы это все работало корректно?
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте Willi, Вы писали:
W>Прям как в том анекдоте: "Ты, Маугли, кого хочешь достанешь"
Ну, ответы на вопросы форума — дело сугубо добровольное.
W>Не обижайся. Но у тебя действительно каша в голове. Надо бы почитать что-нить (ну например ATL Internals), примерчики посмотреть.
А ответы в стиле "почитай чего-нибудь" еще и малоинформативны. Если человек задает вопрос в форуме, то это, скорее всего, означает, что он не нашел ни в одной книжке ответа на свои вопросы.
Вы, например, пишете:
C>Кроме того, если использовать что-то типа предложенных CServer и CServerWrapper и создавать в _tWinMain() экземпляр CServer, то непонятно: а кто будет создавать экземпляр CServerWrapper,
W>ClassFactory
А кто ж ClassFactory-то создаст, если сервер запущен не через COM? Или Вы предлагаете в теле сервера создавать с помощью ClassFactory компоненты, которые он сам же и реализует? Сомневаюсь. Подозреваю, что имелось ввиду что-то другое.
Точно также сомневаюсь, что ответ на этот вопрос можно найти в ATL Internals.
Если есть возможность отдать человеку все, не прося ничего взамен — отдай. Если тебе один раз из десяти долг отдадут — будешь богатым.
Здравствуйте chum, Вы писали:
C>Ну, ответы на вопросы форума — дело сугубо добровольное.
Ну я же просил, не обижайся.
C>А ответы в стиле "почитай чего-нибудь" еще и малоинформативны. Если человек задает вопрос в форуме, то это, скорее всего, означает, что он не нашел ни в одной книжке ответа на свои вопросы.
C>Вы, например, пишете:
C>>Кроме того, если использовать что-то типа предложенных CServer и CServerWrapper и создавать в _tWinMain() экземпляр CServer, то непонятно: а кто будет создавать экземпляр CServerWrapper,
W>>ClassFactory
C>А кто ж ClassFactory-то создаст, если сервер запущен не через COM? Или Вы предлагаете в теле сервера создавать с помощью ClassFactory компоненты, которые он сам же и реализует? Сомневаюсь. Подозреваю, что имелось ввиду что-то другое.
Вот я и говорю, почитай. Из твоих вопросов становится ясно, что ты весьма смутно представляешь как работает COM. А объяснить все это в рамках форума дело крайне сложное.
Здравствуйте chum, Вы писали:
C>Здравствуйте Willi, Вы писали:
C>Ура! Кажется что-то начинает проясняться! Спасибо за терпение. Видимо мне надо было сразу начинать с [9] собощения
Да, вроде, пока ничего путного.
C>Ну, дело в том, что я не силен в VB. Я просто для проверки своей идеи попробовал написать ActiveX DLL на VB с интерфейсом IGUI. И подсунул ему (этому ActiveX'у) указатель на интерфейс клиента. Из VB ActiveX отлаживается и запускается замечательно. А при попытке использования ее из клиента, VB ругнулся, что из этого хост-приложения не может быть создано немодальное окно, смените тип проекта на ActiveX EXE с модальным окном (не помню, как это сообщение звучит в оригинале). А я просто пытался в методе IGUI::Run() отобразить некую форму (SomeForm.Show()).
Для запуска немодальных форм, VB6 должен иметь доступ к очереди приложения. Скорее всего он сможет это сделать если exe-шник из которого загружать длл будет тоже написан на VB6.
Кстати, модальность форм, при правильном проектировании не должна мешать.
C>Что я делаю неправильно?
Честно?
Ты неправильно проектируешь приложение. (Дизайн).
Сервер конечно может иметь обратную связь с клиентом, но такие связи должны быть минимальны и продуманы.
Тебе не даром сказали не мешай GUI и сервер.
Сформулируй какя функциональность должна наращиваться, что должен делать сервер, и что клиент. Причем не смешивая понятий (обратные связи отбрось для простоты).
PS
Про WinAmp. Этот пример подходит здесь как нельзя кстати.
WinAmp не только имеет сменяемые Шкуры, но и имеет интерфейс т.н. плагинов — модулей подключающихся к WinAmp-у и добавляющих к ниму функциональности.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте Willi, Вы писали:
W>Видимо так. На ATL я серьезного ничего не писал, так книжки читал и баловался немного. В проекте на MFC я бы это делал в InitInstance.
Может тогда для начала изучить технологию которая выбрана как базавая?
Как можно говорить о дизайне, если общее понимание принципов, концепций и технологий, мягко скажем, не на уровне?
Никакого CServer в ATL нет. Экземпляры классов создаются в фабрике классов, но обо всем этом нужно читать в книгах и статьях, а не в форумах.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.