Створення контролерів автоматизації за допомогою C + + Builder, Комерція, Різне, статті

Зміст



Тестування сервера автоматизації


В

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

Створимо оброблювачі подій, пов'язані з натисканням на кнопки (при цьому слід послатися на h-файл модуля ComObj):

//———————————————— —————————
#include <vcl.h>
#pragma hdrstop
#include <ComObj.hpp>
#include “autocon.h”
//———————————————— —————————
#pragma package(smart_init)
#pragma resource “*.dfm”
TForm2 *Form2;
Variant Serv;
//———————————————— —————————
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//———————————————— —————————

void __fastcall TForm2::Button3Click(TObject *Sender)
{
Serv=CreateOleObject(“Project1.MyAuto3”);
}
//———————————————— —————————
void __fastcall TForm2::Button1Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch)
Edit1->Text=IntToStr(Serv.OlePropertyGet(“Width”));
/ / Має сенс перевірити, що саме лежить в варіантної змінної …
}
//———————————————— —————————
void __fastcall TForm2::Button2Click(TObject *Sender)
{
if (VarType (Serv) == varDispatch) Serv.OlePropertySet ("Width", StrToInt (Edit1-> Text));
}
//———————————————— —————————

void __fastcall TForm2::Button12Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch)
CheckBox1->Checked=Serv.OlePropertyGet(“Visible”);
}
//———————————————— —————————
void __fastcall TForm2::Button13Click(TObject *Sender)
{
if (VarType (Serv) == varDispatch) Serv.OlePropertySet ("Visible", CheckBox1-> Checked);
}
//———————————————— —————————
void __fastcall TForm2::Button11Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch) Serv=Unassigned;
}
//———————————————— —————————
void __fastcall TForm2::Button5Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch)
{if (OpenDialog1->Execute())
Serv.OleProcedure(“OpenFile”,OpenDialog1->FileName);}
}
//———————————————— —————————
void __fastcall TForm2::Button6Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch)
{ if (SaveDialog1->Execute())
Serv.OleProcedure(“SaveFile”,SaveDialog1->FileName);}
}

//———————————————— —————————
void __fastcall TForm2::Button7Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch) Serv.OleProcedure(“NewFile”);
}
//———————————————— —————————
void __fastcall TForm2::Button4Click(TObject *Sender)
{
if (VarType(Serv)==varDispatch)
Serv.OleProcedure(“AddLine”,Edit1->Text);
}
//———————————————— —————————


Деякі коментарі


Тепер настав час пояснити, що саме робить наведений вище код.

Для управління сервером автоматизації ми створили змінну типу Variant (в C + + Builder для цієї мети є відповідний клас) і викликали функцію CreateOleObject, що міститься в модулі ComObj бібліотеки VCL.

