42734

ВЗАИМОДЕЙСТВИЕ С УНАСЛЕДОВАННЫМ ПРОГРАММНЫМ КОДОМ

Лабораторная работа

Информатика, кибернетика и программирование

Очень часто сборки .NET должны успешно взаимодействовать со сложными приложениями, где значительную часть кода составляют классические СОМ- серверы. Код модулей СОМ является двоичным и платформенно-зависимым (в отличие от полностью платформенно-независимого кода IL). СОМ-серверы работают с уникальным набором типов данных (BSTR, VARIANT и т. п.), содержание которых в разных языках программирования сильно различается.

Русский

2013-10-30

167.37 KB

3 чел.

ЛАБОРАТОРНАЯ РАБОТА № 5.1

ВЗАИМОДЕЙСТВИЕ С УНАСЛЕДОВАННЫМ ПРОГРАММНЫМ КОДОМ

Очень часто сборки .NET должны успешно взаимодействовать со сложными приложениями, где значительную часть кода составляют классические СОМ- серверы. Код модулей СОМ является  двоичным и платформенно-зависимым (в отличие от полностью платформенно-независимого кода IL).  СОМ-серверы работают с уникальным набором типов данных (BSTR, VARIANT и т. п.), содержание которых
в разных языках программирования сильно различается. В каждом программном модуле СОМ должны быть реализованы достаточно сложные элементы (такие как фабрики классов, код IDL, записи в реестр). В  СОМ-объектах необходимо отслеживать каждую ссылку на объект. Eсли
ошибиться в ссылках на объект, то это может привести к утечке памяти.
 

Следовательно, между типами .NET и СОМ так мало общего, что трудно даже представить, как такие разные типы могут успешно взаимодействовать друг с другом. Но в реальной работе возникает очень много ситуаций, когда необходимо обеспечить такое взаимодействие. Платформа .NET поддерживает следующие виды совместимости с унаследованным кодом:

  1.  вызовы из типов .NET напрямую к модулям DLL, созданным на С (то есть обращения к Win32 API или пользовательским модулям DLL);
  2.  взаимодействие .NET  и СОМ;
  3.  применение элементов управления ActiveX  в Windows Forms;
  4.  вызовы из типов СОМ к типам .NET;

В данной лабораторной работе будут рассмотрены пункты  2 и 3.

РЕАЛИЗАЦИЯ ВНУТРЕННЕГО СЕРВЕРА COM В DELPHI

  1.  Для создания в Delphi внутреннего сервера СОМ, реализуемого библиотекой DLL, выполните команду File New | Other и на странице ActiveX Депозитария выберите пиктограмму ActiveX Library. Будет создан новый проект, который сохраните под каким-то именем, например, PMyComServ.

Взгляните на созданный Delphi код этого проекта:

library  PMyComServ;

uses

ComServ;

exports

DllGetClassObject,

DllCanUnloadNow,

DllRegisterServer,

DllUnregisterServer;

($R   *.RES)

begin

end. .

Оператор uses подключает к проекту модуль ComServ, в котором описан класс TComServ, реализующий свойства сервера СОМ. Объект ComServ этого класса автоматически создается в проекте и позволяет через свои свойства получать информацию о сервере и его объектах.

Как видно из приведенного выше кода, библиотека экспонирует четыре функции. Все они вызываются в нужные моменты автоматически.

  1.  Теперь надо добавить в  сервер объект. Пусть это будет  объект, имеющий два интерфейса, первый из которых имеет две арифметические функции: сложение и вычитание двух действительных чисел, а второй — функции умножения и деления действительных чисел.

Выполните опять команду File New | Other и на странице ActiveX Депозитария выберите пиктограмму COM Object. Перед вами откроется окно, показанное на рисунке 1. В окне Class Name вы должны указать имя класса создаваемого объекта. К этому имени будет автоматически добавлен префикс «Т». Так что имя «MyObject», которое вы видите на рисунке 1, приведет к созданию класса TMyObject.

 

Рисунок 1 – Добавление объекта

