Серверы и контроллеры автоматизации. Создание контроллера автоматизации

   
На этом шаге мы рассмотрим создание контроллера автоматизации.

   
На главной форме будущего приложения-контроллера разместим компоненты TMemo, TEdit, TCheckBox,
TOpenDialog, TSaveDialog, а также десять кнопок (рисунок 1).


Рис.1. Главная форма контроллера автоматизации

   
Объявим переменную FServ типа Variant в секции private класса TForm1. Создадим обработчики событий,
связанные со щелчками на кнопках (при этом следует сослаться на модуль ComObj, указав его в секции uses):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComObj;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Button8: TButton;
    Button9: TButton;
    Button10: TButton;
    Edit1: TEdit;
    CheckBox1: TCheckBox;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button9Click(Sender: TObject);
    procedure Button10Click(Sender: TObject);
  private
    { Private declarations }
    FServ: Variant;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//Подключение к серверу.
procedure TForm1.Button1Click(Sender: TObject);
begin
  FServ := CreateOLEObject('AutoServ.Test');
end;

//Отключение от сервера.
procedure TForm1.Button2Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
    FServ := Unassigned;
end;

//Получить текст от сервера.
procedure TForm1.Button4Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
      Memo1.Text := FServ.Text;
end;

//Отправить текст на сервер.
procedure TForm1.Button3Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
      FServ.Text := Memo1.Text;
end;

//Получение ширины от сервера.
procedure TForm1.Button7Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
     Edit1.Text := IntToStr(FServ.Width);
end;

//Задание ширины окна сервера.
procedure TForm1.Button8Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
       FServ.Width := StrToInt(Edit1.Text);
end;

//Установить видимость/невидимость.
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
        FServ.Visible := CheckBox1.Checked;
end;

//Открыть файл на сервере.
procedure TForm1.Button5Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
    if OpenDialog1.Execute then
        FServ.OpenFile(OpenDialog1.FileName);
end;

//Сохранить файл на севере.
procedure TForm1.Button6Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
    if SaveDialog1.Execute then
        FServ.SaveFile(SaveDialog1.FileName);
end;

//Создать новый файл на сервере.
procedure TForm1.Button9Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
      FServ.NewFile;
end;

//Добавить строку на сервер.
procedure TForm1.Button10Click(Sender: TObject);
begin
  if VarType(FServ) = varDispatch then
      FServ.AddLine(Edit1.Text);
end;

end.

Текст этого приложения можно взять здесь (7,1 Кб).

   
Поясним приведенный выше код.

   
Для управления сервером автоматизации мы создали переменную типа Variant и вызвали функцию CreateOleObject(),
содержащуюся в модуле ComObj. При выполнении функции CreateOleObject() она, вызвав несколько функций
COM API, создаст экземпляр СОМ-объекта и вернет его интерфейс IDispatch внутри вариантной переменной.
Этот объект содержит интерфейс СОМ-объекта (в данном случае нашего сервера автоматизации), методы которого
мы хотим вызывать из приложения. Если исследовать реализацию функции CreateOleObject() в исходном тексте модуля
ComObj, можно обнаружить, что она, в свою очередь, вызывает функцию CoCreateInstance() COM API, назначение
которой - создать объект из исполняемого файла или DLL, то есть обратиться к фабрике классов. Переменная типа
Variant может содержать разнообразные данные (строку, число и др., в том числе и интерфейс СОМ-объекта).

   
Delphi в отличие от C++ позволяет обращаться к методам и свойствам объектов внутри вариантных переменных,
при этом существование этих методов и свойств в общем случае может быть заранее неизвестно. Поэтому допустимый в Delphi
код следующего вида вовсе не означает, что компилятор "знает" о существовании свойства Width вариантной переменной FServ:

   if VarType(FServ) = varDispatch then 
           FServ.Width:=StrToInt(Edit1.Text);

   
Дело в том, что при создании контроллеров в Delphi компилятор не проверяет, имеется ли в действительности свойство
(в данном случае Width) у объекта, хранящегося в переменной типа Variant (в отличие от объектов другого типа, например TForm),
а просто воспринимает название свойства или метода как обычную символьную строку, не анализируя ее содержимое. Поэтому ошибка в названии
свойства или метода компилятором опознана не будет и проявится лишь на этапе выполнения. Попробуйте изменить представленный выше код следующим образом:

  if VarType(FServ)=varDispatch then 
     FServ.WiGth:=StrToInt(Edit1.Text);

   
В этом случае компилятор скомпилирует проект с ошибочным словом WiGth.

   
На этапе выполнения приведенного кода меняется свойство Width объекта, содержащегося в адресном пространстве сервера, а не созданного контроллера.

   
Соединение с сервером в данном проекте выполняется динамически, при щелчке на кнопке Подключиться. Разрыв соединения выполняется при
щелчке на кнопке Отключиться. Здесь вариантной переменной просто присваивается неопределенное
значение (unassigned). В этом заключается маленькая хитрость компилятора Delphi: при таком присвоении генерируется код, который проверяет,
что находится в вариантной переменной, и если там имеется ссылка на интерфейс, то вызывается его метод Release. Поскольку сервер вызывается
динамически, то перед вызовом каждого метода следует проверить, имеется ли в данный момент ссылка па сервер. Это достигается с помощью следующего оператора:

  if VarType(FServ) = varDispatch then ...

   
После запуска контроллера при щелчке на кнопке Подключиться запускается сервер. При щелчках на кнопках
Новый файл, Открыть файл и происходит соответственно очистка окна редактирования, загрузка текста в окно редактирования сервера
из файла, сохранение текста в файле. Установка (снятие) флажка Видимость приводит к появлению (скрытию) сервера. Щелчок на кнопке
Узнать ширину приводит к тому, что в текстовом поле отображается значение ширины окна сервера в пикселях. Если ввести в это поле
другое число и щелкнуть на кнопке Задать ширину, ширина окна сервера станет равной введенному числу пикселей. Щелчок на кнопке
Добавить строку приводит к тому, что в редактируемый текст компонента ТМеmо добавляется строка, находящаяся в этот момент
во все том же текстовом поле. И наконец, при помощи кнопок Получить текст и Задать текст можно копировать целиком содержимое компонента ТМеmо (рисунок 2).


Рис.2. Совместное функционирование контроллера и сервера автоматизации

   
На следующем шаге мы рассмотрим ранее и позднее связывание.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий