
- •Добавление к com-серверу поддержки событий
- •Создание модели взаимодействия приложения хоста с плагинами
- •Описание com-интерфейсов, связанных с поддержкой плагинов
- •Создание com-интерфейсов, связанных с поддержкой плагинов
- •Создание com-классов, связанных с поддержкой плагинов
- •Создание класса, отвечающего за взаимодействие с плагинами
- •Код класса Plugin.Cs
- •Внесение косметических изменений в серверную часть
- •Строим своё меню с плагинами и идентификаторами
- •Вносим изменения в главную форму сервера
- •Создание первого плагина
- •Импорт типов с сервера
- •Создание класса для хранения внутреннего представления точек
- •Создание форм редактирования данных о точках
- •Реализация форм редактирования данных о точках
- •Реализация класса первого плагина
- •Создание третьего плагина
- •Делаем наш плагин com-видимым
- •Создание главной формы плагина
- •Реализация класса третьего плагина
- •Создание инсталлятора для плагина
- •Создание второго плагина
- •Создание главной формы плагина
- •Создание библиотеки типов
- •Реализация формы второго плагина
- •Реализация класса второго плагина
- •Добавление метода GetComClassName
- •Data Execution Prevention и его отключение
- •Тестирование совместной работы клиента и плагинов
- •Исходный код
Реализация класса третьего плагина
Этот класс будет многим похож на аналогичный в первом плагине, разве что мы не будем создавать копии серверных классов PluginConnectionInfo и PluginAction.
Первое, о чём мы вспомним, это то, что наше приложение-хост ищет класс ZigzagPlugin с методом GetComClassName. Сейчас наш класс находится в неймспейсе Plugin3, так что конечное имя класса будет Plugin3.ZigzagPlugin. Можно так же убить неймспейс, как мы это делали в прошлый раз, но давайте тут поступим иначе. Создадим вне пространства имён ещё один класс, в самом низу файла:
public class ZigzagPlugin
{
/// <summary>
/// Возвращает имя COM-класса плагина.
/// </summary>
/// <returns>Строка с именем COM-класса плагина.</returns>
public static string GetCOMClassName()
{
string result = typeof(Plugin3.ZigzagPlugin).FullName;
return result;
}
}
Теперь непосредственно о реализации класса плагина. Так как это будет COM-класс, единственный экспонируемый нашей библиотекой, зададим ему свойство COM-видимости и Guid. Кроме того, пропишем, что он реализует интерфейс IPlugin.
/// <summary>
/// COM-класс плагина для ZigzagServer.
/// </summary>
[ComVisible(true), Guid("9665CD7C-2CF6-4D73-B6C9-1EC865BE0930")]
public class ZigzagPlugin : ZigzagServer.IPlugin
Добавим в класс переменную с ZigzagControl и экземпляр главной формы. Кроме того, напишем пустой конструктор, дабы класс легко было создавать через COM.
object zigzagControl;
MainForm form;
public ZigzagPlugin()
{
}
Добавим пару вспомогательных методов, которые представляют собой вызываемые из плагина действия. Тут у нас их, для разнообразия, два, что гораздо больше, чем одно:).
/// <summary>
/// Отображает форму.
/// </summary>
private void ShowForm()
{
form = new MainForm(zigzagControl);
form.Show();
}
/// <summary>
/// Обновляет данные на форме, загружая их с сервера.
/// </summary>
private void RefreshFormData()
{
if (form != null)
form.RefreshData(zigzagControl);
}
С этим развязались, теперь можно переходить к основной нагрузке класса, реализации интерфейса IPlugin. Заведём регион:
#region IPlugin Members
#endregion
А потом добавим методы, которые будут практически идентичны методам предыдущего плагина. Вот метод подключения:
/// <summary>
/// Осуществляет подключение плагина.
/// </summary>
/// <param name="iZigzagControl">Интерфейс IZigzagControl объекта ZigzagControl.</param>
/// <param name="iPluginConnectionInfo">Интерфейс IPluginConnectionInfo. Передавайте сюда object, плагин должен его инициализировать на своей стороне.</param>
/// <returns>Возвращает код ошибки или 0, если ошибок не было.</returns>
public int Connect(object iZigzagControl, ref object iPluginConnectionInfo)
{
try
{
this.zigzagControl = iZigzagControl; // Сохраним переменную, дающую контроль над сервером. "Переменная всевластия", ага.
// Получим типы "действие плагина" и "информация подключения плагина".
Type pluginActionType = Type.GetTypeFromProgID("ZigzagServer.PluginAction");
Type pluginConnectionInfo = Type.GetTypeFromProgID("ZigzagServer.PluginConnectionInfo");
List<object> actionsList = new List<object>(); // Создадим список доступных из плагина действий.
//С помощью класса Activator создадим COM-объекты типов по их ProgID, имени.
actionsList.Add(Activator.CreateInstance(pluginActionType, new object[3] { 0, "Показать форму диаграмы", "Отображает форму динамической диаграмы на экране" })); // Добавим туда действия.
actionsList.Add(Activator.CreateInstance(pluginActionType, new object[3] { 1, "Отправить текущие данные на форму", "Актуализирует данные формы" }));
//Аналогичным образом создадим информацию подключения плагина.
iPluginConnectionInfo = Activator.CreateInstance(pluginConnectionInfo, new object[3] { "Zigzag dynamic diagram", "Динамическая диаграма", actionsList.ToArray() });
return 0;
}
catch (Exception exc)
{
System.Windows.Forms.MessageBox.Show(exc.Message + "\r\n" + exc.StackTrace, "Exception occured");
return -1;
}
}
Похоже на предыдущий, не правда ли? Только, разве что, на этот раз мы используем классы с сервера, а не пишем их сами, реализовывая серверные интерфейсы. Мы получаем тип по его имени, так называемому в COM «ProgID», и просим среду создать для нас экземпляр этого типа через статический класс Activator. Активатору мы передаём параметры для конструктора, а он ищет имя в реестре, находит бинарники, где содержится данный класс; опционально загружает их в память, вызывает конструктор нужного класса и возвращает нам инициализированный экземпляр с сервера.
Теперь реализуем метод отключения.
/// <summary>
/// Метод отключения плагина от приложения-хоста.
/// </summary>
/// <returns>Возвращает код ошибки или 0, если ошибок не было.</returns>
public int Disconnect()
{
try
{
((IDisposable)zigzagControl).Dispose(); // Освободим переменную ZigzagControl, чтобы сервер мог уменьшить счётчик выданных COM-экземпляров.
zigzagControl = null;
form.Close(); // Уничтожим главную форму.
form.Dispose();
form = null;
}
catch
{ }
return 0;
}
Тут всё совсем точь-в-точь, как в первом плагине, даже пояснять не интересно. Переходим к запросу выполнения действия:
/// <summary>
/// Метод выполнения действия плагина. Вызывается приложением-хостом.
/// </summary>
/// <param name="actionId">Числовой уникальный идентификатор действия.</param>
/// <returns>Возвращает код ошибки или 0, если ошибок не было.</returns>
public int PerformAction(int actionId)
{
switch (actionId)
{
case 0:
ShowForm(); // Отобразить форму.
return 0;
case 1:
RefreshFormData(); // Заставить форму запросить новые данные с сервера.
return 0;
default:
return -1; // Действия с запрошенным actionId не существует. Такие дела.
}
}
Тут тоже всё прозрачно.
Казалось бы, плагин реализован, ан нет. Для него теперь нужно сделать инсталлятор, который будет его регистрировать в COM.