Выпадающий список Instancing позволяет выбрать способ создания объекта (см. таблицу 1).

Таблица 1 Описание способов создания объектов

Internal

Объект создается только внутренне                                      

Single Instance

Каждый сервер может содержать только один экземпляр объекта, так что для каждого клиента создается отдельный экземпляр сервера                                                                          

Multiple Instances

   Для каждого клиента создается отдельный экземпляр объекта в пределах адресного пространства одного сервера     

В данном примере выбор в списке Instancing не имеет значения, так как для внутреннего сервера, который мы создаем, этот параметр игнорируется.

Выпадающий список Threading model определяет способы вызова клиентами интерфейса объекта СОМ в многопоточных приложениях (см. таблицу 2).

Таблица 2 Способы вызова клиентами интерфейса объекта СОМ в многопоточных приложениях

Single

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

Apartment

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

Free

Объекты обрабатывают вызовы произвольного числа потоков одновременно. Надо принимать меры для защиты всех локальных и глобальных данных

Both

To же, что Free, только откаты осуществляются гарантированно в том же потоке

Neutral

Множество клиентов могут вызывать объект в различных потоках, но предполагается, что между этими вызовами не возникает конфликтов. Эта модель не может использоваться для объектов, имеющих пользовательский интерфейс, т.е. визуальные компоненты. Модель поддерживается только для СОМ+. Для СОМ она эквивалентна Apartment

  1.  В окне Implemented interfaces задается имя интерфейса вашего объекта СОМ по умолчанию. Вы можете согласиться с предложенным именем, которое является именем класса с префиксом «I», или написать новое имя. Созданный интерфейс будет наследником IUnknown и в дальнейшем вы сможете задать его реализацию, пользуясь описанным далее редактором библиотеки типов.

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

  1.  Окно Description дает возможность ввести текстовое описание объекта СОМ. Индикатор Include Type Library определяет автоматическую генерацию библиотеки типов. Индикатор Mark interface OleAutornation разрешает маршаллинг — вызов функции интерфейса удаленными объектами в другом процессе и на другой машине, чтобы не усложнять свою задачу, выключите этот индикатор.

После того, как вы заполните всю информацию в окне и щелкнете на ОК перед вами откроется окно редактора библиотеки типов (рисунок 2), а в окне Редактора Кода вы сможете увидеть заготовку модуля объекта СОМ. Она будет иметь вид:

unit UObject;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses

Windows, ActiveX, Classes, ComObj, PMyComServ_TLB, StdVcl;

type

TMyObjec=class (TTypedComObject, IMyObject)

protected

// Здесь объявляются методы интерфейса

end;

implementation

uses ComServ;

initialization

TTypedComObjectFactory.Create(ComServer, TMyObject,

Class_MyObject, ciMultilnstance, tmApartment);

end.

  1.  Вы видите, что в раздел initialization включен конструктор фабрики класса. Класс фабрики класса создан Delphi автоматически.
  2.  Вызвав Менеджер Проектов (команда View Project Manager) вы увидите, что помимо этого модуля сгенерировался и включился в проект файл РМуComServ_TLB.pas — модуль библиотеки типов.
  3.  Теперь займемся разработкой методов созданного объекта. В первый момент после создания объекта окно редактора библиотеки типов (рисунок 2 ) откроется автоматически. В дальнейшем вы в любой момент можете вызвать это окно командой View | Type Library. Эта команда доступна только в том случае, если ваш проект содержит библиотеку типов.

Рисунок 2 - Редактор библиотеки типов

  1.  В левой панели окна редактора библиотеки типов вы видите дерево элементов вашего объекта СОМ. Правая многостраничная панель позволяет посмотреть и задать свойства вершины, выделенной в левой панели. А инструментальная панель верху окна содержит быстрые кнопки, позволяющие вводить в объект новые интерфейсы, методы, свойства и т.п.
  2.  Начнем с добавления методов в интерфейс IMyObject. Выделите в левой панели вершину этого интерфейса и щелкните на быстрой кнопке New Method. В дереве левой панели появится вершина нового метода. Назовите этот метод Add — он будет складывать два числа. Выделите вершину метода и перейдите в правой панели на страницу Parameters, которая показана на рисунке 3. В выпадающем списке Return Type надо выбрать тип возвращаемого методом значения -  в нашем примере float. Для задания параметров метода нажмите кнопку Add.

