
- •Добавление к com-серверу поддержки событий
- •Создание модели взаимодействия приложения хоста с плагинами
- •Описание com-интерфейсов, связанных с поддержкой плагинов
- •Создание com-интерфейсов, связанных с поддержкой плагинов
- •Создание com-классов, связанных с поддержкой плагинов
- •Создание класса, отвечающего за взаимодействие с плагинами
- •Код класса Plugin.Cs
- •Внесение косметических изменений в серверную часть
- •Строим своё меню с плагинами и идентификаторами
- •Вносим изменения в главную форму сервера
- •Создание первого плагина
- •Импорт типов с сервера
- •Создание класса для хранения внутреннего представления точек
- •Создание форм редактирования данных о точках
- •Реализация форм редактирования данных о точках
- •Реализация класса первого плагина
- •Создание третьего плагина
- •Делаем наш плагин com-видимым
- •Создание главной формы плагина
- •Реализация класса третьего плагина
- •Создание инсталлятора для плагина
- •Создание второго плагина
- •Создание главной формы плагина
- •Создание библиотеки типов
- •Реализация формы второго плагина
- •Реализация класса второго плагина
- •Добавление метода GetComClassName
- •Data Execution Prevention и его отключение
- •Тестирование совместной работы клиента и плагинов
- •Исходный код
Описание com-интерфейсов, связанных с поддержкой плагинов
Создадим три новых интерфейса. IPlugin будет содержать действия, доступные из плагина, а именно подключение, запрос на выполнение действия, отключение. IPluginConnectionInfo будет содержать информацию о плагине, такую как имя, описание, список доступных действий, флаг инициализированности и метод, инициализирующий поля структуры. Следующий интерфейс, IPluginAction, будет содержать информацию о действии, доступном из плагина – его идентификатор, имя и описание, а также флаг инициализированности и метод инициализации. Нарисую-ка таблицу.
Интерфейс |
Поля |
Методы |
Плагин (IPlugin) |
|
int Connect(object iZigzagControl, ref object iPluginConnectionInfo) – подключает плагин к приложению-хосту. int PerformAction(int actionId) – запрашивает выполнение действия с заданным идентификатором. int Disconnect() – отключает плагин от приложения-хоста. |
Информация о плагине (IPluginConnectionInfo) |
string PluginName – получает имя плагина. string PluginDescription – получает описание плагина. IPluginAction[] AvailableActions – получает список доступных из плагина действий. bool IsInitialized – получает признак того, что экземпляр информации подключения плагина инициализирован. |
void Init(string pluginName, string pluginDescription, IPluginAction[] pluginActions) - инициализирует экземпляр информации подключения плагина. |
Действие плагина (IpluginAction) |
int ActionId – получает идентификатор действия string ActionDescription – получает описание данного действия string ActionName – получает имя действия, которое будет отражено в меню bool IsInitialized - получает признак того, что экземпляр действия плагина инициализирован. |
void Init(int actionId, string actionName, string actionDescription) – инициализирует экземпляр действия плагина. |
Как вы, наверняка, видите, вполне можно было бы обойтись без второго интерфейса, переместив все его поля в первый, но я решил проверить работу с out-параметрами в COM, то есть протестировать работу методов, которые имеют параметры, через которые из функций возвращаются результаты её работы.
Создание com-интерфейсов, связанных с поддержкой плагинов
Пора переходить к реализации описанных интерфейсов. Добавим ещё один интерфейс в проект сервера.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ZigzagServer
{
[ComVisible(true), Guid("9665CD7C-2CF6-4D73-B6C9-1EC865BE5927")]
public interface IPlugin
{
/// <summary>
/// Осуществляет подключение плагина.
/// </summary>
/// <param name="iZigzagControl">Интерфейс IZigzagControl объекта ZigzagControl.</param>
/// <param name="iPluginConnectionInfo">Интерфейс IPluginConnectionInfo. Передавайте сюда object, плагин должен его инициализировать на своей стороне.</param>
/// <returns>Возвращает код ошибки или 0</returns>
[DispId(1)]
int Connect([MarshalAs(UnmanagedType.Interface), In]object iZigzagControl, [MarshalAs(UnmanagedType.Interface), In, Out]ref object iPluginConnectionInfo);
/// <summary>
/// Просит выполнить плагин заданное идентификатором действие.
/// </summary>
/// <param name="actionId">Идентификатор действия</param>
/// <returns>Возвращает код ошибки или 0.</returns>
[DispId(2)]
int PerformAction(int actionId);
/// <summary>
/// Отключает плагин от приложения.
/// </summary>
/// <returns>Возвращает код ошибки или 0.</returns>
[DispId(3)]
int Disconnect();
}
}
Методе Connect будет вызываться со стороны приложения-хоста. Таким образом плагин будет получать экземпляр ZigzagControl, но должен будет инициализировать параметр iPluginConnectionInfo. Если вас интересуют детали объявления COM-интерфейсов, прочитайте лучше главу «Создание интерфейса IPoint. Создание и работа с GUID-ами. Типы связывания» моего первого руководства, ну или соседние с ней.
Объявим оставшиеся два интерфейса. Для этого добавьте файлы в проект схожим образом.
IPluginConnectionInfo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ZigzagServer
{
/// <summary>
/// Информация о плагине
/// </summary>
[ComVisible(true), Guid("9665CD7C-2CF6-4D73-B6C9-1EC865BE5929")]
public interface IPluginConnectionInfo
{
/// <summary>
/// Получает имя плагина.
/// </summary>
string PluginName
{ get; }
/// <summary>
/// Получает описание плагина.
/// </summary>
string PluginDescription
{ get; }
/// <summary>
/// Получает массив возможных в плагине действий.
/// </summary>
//[property: MarshalAs(UnmanagedType.Interface)]
IPluginAction[] AvailableActions
{ get; }
/// <summary>
/// Получает признак того, что экземпляр информации подключения плагина инициализирован.
/// </summary>
bool IsInitialized
{ get; }
/// <summary>
/// Инициализирует экземпляр информации подключения плагина.
/// </summary>
/// <param name="pluginName">Имя плагина.</param>
/// <param name="pluginDescription">Описание плагина.</param>
/// <param name="pluginActions">Список возможных действий, которые предоставляет плагин.</param>
void Init(string pluginName, string pluginDescription, IPluginAction[] pluginActions);
}
}
IPluginAction.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ZigzagServer
{
/// <summary>
/// Действие, доступное из плагина.
/// </summary>
[ComVisible(true), Guid("9665CD7C-2CF6-4D73-B6C9-1EC865BE5928")]
public interface IPluginAction
{
/// <summary>
/// Получает идентификатор действия.
/// </summary>
int ActionId
{ get; }
/// <summary>
/// Получает строку помощи по данному действию.
/// </summary>
string ActionDescription
{ get; }
/// <summary>
/// Получает имя действия. Это значение будет отображено в меню.
/// </summary>
string ActionName
{ get; }
/// <summary>
/// Получает признак того, что экземпляр действия плагина инициализирован.
/// </summary>
bool IsInitialized
{ get; }
/// <summary>
/// Инициализирует экземпляр действия плагина.
/// </summary>
/// <param name="actionId">Идентификатор действия.</param>
/// <param name="actionName">Имя действия. Это значение будет отображено в меню.</param>
/// <param name="actionDescription">Описание действия.</param>
void Init(int actionId, string actionName, string actionDescription);
}
}