- •Добавление к com-серверу поддержки событий
- •Создание модели взаимодействия приложения хоста с плагинами
- •Описание com-интерфейсов, связанных с поддержкой плагинов
- •Создание com-интерфейсов, связанных с поддержкой плагинов
- •Создание com-классов, связанных с поддержкой плагинов
- •Создание класса, отвечающего за взаимодействие с плагинами
- •Код класса Plugin.Cs
- •Внесение косметических изменений в серверную часть
- •Строим своё меню с плагинами и идентификаторами
- •Вносим изменения в главную форму сервера
- •Создание первого плагина
- •Импорт типов с сервера
- •Создание класса для хранения внутреннего представления точек
- •Создание форм редактирования данных о точках
- •Реализация форм редактирования данных о точках
- •Реализация класса первого плагина
- •Создание третьего плагина
- •Делаем наш плагин com-видимым
- •Создание главной формы плагина
- •Реализация класса третьего плагина
- •Создание инсталлятора для плагина
- •Создание второго плагина
- •Создание главной формы плагина
- •Создание библиотеки типов
- •Реализация формы второго плагина
- •Реализация класса второго плагина
- •Добавление метода GetComClassName
- •Data Execution Prevention и его отключение
- •Тестирование совместной работы клиента и плагинов
- •Исходный код
Создание модели взаимодействия приложения хоста с плагинами
Прежде чем приступать к описанию интерфейсов, нам необходимо хоть как-то представлять себе, как будет работать наша система поддержки плагинов. Каждый плагин содержится в отдельном dll-файле – по одному плагину на одну либу. Во время работы программы (а именно во время запуска) мы будем динамически подключать библиотеки из заданной директории приложения. Допустим, что длл-ки мы будем искать в дирректории plugins, которая будет располагаться в рабочем каталоге приложения. Соответственно, мы будем стараться подцепить все лежащие там библиотеки. Когда юзер подключает новую библиотеку, она копируется нашей программой в эту директорию.
Библиотека может быть двух типов – в managed-коде (написанная на языках семейства .NET Framework), и обычная, в unmanaged-коде. Помимо этого, библиотека может содержать внутренний COM-сервер, а может и не содержать. Изобразим все возможные варианты:
Plugin |
Managed |
Unmanaged |
Содержит COM-сервер |
Managed, c COM |
Unmanaged, c COM |
Не содержит COM-сервера |
Managed, без COM |
Managed, без COM |
Соответственно, наше приложение-хост должно поддерживать все 4 варианта. Честно говоря, по заданию нам необходимо только 3 (мы не ставили себе целью делать unamnaged-плагины без COM), но я на всякий случай реализовал и такую функциональность, хотя и совершенно не тестировал её.
Проверить библиотеку на то, написана ли она в managed-коде довольно легко – нужно попытаться загрузить сборку (assembly) из библиотеки. В случае, если библиотека написана в unmaneged-коде, метод загрузки выбросит исключение. Также необходимо будет проверить библиотеку на наличие внутреннего COM-сервера. Для этого мы условимся, что библиотека с плагином и внутренним COM-сервером должна содержать метод GetCOMClassName, возвращающий строку, содержащую имя COM-класса плагина, который реализован в данной дллке.
public static string GetCOMClassName()
Каждому плагину будет доступен контроль за данными сервера в том же самом объёме, в котором он доступен клиенту. В этом смысле плагины ничем не отличаются от клиентов кроме того, что подключены к серверу постоянно и сразу после его запуска.
Каждый плагин имеет имя и описание, и предоставляет некоторое (вероятно пустое) множество действий, которые можно вызвать со стороны сервера, приложения-хоста. Для плагинов мы создадим меню на главном окне приложения и будем добавлять туда возможные действия:
Каждое возможное действие плагина имеет свой уникальный внутри этого плагина числовой идентификатор, имя и описание. Во время подключения плагина приложение-хост отправляет плагину экземпляр ZigzagControl и получает от него имя плагина, его описание и список доступных действий. Список действий добавляется в меню главного окна сервера. Во время выбора некоторого пункта меню с действием плагина приложение-хост запрашивает от плагина выполнение этого действия, передавая плагину идентификатор действия.
Теперь, когда мы обрисовали модель взаимодействия с плагинами, можно переходить к описанию интерфейсов.