Рисунок 3 - Определение входных и  выходных параметров

  1.  В нижнем окне панели появится строка, соответствующая вводимому параметру. В столбце Name надо задать имя параметра («Numberl» на рисунке 3). В столбце Туре надо выбрать из выпадающего списка тип параметра. В столбце Modifier можно выбрать модификаторы параметра: входной, выходной, необязательный, со значением по умолчанию и т.п. В нашем примере можно оставить значение по умолчанию «[in]».
  2.  Аналогичным образом надо задать второй параметр. Далее так же, как вы добавили метод Add, добавьте в интерфейс метод Sub — вычитание чисел.
  3.  Теперь надо ввести в объект второй интерфейс. Щелкните на быстрой кнопке New Interface (крайняя левая). В левой панели появится новая вершина. Назовите новый интерфейс «IMyObject2». Укажите для нового интерфейса родительский интерфейс – IUnknown.
  4.  Выделите эту вершину, перейдите на правой панели на страницу Flags и выключите на ней флаги Dual и OleAutomation, чтобы не усложнять нашу задачу.
  5.  Введите в новом интерфейсе так же, как делали раньше, два метода Mult — перемножение чисел, и Div — деление.    
  6.  Вы описали второй интерфейс. Теперь надо ввести его в ваш объект. Выделите в левой панели вершину объекта MyObject и перейдите в правой панели на страницу Implements. Щелкните на ней правой кнопкой мыши и выберите в контекстном меню раздел InsertInterface. Перед вами откроется окно со списком интерфейсов, которые вы можете добавить в свой объект. Выберите из него созданный вами интерфейс IMyObject2. Интерфейс включится в ваш объект.
  7.  Описание объекта закончено. Теперь надо написать реализацию введенных методов. Щелкните на быстрой кнопке Refresh Implementation — обновить реализацию. Перейдите в редактор кода и посмотрите модуль объекта. Вы увидите в объявлении класса ссылку на оба интерфейса, объявления введенных вами методов, а в разделе implementation найдете заготовки реализации этих методов. Напишите в них соответствующие операторы. В результате модуль объекта приобретет вид:

unit Unit1;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses

 Windows, ActiveX, Classes, ComObj, PMyComServ_TLB, StdVcl;

type

 TMyObject = class(TTypedComObject, IMyObject, IMyObject2)

 protected

   function Add(Number1, Number2: Single): Single; stdcall;

   function Div_(Number1, Number2: Single): Single; stdcall;

   function Mult(Number, Number2: Single): Single; stdcall;

   function Sub(Number1, Number2: Single): Single; stdcall;

   {Declare IMyObject methods here}

 end;

implementation

uses ComServ;

function TMyObject.Add(Number1, Number2: Single): Single;

begin

  Result:=Number1+Number2;

end;

function TMyObject.Div_(Number1, Number2: Single): Single;

begin

  Result:=Number1/Number2;

end;

function TMyObject.Mult(Number, Number2: Single): Single;

begin

  Result:=Number*Number2;

end;

function TMyObject.Sub(Number1, Number2: Single): Single;

begin

  Result:=Number1-Number2;

end;

initialization

 TTypedComObjectFactory.Create(ComServer, TMyObject, Class_MyObject,

   ciMultiInstance, tmApartment);

