Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lab3.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
3.22 Mб
Скачать

Создание первого плагина

Первый плагин должен предоставлять способ обозревать и редактировать данные точек ломаной. Он имеет возможность запрашивать данные точек с сервера и отправлять отредактированные данные обратно. Кроме того, он не должен напрямую использовать COM. Для того, чтобы его работа была возможной, мы реализовали дополнительный метод SetPoints в ZigzagControl. Я иногда использую слова «сервер» и «приложение-хост». Следует понимать, что это всё одно и то же приложение, просто термин «сервер» по отношению к плагинам как-то по-моему звучит некорректно, потому я стараюсь его использовать реже.

Вид главного окна плагина:

Для удобства я советую открыть солюшен первого плагина в примерах, там действительно очень много комментариев, которые делают код предельно понятным для всех, у кого был хоть какой-то, даже самый небольшой опыт программирования. Именно такой целью я и задавался, создавая данное руководство – предельная понятность.

Плагин – это отдельно компилируемая библиотека, потому создадим отдельное решение для нашего плагина. Запустите MS Visual Studio. Выберете «Создать проект».

Далее выбираем «Библиотека классов» и указываем имя проекта Plugin1.

Сразу же переименовываем файл Class1.cs в ZigzagPlugin.cs, соглашаемся с предложением переименовать класс в содержимом файла.

Добавляем новую ссылку.

Выбираем вкладку «Обзор», находим директорию с нашим сервером и указываем исполняемый файл в качестве ссылки. Он содержит .NET-сборку и все публичные типы оттуда будут экспортированы в наш проект.

Импорт типов с сервера

Нам потребуются некоторые типы, которые уже есть на сервере, а именно: Pair, Point, PluginConnectionInfo, PluginAction. Конечно, раз мы подключили сервер как ссылку, мы могли бы их использовать оттуда, но я хочу показать, что покуда у нас есть доступ к интерфейсам, то нам совершенно не обязательно опираться на чужие классы. Мы можем создавать свои реализации интерфейсов на стороне плагина и использовать их. Ведь серверу всё равно, с каким именно классом работать, для него существенно только то, какие интерфейсы эти классы реализуют. Потому сервер я только подключил для того, чтобы импортировать все его интерфейсы.

Реализуем вышеуказанные классы. Добавим файл Import.cs в проект.

В этом файле мы создадим несколько классов-аналогов серверным классам. Честно говоря, я просто собираюсь скопипастить серверные реализации этих классов и внести в них небольшие изменения. Итак, удаляем автоматически созданный класс Import и копипастим с сервера класс Pair.

/// <summary>

/// Пара, кортеж объектов длины 2.

/// Имеет левый и правый элемент.

/// </summary>

[ComVisible(true), Guid("9665CD7C-2CF6-4D73-B6C9-1EC865BE5931")]

public class Pair : IPair, IDisposable

{

object left, right;

/// <summary>

/// Конструктор экземпляра класса Pair.

/// </summary>

public Pair()

{

left = null;

right = null;

ComServer.Lock();

}

/// <summary>

/// Конструктор экземпляра класса Pair.

/// </summary>

/// <param name="left">Левый объект пары.</param>

/// <param name="right">Правый объект пары.</param>

public Pair(object left, object right)

{

this.left = left;

this.right = right;

ComServer.Lock();

}

#region Члены IPair

/// <summary>

/// Возвращает левый объект пары.

/// </summary>

public object Left

{

get { return left; }

}

/// <summary>

/// Возвращает правый объект пары.

/// </summary>

public object Right

{

get { return right; }

}

#endregion

#region Члены IDisposable

bool isDisposed = false;

/// <summary>

/// Уничтожает экземпляр класса.

/// </summary>

public void Dispose()

{

if (!isDisposed)

{

ComServer.Unlock();

isDisposed = true;

}

}

#endregion

/// <summary> Деструктор класса, который будет автоматически освобождать объект после того, как не осталось ни одной ссылки на него. </summary>

~Pair()

{

Dispose();

}

}

Смотрим, что в нём можно удалить. Во-первых, строчка «[ComVisible(true), Guid("9665CD7C-2CF6-4D73-B6C9-1EC865BE5931")]» нам больше не понадобится, мы не собираемся экспонировать объекты плагина в COM, удаляем её. Строки «ComServer.Lock();» тоже уже не нужны. Весь регион с методом Dispose и деконструктором ~Pair() – туда же. Так как интерфейс IPair находится в пространстве имён сервера, то заменяем строку объявления класса на вот эту:

public class Pair : ZigzagServer.IPair

Посмотрим, что у нас в итоге получилось.

/// <summary>

/// Пара, кортеж объектов длины 2.

/// Имеет левый и правый элемент.

/// </summary>

public class Pair : ZigzagServer.IPair

