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

Внесение косметических изменений в серверную часть

Так как до этого наш код плагины не поддерживал, наш сервер функционировал немного по-другому. Предполагалось, что сервер сам должен закрываться после того, как от него отключается последний клиент. Клиентов я считал по количеству созданных экземпляров COM-объектов. Тогда, когда счётчик объектов становился равен одному (главная форма сервера тоже хранит ссылку на ZigzagControl), сервер выгружался. Теперь же каждый плагин хранит по одному ZigzagControl-у. Учтём это на сервере. Откроем файл ComServer.cs и изменим его. Сперва добавим туда счётчик плагинов и методы его изменения.

public static int PluginsCount

{ get; set; }

public static void IncreasePluginsCount()

{

PluginsCount++;

}

public static void DecreasePluginsCount()

{

PluginsCount--;

}

Теперь немного перепишем метод Unlock, изменим условие выгрузки сервера из рассчёта на то, что каждый плагин ссылается на один ZigzagControl и один экземпляр Zigzag хранится на сервере в том случае, если где-то помимо сервера он нужен. То есть, примерно так:

Каждый клиент содержит один ZigzagControl

Каждый плагин содержит один ZigzagControl

Сервер содержит один ZigzagControl

Если вне сервера содержится хотя бы один ZigzagControl, то на сервере содержится ещё и экземпляр класса Zigzag.

Таким образом, заменяем метод Unlock на:

/// <summary>

/// Уменьшает счётчик ссылок на единицу.

/// Если счётчик ссылок принимает значение, равное нулю, генерирует событие OnComReleased. Это говорит о том, что все экземпляры COM-классов, выданные COM-клиентам, больше им не нужны и можно безопасно закрывать сервер.

/// </summary>

public static void Unlock()

{

uint refCount = CoReleaseServerProcess();

if ((refCount == PluginsCount + 1 + ((PluginsCount == 0) ? 0 : 1)))

if (OnComReleased != null)

OnComReleased();

}

А ещё я заметил, что для одного из запланированных плагинов мне не хватает функционала интерфейса IZigzagControl. Придётся туда добавить ещё один метод. Если бы дело было уже после гипотетического выхода нашего ZigzagServer-а на рынок, то изменять интерфейсы вот таким вот варварским путём не следовало. Кошерным считается добавлять новый интерфейс, наследующийся от старого и содержащий новые необходимые функции. То есть обычно создают IZigzagControl2 с новыми возможностями, а все старые сохраняются из-за наследования. Таким образом, старые клиенты смогут использовать старую версию интерфейса и не сломаются, а новые клиенты будут использовать новый интерфейс. Итак, добавим в IZigzagControl новый метод.

Если ваш интерфейс имеет тип IDispatch, то лучше добавлять методы в конец.

/// <summary>

/// Задаёт массив точек ломаной.

/// </summary>

/// <param name="points">Массив точек. Массив экземпляров IPair, левое значение которой - int, количество мс от момента создания сервера до момента создания точки, правое значение - IPoint, координаты точки.</param>

void SetPoints(IPair[] points);

Реализуем этот метод в ZigzagControl.cs, добавим его в регион членов IZigzagControl.

/// <summary>

/// Задаёт массив точек к ломаной.

/// </summary>

/// <param name="points">Массив точек. Массив экземпляров IPair, левое значение которой - int, количество мс от момента создания сервера до момента создания точки, правое значение - IPoint, координаты точки</param>

public void SetPoints(IPair[] points)

{

zigzag.Lock();

try

{

zigzag.Clear();

zigzag.Add(points);

}

catch (Exception exc)

{

ErrorReporter.ShowExceptionMessage(exc);

}

finally

{

zigzag.ReleaseLock();

}

}

Тут тоже всё просто, блокируем объект зигзаг, чтобы никто не получил к нему доступ, пока мы совершаем свои махинации, очищаем его, заполняем его новыми точками, снимаем блокировку.

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

Кроме того, необходимо несколько изменить код класса Zigzag.cs, а именно всю ветку кода с условимем “if (element is IList)” метода Add. Всё это условие заменяется на следующий код:

if ((element is IList) || (element is IPair[]))

{

LocalLock();

//Попробуем перенести данные из переданного аргумента в нативные фреймворковские списки.

//Если структура списка была некорректной, то возникнет исключение и ни одна из точек списка добавлена в ломаную не будет.

try

{

IPair[] pointsArray;

if (element is IList)

{

IList list = (IList)element;

List<IPair> tempList = new List<IPair>(list.Count);

for (int i = 0; i < list.Count; i++)

tempList.Add((IPair)list.GetElementAt(i));

pointsArray = tempList.ToArray();

}

else

pointsArray = (IPair[])element;

if (pointsArray.Length > 0)

{

List<long> time = new List<long>(pointsArray.Length);

List<int> X = new List<int>(pointsArray.Length);

List<int> Y = new List<int>(pointsArray.Length);

for (int i = 0; i < pointsArray.Length; i++)

{

IPair pair = pointsArray[i];

long timePassed = (long)pair.Left;

IPoint point = (IPoint)pair.Right;

//Нужно, чтобы время создания каждой последующей точки ломаной было больше или равно времени создания предыдущей.

//Проконтролируем это.

if (time.Count == 0)

{

if ((pointCreationPassedTimeList.Count > 0) && (timePassed < pointCreationPassedTimeList[pointCreationPassedTimeList.Count - 1]))

throw new Exception("Ожидается, что переданное время создания новой точки больше или равно времени создания последней существующей точки списка. " +

"Время создания каждой последующей точки ломаной должно быть больше или равно времени создания предыдущей. " +

"Переданное же вами значение времени создания новой точки меньше, чем время создания последней точки ломаной.");

}

else

if (timePassed < time[time.Count - 1])

throw new Exception("Ожидается, что переданное время создания новой точки больше или равно времени создания последней существующей точки списка. " +

"Время создание одной из точек переданного списка меньше времени создания предыдущей точки. Упорядочите точки по возрастанию времени прежде чем передавать их в метод.");

//Нет, я бы и сам, конечно, мог бы упорядочить, но сейчас 6 часов утра и мне лень. Если не лень вам - перепишите метод.

time.Add(timePassed);

X.Add(point.X);

Y.Add(point.Y);

}

//Похоже на то, что в структуре полученного в качестве аргумента списка ошибок нет.

//Перенесём данные из временных списков в наши, хранящие информацию о точках ломаной.

for (int i = 0; i < pointsArray.Length; i++)

{

pointCreationPassedTimeList.Add(time[i]);

pointList.Add(new System.Drawing.Point(X[i], Y[i]));

}

}

}

catch (Exception exc)

{ ErrorReporter.ShowExceptionMessage(exc); }

LocalRelease();

FirePointListChangedEvent();

return;

}

Теперь в метод можно передавать массив IPair-ов, где левое значение пары – время в мс от создания сервера, а правое значение – IPoint.

Кроме того, я изменил метод Clear. Раз уж мы всё равно не храним историю удаленных точек, то теперь в этом методе будем заново инициализировать переменную creationTime (которая хранит время создания сервера). Таким образом, после каждого вызова Clear будем считать, что сервер создан только что, и отсчёт времени создания новых последующих точек будет начинаться с нуля. Итак, новый код метода:

/// <summary> Очищает список точек ломаной. </summary>

public void Clear()

{

accessControl.ResourceUsed();

LocalLock();

creationTime = DateTime.Now; // Обнуляем время создания экземпляра сервера.

pointList.Clear();

pointCreationPassedTimeList.Clear();

LocalRelease();

FirePointListChangedEvent();

}

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