end.

  1.  Обратите внимание, что Delphi автоматически изменила имя метода Div на Div_, так как мы случайно  задали методу имя, совпадающее с именем соответствующей операции Object Pascal. Чтобы в кодах не возникала двусмысленность, Delphi добавила в конце имени метода символ подчеркивания.
  2.  Теперь все сделано, объект в составе сервера СОМ создан. Выполните компиляцию проекта (Project|Compile All Project).
  3.  Осталось зарегистрировать сервер в системе. Это можно сделать командой Run | Register ActiveX Server главного меню Delphi. Если вы в дальнейшем надумаете удалить его (вряд ли наш тестовый сервер представляет какую-то ценность), вы должны будете выполнить команду Run | Unregister ActiveX Server.

Отметим еще, что для распространения вашего проекта между пользователями вам потребуется библиотека типов на языке IDL Трансляция ее осуществляется быстрой  кнопкой Export To IDL — крайняя правая на рисунке 3.

  1.  Осталось проверить работу нашего сервера. Создайте тестовое приложение, включающее два окна Edit, в которых пользователь может задавать числа, две кнопки, одна из которых выполняет методы первого, а другая — второго интерфейса, и две метки для отображения результатов (рисунок 4.).

Рисунок 4 - Тестовый пример

Код этого приложения может сеть вид:

unit Unit3;

interface

uses

 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

 Dialogs, StdCtrls,PMyComServ_TLB;

type

 TForm1 = class(TForm)

   Edit1: TEdit;

   Edit2: TEdit;

   Label1: TLabel;

   Label2: TLabel;

   Button1: TButton;

   Button2: TButton;

   procedure FormCreate(Sender: TObject);

   procedure Button1Click(Sender: TObject);

   procedure Button2Click(Sender: TObject);

 private

   { Private declarations }

 public

   { Public declarations }

 end;

var

 Form1: TForm1;

 Interface1:IMyObject;

 Interface2:IMyObject2;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

begin

 Interface1:=CoMyObject.Create;

 Interface1.QueryInterface(ImyObject2,Interface2);

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

 Label1.Caption:=FloatToStr(Interface1.Add(StrToFloat(Edit1.Text),StrToFloat(Edit2.Text)));

 Label2.Caption:=FloatToStr(Interface1.Sub(StrToFloat(Edit1.Text),StrToFloat(Edit2.Text)));

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

Label1.Caption:=FloatToStr(Interface2.Mult(StrToFloat(Edit1.Text),StrToFloat(Edit2.Text)));

Label2.Caption:=FloatToStr(Interface2.Div_(StrToFloat(Edit1.Text),StrToFloat(Edit2.Text)));

end;

end.

  1.  Обратите внимание прежде всего на то, что в оператор uses включена ссылка на модуль созданной вами библиотеки типов PMyComServ_TLB.pas. Далее после объявления класса формы вводятся две переменные Interface1 и Interface2 соответственно типов IMyObject и IMyObject2, объявленных в вашем объекте СОМ.
  2.  Процедура FormCreate является обработчиком события OnCreate формы. Первый оператор этого обработчика создает CoClass класса CoMyObject и возвращает указатель на интерфейс по умолчанию IMyObject в переменную Interfacel.
  3.  Чтобы получить указатель на второй интерфейс, используется функция Querylnterface первого интерфейса, в которую передаются как параметры имя второго интерфейса IMyObject2 и переменная Interface2. В результате переменной Interfaсе2 присваивается указатель на интерфейс IMyObject2.

Код примера очевиден: при щелчках на той или иной кнопке в метки Label1 и Label2 заносятся результаты выполнения соответствующих методов интерфейсов с параметрами, получаемыми из окон Editl и Edit2.

Для взаимодействия .NET с COM  выполните следующие действия:

  1.  Создайте проект в C# , изображенный на рисунке 5.

Рисунок  5 – Пример COM-клиента на C#

  1.  Выполните раннее связывание с СOM-сервером при помощи диалогового окна Add Reference (см. рисунок 6).

