Приветствую вас уважаемые коллеги. Итак, проблема следующего плана. Пишу свой OPC DA2-сервер (без ATL). Клиентов ранее не писал и с COM'ом не работал. Но в целом все понятно, кроме одного — время жизни перечислителя на стороне OPC-клиента, т.е. когда он должен сделать Release.
Поясню:
Например, OPC-клиент запрашивает перечислитель атрибутов ячеек в группе IOPCGroup::CreateEnumerator(IN REFIID riid,OUT LPUNKNOWN *ppUnk) интерфейса IEnumOPCItemAttributes. У меня два варианта релизации интерфейса:
1. Создаю класс на подобии связанного списка (с внутренними методами типа "AddItem", "GetItem", "DeleteItem" и т.д.), реализую в нем интерфейсы перечислителя, а при вызове клиентом пичкаю этот список всеми существующими ячейками в данной группе. В этом случае объект будет жить сам по себе и уже не будет зависеть от реального набора ячеек в группе. Получается таким образом я делаю некий снимок ячеек группы на момент запроса CreateEnumerator.
2. Создаю агрегатный класс для группы IOPCGroup и реализую методы интерфейса IEnumOPCItemAttributes осуществляющие навигацию уже по существующему списку ячеек в группе. В данном случае перечислитель работает с "живыми" данными и при добавлении/удалении ячеек в группе вызов Next вернет существующие ячейки.
Первый вариант дает преимущество в том, что все используемые в OPC-сервере перечислители можно реализовать одним-двумя шаблонными классами и не париться. А вот во втором случае практически каждый перечислитель надо реализовывать отдельно.
В спецификации (может от невнимательности) не нашел КОГДА должен клиент освобождать перечислитель. Подскажите, как должен вести себя сервер с перечислителями, давать информацию которая имеется на момент запроса (вариант 1) (в данном случае клиент должен получить всю необходимую информацию и освободить объект), или учитывать что клиент, получив перечислитель, может "держать его вечно" (вариант 2)? Кто писал OPC-клиенты, подскажите как вы использовали эти объекты? Есть исходники с набросками OPC-сервера где реализовал первый вариант. Но по логике склоняюсь ко второму варианту.
Здравствуйте, KVakaMarshal, Вы писали:
KVM>... проблема следующего плана. Пишу свой OPC DA2-сервер (без ATL). Клиентов ранее не писал и с COM'ом не работал. Но в целом все понятно, кроме одного — время жизни перечислителя на стороне OPC-клиента, т.е. когда он должен сделать Release.
Я ОРС-сервера не писал, но общий ответ на вопрос "когда OPC-клиент должен сделать Release" такой: клиент должен сделать Release объекту тогда, когда его этот объект больше не интересует. К этому можно добавить, что спецификация интерфейса IEnumXXX не накладывает специальных требований к времени жизни этого объекта. Но, по крайней мере, справедливо, что время его жизни не может превышать время жизни породившей его коллекции, хотя и тут енумератор — это самостоятельный объект.
KVM>Первый вариант дает преимущество в том, что все используемые в OPC-сервере перечислители можно реализовать одним-двумя шаблонными классами и не париться. А вот во втором случае практически каждый перечислитель надо реализовывать отдельно.
Здравствуйте, Vi2, Вы писали:
Vi2>Я ОРС-сервера не писал, но общий ответ на вопрос "когда OPC-клиент должен сделать Release" такой: клиент должен сделать Release объекту тогда, когда его этот объект больше не интересует.
Ну, это понятно, попользовался — освободил. Вот меня и интересует, когда OPC-клиента (я говорю именно о OPC-клиенте и правилах которые регламентирует спецификация, в моем случае OPC DA2.05a) должен прекратить интересовать перечислитель. Я к тому, что возможно вообще нигде не регламентировано что должен OPC-клиент освобождать перечислитель, по схеме "получить перечислитель->прочитать данные->освободить перечислитель". Просто судя по тем чужим наброскам что у меня есть, то это именно так. У меня два пути:
1. Более простая и общая реализация всех перечислителей сервера (а их хватает), естественно с небольшой потерей производительности за счет промежуточного буферизирования. Этот вариант только для той схемы что я описал выше.
2. Более детальная реализация каждого метода интерфейсов IEnumXXX которые используются в OPC. В этом случае больше кода, но выше производительность и полная совместимость с любой схемой "жизни перечислителя".
Ясно, что алгоритмы различных перечислителей, как родных COM'овских, так и OPC'ишных в целом одинаковы. Очень компактно получается их реализовать шаблонно. Все прекрастно понимают гибкость шаблонных классов, поменял в одном месте, изменилось везде. Во втором варианте логика работы методов IEnumXXX:Skip и IEnumXXX:Next будет кардинально отличаться, за чет того что придется работать с разными "живыми данными", кому с группапи, кому с ячейками, а кому и с деревом сигналов. Шаблонным алгоритмом здесь уже не место. Просто если бы я знал что клиент как получит перечислитель сразу считает нужные данные и освободит его, то я сделал бы как в первом варианте, это проще.
Собственно поэтому мне нужен совет не столько по реализации интерфейсов не широкого мира COM, а именно узкой прослойки OPC.
Vi2>Вот и не парься, хотя можешь и попариться.
Ну вот я склоняюсь по своим соображениям и из выше сказанного что попарится надо. Но для уверенности пара советов бывалых OPC'истов мне бы не помешали.
Re[3]: Как правильно реализовывать IEnumXXX в OPC-сервере?
Наконец нашел Sample-исходники сервера OPC DA от OPC Foundation. Оба варианта приемлемы. Правильнее чем в OPC Foundation быть не может. Вопрос снялся. Можно закрыть тему.