{

object left, right;

/// <summary>

/// Конструктор экземпляра класса Pair.

/// </summary>

public Pair()

{

left = null;

right = null;

}

/// <summary>

/// Конструктор экземпляра класса Pair.

/// </summary>

/// <param name="left">Левый объект пары.</param>

/// <param name="right">Правый объект пары.</param>

public Pair(object left, object right)

{

this.left = left;

this.right = right;

}

#region Члены IPair

/// <summary>

/// Возвращает левый объект пары.

/// </summary>

public object Left

{

get { return left; }

}

/// <summary>

/// Возвращает правый объект пары.

/// </summary>

public object Right

{

get { return right; }

}

#endregion

}

Как вы видете, это уже совершенно другой класс, но который так же реализовывает IPair, как и его серверный аналог.

Сходным образом создадим аналоги классов Point, PluginAction и PluginConnectionInfo. Выглядеть они будут вот так:

public class Point : ZigzagServer.IPoint

{

int x, y;

/// <summary>

/// Конструктор экземпляра класса Point.

/// </summary>

public Point()

{

x = 0;

y = 0;

}

/// <summary>

/// Конструктор экземпляра класса Point.

/// </summary>

/// <param name="x">X-координата точки.</param>

/// <param name="y">Y-координата точки.</param>

public Point(int x, int y)

{

this.x = x;

this.y = y;

}

#region Члены IPoint

/// <summary>

/// Получает X-координату точки.

/// </summary>

public int X

{

get { return x; }

}

/// <summary>

/// Получает Y-координату точки.

/// </summary>

public int Y

{

get { return y; }

}

#endregion

}

/// <summary>

/// Информация о плагине

/// </summary>

public class PluginConnectionInfo : ZigzagServer.IPluginConnectionInfo

{

string pluginName, pluginDescription;

ZigzagServer.IPluginAction[] actions = new ZigzagServer.IPluginAction[0];

bool isInited = false;

#region Члены IPluginConnectionInfo

/// <summary>

/// Получает имя плагина.

/// </summary>

public string PluginName

{

get { return pluginName; }

}

/// <summary>

/// Получает описание плагина.

/// </summary>

public string PluginDescription

{

get { return pluginDescription; }

}

/// <summary>

/// Получает массив возможных в плагине действий.

/// </summary>

public ZigzagServer.IPluginAction[] AvailableActions

{

get { return actions; }

}

/// <summary>

/// Инициализирует экземпляр информации подключения плагина.

/// </summary>

/// <param name="pluginName">Имя плагина.</param>

/// <param name="pluginDescription">Описание плагина.</param>

/// <param name="pluginActions">Список возможных действий, которые предоставляет плагин.</param>

public void Init(string pluginName, string pluginDescription, ZigzagServer.IPluginAction[] pluginActions)

{

try

{

this.pluginName = pluginName;

this.pluginDescription = pluginDescription;

actions = (ZigzagServer.IPluginAction[])pluginActions.Clone();

isInited = true;

}

catch { }

}

/// <summary>

/// Получает признак того, что экземпляр информации подключения плагина инициализирован.

/// </summary>

public bool IsInitialized

{

get { return isInited; }

}

#endregion

/// <summary>

/// Инициализирует экземпляр информации подключения плагина.

/// </summary>

/// <param name="pluginName">Имя плагина.</param>

/// <param name="pluginDescription">Описание плагина.</param>

/// <param name="pluginActions">Список возможных действий, которые предоставляет плагин. Сюда следует передавать массив IPluginAction-ов</param>

public PluginConnectionInfo(string pluginName, string pluginDescription, ZigzagServer.IPluginAction[] pluginActions)

{

try

{

Init(pluginName, pluginDescription, pluginActions);

}

catch { }

}

public PluginConnectionInfo()

{

}

}

/// <summary>

/// Действие, доступное из плагина.

/// </summary>

public class PluginAction : ZigzagServer.IPluginAction

{

int actionId;

string actionName;

string actionDescription;

bool isInited = false;

public PluginAction(int actionId, string actionName, string actionDescription)

{

Init(actionId, actionName, actionDescription);

}

public PluginAction()

{

}

#region Члены IPluginAction

/// <summary>

/// Получает идентификатор действия.

/// </summary>

public int ActionId

{

get { return actionId; }

}

/// <summary>

/// Получает строку помощи по данному действию.

/// </summary>

public string ActionDescription

{

get { return actionDescription; }

}

/// <summary>

/// Получает имя действия. Это значение будет отображено в меню.

/// </summary>

public string ActionName

{

get { return actionName; }

}

/// <summary>

/// Получает признак того, что экземпляр действия плагина инициализирован.

/// </summary>

public bool IsInitialized

{

get { return isInited; }

}

/// <summary>

/// Инициализирует экземпляр действия плагина.

/// </summary>

/// <param name="actionId">Идентификатор действия.</param>

/// <param name="actionName">Имя действия. Это значение будет отображено в меню.</param>

/// <param name="actionDescription">Описание действия.</param>

public void Init(int actionId, string actionName, string actionDescription)

{

this.actionId = actionId;

this.actionName = actionName;

this.actionDescription = actionDescription;

isInited = true;

}

#endregion

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]