Рисунок 6- Вызов диалогового окна Add Reference

  1.  В появившемся диалоговом окне выбираете нужный COM-сервер (см. рисунок 7.

Рисунок 7 – Обращение к COM-серверу средствами Visual Studio .NET

  1.  Для  упрощения доступа к COM-серверу добавьте строку:

namespace com

{

   using PMyComServ; // !!!!!

   public partial class Form1 : Form

   {

       public Form1()

       {

           InitializeComponent();

       }

  1.   Объявите глобальные переменные:

MyObject m;

     IMyObject i;

IMyObject2 j;

  1.   Для события Click кнопки Button1 (Интерфейс1) напишите следующий программный код:

private void button1_Click(object sender, EventArgs e)

{

// Создаем объект MyObject          

m = new MyObject();

// Явным образом получаем ссылку на интерфейс IMyObject

    i = m;

    float s1 = Convert.ToSingle(textBox1.Text);

    float s2 = Convert.ToSingle(textBox2.Text);

// Вызываем методы интерфейса IMyObject

    label1.Text = Convert.ToString(i.Add(s1, s2));

    label2.Text = Convert.ToString(i.Sub(s1,s2));

 }

  1.  Для события Click кнопки Button2 (Интерфейс2) напишите следующий программный код:

private void button2_Click(object sender, EventArgs e)

{

// Создаем объект MyObject

  m = new MyObject();

// Явным образом получаем ссылку на интерфейс IMyObject

  i = m;

// Получаем ссылку на интерфейс IMyObject2

// через интерфейс IMyObject

  j = (IMyObject2)i;

  float s1 = Convert.ToSingle(textBox1.Text);

  float s2 = Convert.ToSingle(textBox2.Text);

  label1.Text = Convert.ToString(j.Mult(s1, s2));

  label2.Text = Convert.ToString(j.Div(s1, s2));

}

ЗАДАНИЯ  К ЛАБОРАТОРНОЙ РАБОТЕ № 5_1

Создайте COM-объект, имеющий два интерфейса, каждый интерфейс содержит два метода:

  1.  Работа со строками. Введите предложение. Выполните подсчет гласных  и согласных  букв, количества слов и количества слов, начинающихся с гласных.
  2.  Работа со строками. Введите предложение. Выполните подсчет букв  и знаков препинания,. количества слов и количества слов, начинающихся с больших английских букв.
  3.  Строки. Введите предложение и определите длину самой большой цепочки идущих подряд цифр и букв, а также удалите все лишние пробелы (между каждым словом только 1 пробел)  и расставьте дополнительные пробелы таким образом, чтобы длина всей строки была равна 40 символов.
  4.  Работа со строками. Введите предложение. Замените все маленькие буквы на большие. Замените все большие буквы на маленькие. Переверните все предложение. Переверните каждое слово.
  5.   Геометрия. По известному радиусу окружности найдите длину окружности, площадь круга, периметр и площадь квадрата, описанного около окружности.
  6.  Геометрия. Даны катеты прямоугольного треугольника, найдите гипотенузу треугольника, периметр треугольника, площадь треугольника по формуле Герона и по известной стороне и высоте треугольника.
  7.  Геометрия. Даны радиус и высота цилиндра. Найдите площадь цилиндра, объем цилиндра, площадь боковой поверхности и площадь основания.
  8.  Геометрия.  Даны стороны прямоугольного параллелепипеда. Найдите площадь поверхности  и объем параллелепипеда, а также площадь одной  грани и площадь боковой поверхности.
  9.  Физика. Даны три сопротивления.  Найдите сопротивление соединения для случаев, когда соединение параллельное и когда последовательное. А также, значение наибольшего и наименьшего сопротивлений.
  10.  Математика. Введите число и определите, является ли оно простым,  найдите НОД числа, определите является ли число степенью двух и степенью  трех.
  11.  Булева алгебра. Введите десятичное число и переведите его в двоичное, введите двоичное число и переведите его в десятичное. Выполните аналогичный перевод десятичного числа в шестнадцатеричное  и шестнадцатеричного в десятичное.
  12.  Булева алгебра. Введите двоичное число и выполните операции сложения, вычитания, умножения и деления. Результат выведите в двоичной форме.
  13.  Булева алгебра. Введите шестнадцатеричное число и выполните операции сложения, вычитания, умножения и деления. Результат выведите в шестнадцатеричной форме.
  14.  Булева алгебра. Введите восьмеричное число и выполните операции сложения, вычитания, умножения и деления. Результат выведите в восьмеричной форме.


 

А также другие работы, которые могут Вас заинтересовать

36875. ИСПОЛЬЗОВАНИЕ ОТНОСИТЕЛЬНОЙ И АБСОЛЮТНОЙ АДРЕСАЦИИ В ВЫЧИСЛЕНИЯХ 197.5 KB
  Переименуйте Лист 1 в Задание 1 и на этом листе создайте таблицу по Образцу 1 значения в ячейках к которым применена заливка серым цветом подсчитать с помощью формул: – в ячейку D2 введите формулу в которой по умолчанию используются относительные адреса ячеек и скопируйте её в ячейки для других товаров D3 D4 с помощью маркера автозаполнения; – в ячейку D5 введите формулу расчета суммы затрат на приобретение товаров; – в ячейку E2 введите формулу: = Стоимость 100 Всего в которой используются относительные адреса ячеек и...
36876. РАБОТА СО СПИСКАМИ: ФИЛЬТРАЦИЯ, СОРТИРОВКА, ИТОГИ, СВОДНЫЕ ТАБЛИЦЫ 64.5 KB
  РАБОТА СО СПИСКАМИ: ФИЛЬТРАЦИЯ СОРТИРОВКАИТОГИ СВОДНЫЕ ТАБЛИЦЫ. Перейти на лист Книжный магазин и скопировать таблицу на листы Итоги1 Итоги2 Итоги3 и Итоги4. На листе Итоги1 сформировать итоги по товарам: в итоги включить сумму значений по столбцам Колво и Доход руб. На листе Итоги2 сформировать итоги по продавцам: в итоги включить сумму значений по столбцам Колво и Доход руб.
36877. РАБОТА С ФОРМУЛАМИ И ФУНКЦИЯМИ В MS EXCEL 527 KB
  Создайте таблицу Результаты тестирования рассчитайте средний показатель тестирования для каждого сотрудника. Создайте таблицу содержащую следующие поля: № п п Фамилия Тест 1 Тест 2 Тест 3 Тест 4 Средний показатель Заполните таблицу данными. Таблица результаты тестирования Рассчитайте Средний показатель тестирования каждого сотрудника. Для этого: Выделите пустую ячейку в поле Средний показатель напротив фамилии первого сотрудника.
36878. Определение ёмкости конденсаторов измерительным мостиком Соти 85 KB
  Тема: Определение ёмкости конденсаторов измерительным мостиком Соти. Цель работы: измерение теплоёмкостей двух конденсаторов проверка закона последовательного и параллельного соединения конденсаторов. Пусть Δφ1 Δφ2 – мгновенные значения напряжений на обкладках конденсаторов а ΔφN ΔφNB – мгновенные значения напряжений на сопротивлениях R1 R2.
36880. Определение заряда иона водорода 63.5 KB
  Тема: Определение заряда иона водорода. Цель работы: изучить прохождение тока в электролитах определить заряд иона водорода оценить погрешность данного метода определения заряда иона водорода и ознакомиться с явлением наводораживания металлов. КРАТКАЯ ТЕОРИЯ Для определения заряда иона водорода можно использовать прохождение тока в электролитах явление электролиза.
36882. Word: Ввод и редактирование текста. Операции с фрагментами текста 99 KB
  ввод пробела: при нажатии клавиши Пробел вводится занимающий определенное место в строке символ пробела; наличие или отсутствие пробела в конце строки может быть определено при нажатии на кнопку Непечатаемые знаки на Стандартной панели инструментов в правой стороне; Введите в расположенной ниже строке по одному пробелу между цифрами 1 и 2 и еще три пробела в конце строки. Ввод пробелов: 1111122222311112222311122231122313 Отобразите на экране символы пробела абзаца разрыва строки нажатием на кнопку Непечатаемые знаки на Стандартной панели...