При виконанні функції CreateOleObject відбудеться наступне. Ця функція, викликавши кілька функцій Windows API, створить примірник COM-об'єкта IDispatch і поверне його всередині варіантної змінної. Цей об'єкт, в свою чергу, містить інтерфейс об'єкта (у даному разі нашого сервера автоматизації), методи якого ми хочемо викликати з програми. Якщо досліджувати реалізацію функції CreateOleObject у вихідному тексті модуля ComObj, можна виявити, що вона, в свою чергу, викликає функцію Windows API CoCreateInstance, що є частиною специфікації COM, призначення якої – створити об'єкт з виконуваного файлу або DLL.Переменная типу Variant може містити різноманітні дані (рядок, число та інші, в тому числі і інтерфейс COM-об'єкта).

Відзначимо, що, на відміну від Visual Basic або Delphi, C + + Builder не дозволяє звертатися до методів і властивостей варіантних змінних, існування яких заздалегідь невідомо. Тому допустимий в Delphi код виду

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

не має аналога в C + + Builder. Справа в тому, що при створенні контролера за допомогою Delphi в разі об'єктів типу Variant, на відміну від об'єктів іншого типу, наприклад, TForm, компілятор не перевіряє, є Чи насправді таку властивість (в даному випадку Width) у даного об'єкта. На етапі виконання такого коду відбувається виклик функцій Windows API, в результаті роботи яких змінюється властивість Width об'єкт, що міститься не в адресному проcтранстве створеного контролера, а в адресному просторі Excel.

У С + + Builder досягти такого ж результату можна за допомогою наступного коду:

if (VarType (Serv) == varDispatch) Serv.OlePropertySet ("Width", StrToInt (Edit1-> Text));

У цьому випадку на етапі виконання здійснюється виклик тих же самих функцій Windows API, що і в попередньому випадку. OlePropertySet є оболонкою для методу варіантної змінної Exec () (поряд з OlePropertyGet, OleProcedure і OleFunction, що дозволяють одержувати значення властивостей об'єктів автоматизації та виконувати їхні методи). Відзначимо, що в Delphi також можна використовувати виклики OlePropertySet, OlePropertyGet, OleProcedure, OleFunction.

Після запуску контроллера при натисканні кнопки Connect запускається сервер. При натисканні кнопки Disconnect він вивантажується. При натисканні кнопок New File, Open File і Save File відбувається очищення вікна редагування, завантаження тексту у вікно редагування сервера з файлу, збереження тексту у файлі. Кнопка Get Visible показує і приховує вікно сервера в залежності від наявності відмітки біля напису Visible, при цьому в невидимому стані сервер продовжує виконувати свої функції. Натискання кнопки Set Visible призводить відмітку біля напису Visible у відповідність значенню властивості Visible сервера. Натиснення кнопки Get Width призводить до того, що в рядку редагування у верхній частині вікна контролера відображається ширина вікна сервера в пікселах. Якщо ввести в рядок редагування інше число і натиснути кнопку Set Width, ширина вікна сервера стане рівною введеному числу пікселів. Натискання кнопки Add String призводить до того, що в редагований текст додається рядок, що знаходиться в цей момент в поле редагування.



Рис. 2. Контролер і сервер автоматизації, запущені одночасно


Хотілося б звернути увагу на те, що, хоча ми і змогли протестувати властивості і методи сервера автоматизації за допомогою створеного контролера, у нас ще не було можливості налагодити частини коду, пов'язаного з автоматизацією. Природно, якщо клієнт запускається під управлінням середовища розробки C + + Builder, використовувати той же самий екземпляр середовища розробки для налагодження сервера неможливо. Тому слід відкрити проект сервера в окремому примірнику середовища розробки і запустити його на виконання. Якщо після цього запустити додаток-контролер (неважливо, під керуванням іншого екземпляра середовища розробки або просто засобами операційної системи) і натиснути кнопку Connect, контролер з'єднається з уже запущеним екземпляром сервера. Якщо у вихідному тексті сервера відзначені точки зупину, при їх досягненні виконання коду сервера припиняється, і управління передається середовищі розробки.

Відзначимо один очевидний факт: COM-сервер і COM-клієнт можуть бути написані з використанням будь-яких засобів розробки, що підтримують COM-технологію. Тому в принципі не забороняється написати сервер автоматизації за допомогою. Delphi, а контролер – за допомогою C + + Builder (або навпаки).

Створення контролерів для довільних серверів автоматизації


Як було сказано в попередній статті, наявність тих чи інших можливостей управління довільним сервером залежить від того, які об'єкти, властивості і методи сервера надані розробниками сервера для автоматизації за допомогою зовнішніх програм. Яким чином можна отримати інформацію про них?

Зазвичай такі відомості містяться в документації або файлах довідкової системи, що поставляються з даним сервером, як, наприклад, це зроблено в MS Office або Seagate Crystal Reports Professional. Але в принципі таку інформацію можна отримати і з бібліотеки типів.

Як приклад розглянемо використання інформації з бібліотеки типів MS Excel як одного з найбільш часто використовуваних серверів автоматизації в практиці вітчизняних розробників. Треба зауважити, що практично все, що може зробити користувач, працюючи з цим додатком, так само як і з іншими додатками MS Office, доступно для автоматизації.

Як і в попередньому випадку, для управління сервером автоматизації слід створити змінну типу Variant (в C + + Builder для цієї мети є відповідний клас) і викликати функцію CreateOleObject:

Variant XL;
……

XL=CreateOleObject(“Excel.Application.8”);


Як параметр функції CreateOleObject передається ім'я об'єкта, який ми хочемо створити. Знайти його можна в реєстрі Windows:




Рис. 3. Запис у реєстрі, відповідна вибраного сервера.


Колекції об'єктів усередині серверів автоматизації.


Усередині деяких OLE-серверів (зокрема, додатків MS Office) існує ієрархія вкладених об'єктів приблизно наступного вигляду:



Рис. 4. Орієнтовна ієрархія вкладених об'єктів OLE-сервера.


Властивостями об'єктів Excel можуть бути так звані колекції об'єктів. Наприклад, колекція Workbooks є властивістю об'єкта Excel.Application, при цьому вона містить набір вкладених об'єктів – робітників книг Excel, а ті, в свою чергу, мають властивість Worksheets, що представляє собою колекцію робочих аркушів, кожний з яких володіє властивістю Cells, що є колекцією осередків. Аналогічно, колекція Charts також є властивістю робочої книги. Аналогічно, всередині властивостями об'єктів Word можуть бути колекції Paragraphs, Words, Tables.

У С + + Builder звернення до члена колекції проводиться таким чином:

Variant MyWorkbook = XL.OlePropertyGet ("WorkBooks"). OlePropertyGet ("Item", 1);

Розглянемо приклад, що використовує такі колекції. Нехай при натисканні на кнопку головної форми програми-клієнта будуть виконані наступні дії:


  • створення в Excel робочої книги з двома сторінками і якими-небудь іменами;
  • заповнення перших 10 осередків двох перших колонок числами;
  • обчислення в одинадцятій комірці їх суми;
  • зміна кольору і зображення шрифту в одній з колонок, а також кольору осередків;
  • збереження отриманої робочої книги у файлі.

Код, що змушує Excel виконати ці дії, буде виглядати наступним чином:

//———————————————— —————————
#include <vcl.h>
#pragma hdrstop
#include <ComObj.hpp>
#include “xlauto2.h”
//———————————————— —————————
#pragma package(smart_init)
#pragma resource “*.dfm”
TForm1 *Form1;
Variant XL,v0,v1,v2;
//Function Item(“Item”);
//———————————————— —————————
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//———————————————— —————————
void __fastcall TForm1::Button1Click(TObject *Sender)
{
XL=CreateOleObject(“Excel.Application.8”);
XL.OlePropertySet(“Visible”,true);
v0=XL.OlePropertyGet(“Workbooks”);
v0.OleProcedure(“Add”);
v1=v0.OlePropertyGet(“Item”,1);
v0=v1.OlePropertyGet(“Worksheets”) ;
v0.OlePropertyGet ("Item", 1). OlePropertySet ("Name", "Бухгалтерія жовта");
v0.OlePropertyGet ("Item", 2). OlePropertySet ("Name", "Бухгалтерія червона");
for (int j=1;j<3;j++)
{
v1=v0.OlePropertyGet(“Item”,j);
for (int i=1;i<11;i++)
{
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", i, 1). OlePropertySet ("Value", i);
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", i, 2). OlePropertySet ("Value", i * 5);
v2=v1.OlePropertyGet(“Cells”).OlePropertyGet(“Item”,i,2);
v2.OlePropertyGet(“Font”).OlePropertySet(“Color”,clBlue);
v2.OlePropertyGet(“Font”).OlePropertySet(“Bold”,true);
v2.OlePropertyGet ("Interior"). OlePropertySet ("ColorIndex" ,9-3 * j);
}
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", 11,1). OlePropertySet ("Value", "= SUM (A1: A10)");
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", 11,2). OlePropertySet ("Value", "= SUM (B1: B10)");
}
XL.OlePropertySet ("DisplayAlerts", false); / / відключити діагностику при закритті сервера
XL.OlePropertyGet ("Workbooks"). OlePropertyGet ("Item", 1). OleProcedure ("SaveAs", "test.xls");
XL.OleProcedure(“Quit”);
}
//———————————————— —————————

Зазначимо, що для запуску Excel у фоновому режимі без відображення його вікна на екрані досить прибрати з коду С + + Builder рядок:

XL.OlePropertySet(“Visible”,true);



Рис. 5. Результат роботи програми


Слід звернути увагу на те, що варіантна мінлива XL оголошена за межами процедури маніпуляції OLE-сервером. Це зроблено для того, щоб існування варіантної змінної не обмежувалося даною процедурою.

Використання інформації з бібліотек типів


Відзначимо, що в наведеному вище прикладі робоча книга і робочі листи були створені із застосуванням параметрів, пропонованих за замовчуванням. Яким чином можна змінити ці параметри?

Розглянемо наступний приклад коду:

XL=CreateOleObject(“Excel.Application.8”);
XL.OlePropertySet(“Visible”,true);
v0=XL.OlePropertyGet(“Workbooks”);
v0.OleProcedure(“Add”,-4109);

Даний приклад змушує Excel створити порожній лист з діаграмою на основі шаблону, відмінного від прийнятого за замовчуванням.

Звідки в даному випадку взялася константа -4109? Яким чином можна дізнатися, якими ще константами можна користуватися при автоматизації з використанням даного сервера?

Відповіді на ці запитання можна отримати, відкривши бібліотеку типів даного сервера. Зробити це можна, вибравши пункт меню File / Open, вказавши в списку можливих файлів Type Library і вибравши відповідну бібліотеку типів (для Excel це Excel8.olb, для Word – MSWord8.olb). При цьому по витікання деякого часу (ці бібліотеки дуже великі) будуть створені файли з описом всіх використаних констант, а також властивостей і методів містяться в сервері об'єктів (у даному випадку Excel_TLB.cpp і Excel_TLB.h для С + + Builder, або Excel_TLB.pas для Delphi). При створенні цих файлів з'являться повідомлення про помилки, пов'язані з тим, що в коді Excel і Word можуть використовуватися зарезервовані слова Object Pascal або С + +.

Редактор бібліотеки типів при цьому представляє всі вкладені об'єкти у вигляді ієрархічної структури, всередині якої можна знайти значення необхідних констант. Зокрема, в розділі шаблонів можна знайти список констант, що характеризують різні типи шаблонів листів Excel:



Рис. 6. Значення констант, що описують шаблони MS Excel 97


Саме там і міститься посилання на константу xlWBATChart = -4109, відповідну шаблону діаграми.

При необхідності використовувати в коді програми-клієнта іменовані константи можна послатися на файл Excel_TLB.h йди Excel_TLB.pas в тексті модуля програми.

Точно так само можна визначити, які властивості і методи вкладених об'єктів даного сервера автоматизації:



Рис. 7. Властивості і методи колекції Workbooks


Використовуючи відомості про константи, об'єктах, властивостях і методах OLE-сервера, можна модифікувати наведений вище приклад. Тепер ми створимо в Excel графік на основі даних з робочих аркушів, скопіюємо його в буфер обміну і перенесемо в документ Word (про об'єкти і константах якого дізнаємося з бібліотеки типів Word), забезпечивши графік підписом. Відповідний код виглядає наступним чином:

//———————————————— —————————
#include <vcl.h>
#pragma hdrstop

#include “ole2.h”
#include <ComObj.hpp>
//———————————————— —————————
#pragma package(smart_init)
#pragma resource “*.dfm”
TForm1 *Form1;
Variant XL,v0,v1,v2, v22, vrange, WD,a,b,c;

//———————————————— —————————
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//———————————————— —————————

void __fastcall TForm1::Button1Click(TObject *Sender)
{
XL=CreateOleObject(“Excel.Application.8”);
XL.OlePropertySet(“Visible”,true);
v0=XL.OlePropertyGet(“Workbooks”);
v0.OleProcedure(“Add”);
v1=v0.OlePropertyGet(“Item”,1);
v0=v1.OlePropertyGet(“Worksheets”) ;
v22=v1.OlePropertyGet(“Charts”) ;
v22.OleProcedure(“Add”);
v0.OlePropertyGet ("Item", 1). OlePropertySet ("Name", "Бухгалтерія жовта");
v0.OlePropertyGet ("Item", 2). OlePropertySet ("Name", "Бухгалтерія червона");
for (int j=1;j<3;j++)
{
v1=v0.OlePropertyGet(“Item”,j);
for (int i=1;i<11;i++)
{
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", i, 1). OlePropertySet ("Value", i);
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", i, 2). OlePropertySet ("Value", i * 5);
v2=v1.OlePropertyGet(“Cells”).OlePropertyGet(“Item”,i,2);
v2.OlePropertyGet(“Font”).OlePropertySet(“Color”,clBlue);
v2.OlePropertyGet(“Font”).OlePropertySet(“Bold”,true);
v2.OlePropertyGet ("Interior"). OlePropertySet ("ColorIndex" ,9-3 * j);
}
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", 11,1). OlePropertySet ("Value", "= SUM (A1: A10)");
v1.OlePropertyGet ("Cells"). OlePropertyGet ("Item", 11,2). OlePropertySet ("Value", "= SUM (B1: B10)");
}
vrange = v0.OlePropertyGet ("Item", 1). OlePropertyGet ("Range", "A1: A10");
v1=v22.OlePropertyGet(“Item”,1);
v2=v1.OlePropertyGet(“SeriesCollection”);
v2.OleProcedure(“Add”,vrange);
vrange = v0.OlePropertyGet ("Item", 1). OlePropertyGet ("Range", "B1: B10");
v2.OleProcedure(“Add”,vrange);
v1.OleProcedure(“Select”);
XL.OlePropertyGet(“Selection”).OleProcedure(“Copy”);
WD=CreateOleObject(“Word.Application.8”);
WD.OlePropertySet(“Visible”,true);
WD.OlePropertyGet(“Documents”).OleProcedure(“Add”);
a=WD.OlePropertyGet(“Documents”);
b=a.OleFunction(“Item”,1);
for (int i=1;i<5;i++)
{b.OlePropertyGet(“Paragraphs”).OleProcedure(“Add”);};
c=b.OleFunction(“Range”,1,2);
c.OleProcedure(“Paste”);
c=b.OleFunction(“Range”,3,3);
c.OlePropertySet ("Text", "Графік, скопійований з робочої книги Excel");
XL.OlePropertySet ("DisplayAlerts", false); / / ioee?? Eou aeaaiinoeeo
XL.OlePropertyGet ("Workbooks"). OlePropertyGet ("Item", 1). OleProcedure ("SaveAs", "test.xls");
XL.OleProcedure(“Quit”);
WD.OlePropertySet ("DisplayAlerts", false); / / ioee?? Eou aeaaiinoeeo
b.OleProcedure(“SaveAs”,”test2.DOC”);
WD.OleProcedure(“Quit”);

}
//———————————————— —————————


Результати роботи програми представлені на рис. 8.



Рис. 8. Результат автоматизації створення діаграми Excel і перенесення її в Word


Отже, створивши код, подібний наведеному вище, ми можемо автоматизувати досить складний набір рутинних операцій для користувача, що може бути дуже зручно, якщо такі операції часто повторюються. При цьому створення такого коду, в загальному випадку, безумовно, вимагає набагато менших зусиль, ніж написання окремого додатка, що реалізує якісь частини функціональності Word або Excel.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*