Ф Е Д Е РАЛ Ь Н О Е АГ Е Н С Т В О П О О БРАЗО В АН И Ю РФ В О РО Н Е Ж С К И Й Г О С У Д АРС Т В Е Н Н Ы Й У Н И В Е РС И Т Е Т
Распред ел енныеприл ож ения: контрол л еры автоматизации У чебноепособиепо специал ьности230201 (071900) « И нф ормационныесистемы итех нологии» Д С .09
Ч асть 2
В О РО Н Е Ж 2005
2
У тверж д ено Н аучно-метод ическим советом В оронеж ского университета П ротокол № 12 от 18.02.2005 г.
С оставител ь Ф ертиков В .В .
П особие под готовл ено накаф ед ре инф ормационных систем ф акул ьтетакомпью терных наук В оронеж ского госуд арственного университета. Рекоменд уетсяд л я использования студ ентами4 курсад невного отд ел ения в качестве учебных материалов напрактических занятиях по курсу « Распред ел енныесистемы вычисл ений » .
3
В в едени е в OLE– а в то м а ти з а ци ю Н астол ьные прилож ения – текстовые процессоры, эл ектронные табл ицы и т.д . – пред назначены д л я повыш ения производ ител ьности труд апол ьзовател ей . П р огр ам м и р уе м ос т ь прилож ений позвол яет использовать их сервисы не только л ю д ям, но ид ругим программам. В резул ьтате, вместо того чтобы оставаться инструментами л иш ь д л я конечных пол ьзовател ей , настольные прил ож ения становятся наборами инструментов д л я программистов. О беспечение программируемости требует станд артизации способа пред оставл ения од ной программой своих сервисов д ругой программе. Д л я реализации такого типа взаимод ей ствия Microsoft испол ьзует мод ел ь COM. П рил ож ения обеспечиваю т д оступ к своим сервисам через интерф ей сы своих COM-объектов, посл е чего этимисервисамимож ет воспол ьзоваться л ю бой ф рагмент код а, способный вызывать метод ы COM-объекта. П рограммисты, таким образом, пол учаю т возмож ность созд авать прилож ения поверх ф ункциональности, пред оставл яемой имею щ имся программным обеспечением. В COM такой станд артный способ обеспечения программируемости называется OLE-авт ом ат и заци е й (OLE Automation). И так, разработчик мож ет сд ел ать прилож ение программируемым, опред ел ив объекты (так называемые, объе к т ы авт ом ат и заци и , Automation objects) иинтерф ей сы COM, метод ы которых буд ут прямо отображ аться навнутренние ф ункцииприл ож ения. О бычно, х отя ине обязател ьно, д л я этих цел ей испол ьзуется станд артный интерф ей с IDispatch , разработанный группой Microsoft Visual Basic. Н еобх од имость в этом интерф ей се возникл а на заре OLEавтоматизациииз-затого, что Visual Basic, явл яясь од ним изнаибол ее распространенных сред ств созд ания сценариев д л я программируемых прил ож ений , не под д ерж ивал возмож ностивызоваметод ов обычных COM-интерф ей сов с виртуал ьной табл ицей . П о трад иции, с которой прих од ится мириться программистам над ругих языках , OLE-автоматизациябол ьш инстваприлож ений исегод ня реал изуется с помощ ью IDispatch. Этот интерф ей с в настоящ ее время под д ерж иваетсяMicrosoft Word, Microsoft Excel имассой д ругих прил ож ений . И нтерф ей с IDispatch спроектирован таким образом, что кл иент с его помощ ью мож ет обращ аться к произвольной группеметод ов, перед авая л ю бые необх од имые параметры. Ч тобы это д ей ствовало, разработчик объекта, реал изую щ его IDispatch , д ол ж ен опред ел ить, какие в точностиметод ы буд ут д оступны. Это д остигается опред ел ением ди с пе т че р с к ого и нт ер фе йс а (dispatch interface), сокращ енно – д испинтерф ей са (dispinterface). К аж д ый экземпл яр станд артного интерф ей саIDispatch (объект мож ет под д ерж ивать несколько экземпл яров од новременно) обеспечивает д оступ к опред ел енному д испинтерф ей су. Д ругой , неменееваж ной зад ачей IDispatch ид испинтерф ей сов явл яется обеспечение мех анизмапоздне го с вязы вани я д аж е при отсутствииил и нед оступностибибл иотекитипа. К л иент в период выпол нения мож ет запросить у самого объектаинф ормацию о типе, при этом в станд артизованном вид е д оступнався необх од имая д л я испол ьзования объектаинф ормация: именаиид ен-
4
тиф икаторы свой ств иметод ов, типы параметров ит.п. П осл еэтого кл иент пол учает возмож ность д инамическигенерировать запросы к объекту. В аж ней ш ей зад ачей кл иента, испол ьзую щ его IDispatch, явл яется м ар ш али нгпараметров запросов. Н апомним, что марш ал инг (упаковкапараметров д л я пересыл ки меж д у процессами) обычного COM-интерф ей сас виртуальной табл ицей выпол няется заместител ем и загл уш кой (proxy, stub). В д анном ж е сл учае кл иент сам обязан выпол нить упаковку параметров д л я метод ад испинтерф ей сав некую станд артную ф орму, называемую вар и ант ом (variant), атакж е – распаковку из вариантарезул ьтатов вызова, возвращ енных метод ом. В ариант опред ел яет станд артную ф орму пред ставл ения каж д ого параметра и ид ентиф икатор типапараметрад л я всех типов, испол ьзуемых Visual Basic: короткое цел ое, д л инное цел ое, строкасимволов ит.д . П рограммисты над ругих языках поэтому д ол ж ны испол ьзовать л иш ь известныеVisual Basic типы. П о зднее с в язы в а ни е через ди с пи нт ерф ейс к л и ент а на Delphi Ч тобы испол нить метод д испинтерф ей са, кл иент д ол ж ен созд ать экземпл яр соответствую щ его объекта, пол учить правил ьный ид ентиф икатор метод а, упаковать корректные параметры в вариант ивызвать метод с помощ ью интерф ей са IDispatch. П омимо этого, возмож но, кл иенту потребуется д опол нител ьно обратиться за инф ормацией о типе испол ьзуемого объекта: имена и ид ентиф икаторы свой ств иметод ов, типы параметров ит.п. – д л япроизвод ства д инамического вызова. П осл е возвратарезул ьтат вызовакл иент д ол ж ен корректно распаковать изварианта, в соответствиис той ж е инф ормацией о типе. П рограммист наDelphi избавл ен от необх од имости реализации под робностей перечисл енных мех анизмов. П очти все они инкапсул ирую тся внутренним типом Variant. П еременные типаVariant, помимо всего прочего, мож но испол ьзовать д л я обращ ения к объектам автоматизации. Ч тобы иметь такую возмож ность, необх од имо вкл ю чить ссыл ку намод уль ComObj изод ного изваш их мод ул ей , программы ил ибибл иотеки: uses ComObj;
К огд авариант ссыл ается натакой объект, мож но черезвариант вызывать метод ы объекта, атакж есчитывать ил изаписывать свой ства. П риэтом синтаксис обращ ения к внеш нему объекту д остаточно очевид ен: конструкциипох ож и наиспол ьзуемые приработе с обычными(внутренними) объектами. О сновное отл ичие закл ю чается в том, что вызовы метод ов объектаавтоматизациисвязываю тся во время выпол нения и не требую т никаких пред ыд ущ их объявл ений метод а. П роверкаправил ьностиэтих вызовов во время компил яциине провод ится. С л ед ую щ ий пример ил л ю стрирует вызовы метод аавтоматизации. Ф рагмент запустит программу Microsoft Word исох ранит в ф ай л ед окумент изд вух строк. Ф ункция CreateOleObject (опред ел енная в ComObj) возвращ ает ссыл -
5
ку наIDispatch объектаавтоматизации, совместимую по присваиванию с вариантным типом. var Word: Variant; begin Word := CreateOleObject('Word.Basic'); Word.FileNew('Normal'); Word.Insert('This is the first line'#13); Word.Insert('This is the second line'#13); Word.FileSaveAs('c:\temp\test.txt', 3); end;
С интаксис вызоваметод аобъектаавтоматизацииил ид оступак его свой ству под обен таковому д л я обычного метод аил и свой ства. П риэтом, од нако, вызовы метод аавтоматизациимогут испол ьзовать как обычные позиционные, так и именованные параметры. (П равд а, серверы автоматизации могут и не под д ерж ивать именованныепараметры.) П озиционный параметр – это обычное выраж ение. И м е нованны й пар ам ет р состоит из ид ентиф икаторапараметра, сопровож д аемого символ ом присваивания, с посл ед ую щ им выраж ением. П озиционныепараметры д ол ж ны пред ш ествовать л ю бым именованным параметрам вызоваметод а. И менованные параметры могут быть опред ел ены в л ю бом поряд ке. Н екоторые серверы автоматизациипозвол яю т опускать параметры вызоваметод а, принимаяих значенияпо умол чанию . Н апример, Word.FileSaveAs('test.doc'); Word.FileSaveAs('test.doc', 6); Word.FileSaveAs('test.doc',,,'secret'); Word.FileSaveAs('test.doc', Password := 'secret'); Word.FileSaveAs(Password := 'secret', Name := 'test.doc');
П араметры метод ов автоматизации могут быть сл ед ую щ их типов: integer, real, string, Boolean иvariant. П а раметр перед ается по ссылке, есл ивыраж ениепараметрасостоит тол ько изссыл кинапеременную Delphi типаByte, Smallint , Integer , Single, Double, Currency, TDateTime , AnsiString , WordBool ил иVariant. Е сл ивыра ж ение имеет какой -л ибо д ругой тип ил иесл ионо неявл яетсятол ько переменной , параметр перед аетсязначением. П еред ачапараметрапо ссыл ке метод у, ож ид аю щ ему параметр-значение, заставл яет COM выбирать значение из параметра-ссыл ки. Н аоборот, перед ача параметра-значения метод у, который ож ид ает параметр-ссыл ку, вызывает ош ибку. Т аким образом, метод ам автоматизациимож но перед авать типизированные параметры. П риэтом процед урамарш ал ингаскрытаот программиста. О д нако самым эф ф ективным метод ом перед ачиявл яетсяобмен меж д у кл иентом и сервером д воичными д анными, описываемыми как массивы эл ементов типа varByte. Д л я та ких массивов не производ ится какой -л ибо скрытой обработки
6
в цел ях марш ал инга, и мож но эф ф ективно обращ аться к ним, испол ьзуя под программы VarArrayLock иVarArrayUnlock . Рассматривая привед енные примеры, мож но зад ать вопрос, каким образом именаобъектов (например, Word.Basic ) ил и метод ов (в д анном сл учае, FileNew, Insert иFileSaveAs ) трансл ирую тся в уника л ьныеид ентиф икаторы? Е сл ине буд ет обеспечен д анный мех анизм, невозмож ным станет связываниев реж имевыпол нения. П реж д евсего, рассмотрим наш пример так называемого пр огр ам м ного и дент и фи к ат ор а (programmatic identifier ил исокращ енно ProgID) « Word.Basic» . П рограммный ид ентиф икатор – это уд обный синоним уникал ьного ид ентиф икаторакл асса CLSID. Н апомним, что в мод ел и COM к лас с объе к т а ид ентиф ицирует опред ел енную реал изацию объекта ил игруппы интерф ей сов. О тображ ение уд обочитаемого ProgID в CLSID сод ерж ится в реестре – оно помещ ается туд априустановке программы Word накомпью тер. Т аким образом, л ю бой кл иент, вызвав CreateOleObject с ProgID в качестве параметра, запустит соответствую щ ий сервер автоматизации. Ч то касается ид ентиф икаторов метод ов и свой ств, то соответствую щ ая инф ормация связывания мож ет быть пол ученакл иентом из библ иотеки типа ил иж е путем обращ ения непосред ственно к объекту черезIDispatch . Н апример, метод IDispatch::GetIDsOfNames специал ьно пред назначен д л я этих цел ей : он возвращ ает ид ентиф икатор метод аил и свой ствад испинтерф ей сав ответ назапраш иваемоекл иентом имя. Д анный второй способ в своевремябыл разработан группой Visual Basic иявл яетсянаибол еепростым, х отяинесамым эф ф ективным. И менно он испол ьзуется встроенным типом Variant Delphi д л я производ ствапозд него связывания. Е щ е од ин важ ный вопрос: гд е программист мож ет пол учить свед ения о реал изуемых сервером объектах автоматизации? В д анном сл учае наибол еевероятный источник инф ормациид л ярассматриваемого примера– интерактивная справочная системаMicrosoft Word с пол ным списком объектов в этом прил ож ении, которые мож но испол ьзовать д л я автоматизации, их метод ов исвой ств ивообщ евсего, что необх од имо д л яобращ енияк их сервисам. В общ ем сл учае прил ож ения, пред оставл яю щ иесервисы черезавтоматизацию , сод ерж ат весьма под робную д окументацию насей счет. У ч е бный п ри м е р к ли е нт а Microsoft Word О д ной изнеобх од имых ф ункций бол ьш инстваприл ож ений , работаю щ их с д анными, явл яется генерацияразл ичного род аотчетов. К ак известно, д л я реал изациигенератораотчетов по выборкам избазд анных программист наDelphi имеет в своем распоряж ении ш татные сред ства: компоненты из вкл адок « QReport» и« Decision Cube» палитры компонентов. Разработанный таким образом генератор становится частью прил ож ения, встроен в него, сопровож д ается специализированным интерф ей сом, реализованным как часть интерф ей са всего прил ож ения. Ч асто, од нако, пол ьзовател ям необх од имы отчеты в ф орме, пригод ной д л я некоторой д альней ш ей обработки. У д обно д л я этих цел ей испол ьзовать общ ед оступные оф исные прил ож ения (Word, Excel и т.п.). В этом сл учае зад ачей генератораотчетов становится выд ачаф ай л ов в соответствую -
7
щ их ф орматах (*.doc, *.xls ит.п.). М ож но пой тид альш е: реал изовать распред ел енное прил ож ение, в котором генератор отчетов буд ет кл иентом С У БД с од ной стороны икл иентом сервераавтоматизации(Word, Excel ит.п.) сд ругой . Рассмотрим простой пример такого прил ож ения, генерирую щ его отчет припомощ иMicrosoft Word. Д анные д ля отчетабуд ут выбираться изд емонстрационной базы д анных с псевд онимом DBDEMOS, вх од ящ ей в поставку Delphi. Д л я д оступак какой -л ибо из табл ицэтой базы д анных необх од имо наф орму разрабатываемого прил ож ения поместить компонент TTable, установив соответственно его свой стваDatabaseName и TableName . Ал горитм чтения д анных изтабл ицы мож ет быть, например, сл ед ую щ им: Table1.Open; with Table1 do while not Eof do begin // прочитать значение полей из Fields.Fields[i].AsString; Next end; Table1.Close;
Д л я корректного соед иненияс OLE-сервером кл иент д ол ж ен, преж д евсего, сд ел ать попытку обнаруж ить уж езапущ енный сервер. И тол ько в сл учаенеуд ачи– созд ать новый объект автоматизации. Т аким образом, пример из пред ыд ущ егоразд ел ацел есообразно д оработать, как показано ниж е: try W := except W := end;
// если Word запущен - подключиться к нему GetActiveOleObject('Word.Application'); // если нет - запустить CreateOleObject('Word.Application');
П омимо прочего, в д анном примере мы изменил ипрограммный ид ентиф икатор, испол ьзовав вместо « Word.Basic» бол ее современный объект автоматизации « Word.Application » . К свед ению , объект « Word.Basic» инкапсул ирует конструкции од ноименного языка, обеспечивавш его программируемость преж них версий прилож ения: Word version 6.0 и Word for Windows 95. Е го реализациясох раненад л яобеспечениясовместимостисовременных версий Word со старымикл иентами. Н иж е привед ен пол ный код генератораотчета, который реализован как откл ик насобытиенаж атиякнопки: procedure TForm1.Button1Click(Sender: TObject); var W,D,S,PosBeg,PosEnd:Variant; i,j:Integer; ws:WideString; begin with Table1 do begin DatabaseName:='DBDEMOS'; TableName:='country.db'; Open end;
8 try // если Word запущен - подключиться к нему W := GetActiveOleObject('Word.Application'); except // если нет - запустить W := CreateOleObject('Word.Application'); end; W.Visible := True; D:=W.Documents.Add; S:=W.Selection; S.TypeText('Hello, World!'#13); PosBeg := S.Start; j:=0; ws:='№'; for i:=0 to Table1.FieldCount-1 do ws:=ws+#9+Table1.Fields.Fields[i].FieldName; ws:=ws+#13; S.TypeText(ws); with Table1 do while not Eof do begin j:=j+1; ws:=IntToStr(j)+'.'; for i:=0 to FieldCount-1 do ws:=ws+#9+Fields.Fields[i].AsString; ws:=ws+#13; S.TypeText(ws); Next end; PosEnd := S.Start; Table1.Close; D.Range(PosBeg,PosEnd).ConvertToTable(Separator:=#9, AutoFit:=True,AutoFitBehavior:=1,DefaultTableBehavior:=1) end;
П ож алуй ста, незабуд ьтевставить ссыл ку наупомянутый мод ул ь ComObj. Н апомним такж е о необх од имостиизучения д окументациипо программированию Microsoft Word приразработке его кл иентов автоматизации. В д анном пособиимы имеем возмож ность л иш ь сл ед ую щ его краткого пояснения. Д л я преобразования введ енных текстовых д анных в табл ицу испол ьзован простой прием: текущ ая позиция д окументазапоминается д важ д ы, д о ипосл еввод апреобразуемого текста: PosBeg := S.Start; S.TypeText(ws); ... PosEnd := S.Start;
// начальная позиция // вывод текста // конечная позиция
П осл е чего весь отмеченный д иапазон преобразуется в табл ицу вызовом метод аConvertToTable . Заметим, что в д анном сл учае испол ьзованы именованные параметры. О братите внимание такж е наиспользованный в программе тип WideString. И менно его цел есообразно испол ьзовать д л я пред ставл ения текстовой инф ормацииприпрограммированииOLE-автоматизации, поскол ьку этот тип совместим со станд артным COM типом пред ставл ения строк BSTR.
9
П рил ож ение буд ет бол ееэф ф ективным, есл ивместо конвертирования строк из внутренних типов Delphi в WideString каж д ый раз д л я перед ачи серверу, с самого начал асох ранять текст в требуемом ф ормате. Резул ьтат работы прил ож ения – сод ерж имое табл ицы country.db д емонстрационной базы д анных DBDEMOS, помещ енное в вид е отчетав д окумент Microsoft Word – пред ставл ен нарисункениж е:
Р ис. 1. О тчет в д окументеMicrosoft Word О собе нност и п рог рам м и ровани я на C++Builder Разработкакл иента, взаимод ей ствую щ его с OLE-сервером черезд испинтерф ей с, возмож натакж ев сред епрограммированияBorland C++Builder, х отя и требует написания несколько бол ее обш ирного код а. Д ело в том, что разработчикиC++Builder д л я реал изациитакой возмож ностиреш ил иобой тись сред ствами, пред оставл яемымистанд артным языком C++, в то время как разработчикиDelphi пош л ипо путирасш ирениястанд артасцел ью упрощ ениясинтаксиса. П реж д е всего, необх од имо заметить, что реализован специал ьный кл асс Variant, обл а д аю щ ий теми ж е возмож ностями, что и встроенный тип Variant Delphi. Д л я нас важ но то, что объекты д анного кл ассата кж е могут х ранить указател инад испинтерф ей сы ипред оставл яю т возмож ность управл ения объектамиавтоматизации. М ы рекоменд уем вкл ю чать в код программы заголовочный ф ай л utilcls.h , который помимо самого необх од имого инструментария сод ерж ит ш аблоны метод ов и кл ассов, пред оставл яю щ ие ал ьтернативныеспособы обращ енияк метод ам исвой ствам д испинтерф ей сов:
10 #include
Н е вд аваясь в тонкостиреал изациид анной библ иотеки, укаж ем л иш ь на сущ ествованиед вух способов обращ енияк д испинтерф ей су. • М етод Variant::Exec пред назначен д л я запускаметод ов д испинтерф ей сов, атакж е– д л ясчитыванияиустановкиих свой ств. • Ш абл оны метод ов кл асса Variant , названные OleFunction , OleProcedure , OlePropertyGet и OlePropertySet , реа л изую т бол ее уд обный способ д оступак метод ам исвой ствам д испинтерф ей сав смысл е уд обочитаемоститекстапрограммы. Н апример, команд аустановки свой ствад испинтерф ей сачерез объект W кл ассаVariant, взятаяизпред ыд ущ его примеранаDelphi: W.Visible := True;
наязыкеC++ мож ет быть реализованад вумяспособами: W.Exec(PropertySet("Visible")<<true);
ил и W.OlePropertySet("Visible",true);
В д анном сл учаевторой способ бол еенагл яд ен, поскольку требует указания л иш ь д вух параметров, в том числ е – именисвой ства. П ервый способ реал изован бол ее замысл овато: метод у Exec перед ается тол ько од ин параметр – объект кл ассаPropertySet , специал ьно разработанного д л я совместной работы с Exec. Е го описание вы мож ете най тив заголовкеsysvari.h . Т ам мож но в частности обнаруж ить, что базовым кл ассом д л я PropertySet явл яется кл ассAutoCmd : class AutoCmd { public: ... // By value args AutoCmd& operator AutoCmd& operator AutoCmd& operator AutoCmd& operator ... }; class PropertySet : { ... };
<<(const <<(const <<(const <<(const
Variant& arg); short arg); int arg); float arg);
public AutoCmd
Д л я базового кл ассаAutoCmd перегруж енаоперация <<, чтобы реал изовать уд обный способ перед ачипараметров метод ам д испинтерф ей са. Этаоперация описанад л я всех типов, испол ьзуемых встроенным мех анизмом марш ал инга, который , как ив сл учае Delphi, скрыт от программиста(выш е привед ен
11
л иш ь небол ьш ой ф рагмент описания, сод ерж ащ ий тол ько четыретипа). Д ругими насл ед никами AutoCmd явл яю тся кл ассы PropertyGet , Procedure и Function , пред на значенные д л я аналогичного испол ьзование в качестве параметраExec. PropertyGet – д л я считывания значения свой ства, Procedure и Function – д л я вызоваметод ов д испинтерф ей са. Н апример, перевод ф ра гментарассматриваемого примеранаObject Pascal Delphi: S.TypeText('Hello, World!'#13); PosBeg := S.Start;
выгл яд ит наС ++ сл ед ую щ им образом: S.Exec(Procedure("TypeText")<<WideString("Hello, World!\n")); PosBeg = S.Exec(PropertyGet("Start"));
Зд есь д л я над еж ностииспол ьзовано явное преобразование к рассмотренному ранее типу WideString. Д ругой способ « перевод а» , с использованием ш абл онов метод ов Variant, выгл яд ит так: S.OleProcedure("TypeText",WideString("Hello, World!\n")); PosBeg=S.OlePropertyGet("Start");
П оясним работу д анного описания. М етод ы OleProcedure , OleFunction , OlePropertyGet иOlePropertySet кл ассаVariant описа ны с испол ьзованием мех анизмаш аблонов. Это д ает возмож ность использовать приих вызовах параметры произвольных типов. Бол еетого, этиш абл оны перегруж ены, что позвол яет перед авать произвол ьное кол ичество параметров. М ож но убед иться, рассматривая соответствую щ ий заголовочный ф ай л , что д опустимо испол ьзовать вплоть д о д есятипараметров (помимо основного, обязател ьного параметра, означаю щ его имя метод ад испинтерф ей са). В наш ем примеренаDelphi мы зад авал ид иапазон д л япреобразованияего в табл ицу: D.Range(PosBeg,PosEnd)
Д васпособанаписанияэтого наC++: D.OleFunction("Range",PosBeg,PosEnd) D.Exec(Function("Range")<
К ак вид но, испол ьзование ш аблонов метод ов Variant в бол ьш инстве сл учаев бол ее нагл яд но. О д нако метод Exec незаменим, есл и требуется перед ать именованные параметры. В наш ем примере вызов метод а ConvertToTable испол ьзует именова нныепараметры: ConvertToTable(Separator:=#9, AutoFit:=True,AutoFitBehavior:=1,DefaultTableBehavior:=1)
Реал изациятакого вызованаC++ выгл яд ит так:
12 Exec(Procedure("ConvertToTable") <
Т еперь, наконец, мы готовы реал изовать рассматриваемый генератор отчетов наC++Builder. Н иж е привод ится пол ный текст обработчикасобытия наж атиякнопкид л язапускагенератора: void __fastcall TForm1::Button1Click(TObject *Sender) { Table1->DatabaseName="DBDEMOS"; Table1->TableName="country.db"; Table1->Open(); Variant W,D,S,PosBeg,PosEnd; try // если Word запущен - подключиться к нему { W = GetActiveOleObject("Word.Application"); } catch(...) // если нет - запустить { W = CreateOleObject("Word.Application"); } // W.Exec(PropertySet("Visible")<<true); W.OlePropertySet("Visible",true); // D=W.Exec(PropertyGet("Documents")).Exec(Function("Add")); D=W.OlePropertyGet("Documents").OleFunction("Add"); S=W.OlePropertyGet("Selection"); // S.OleProcedure("TypeText",WideString("Hello, World!\n")); S.Exec(Procedure("TypeText") <<WideString("Hello, World!\n")); PosBeg = S.Exec(PropertyGet("Start")); int i,j=0; WideString ws="№"; for(i=0; iFieldCount; i++) ws+="\t"+Table1->Fields->Fields[i]->FieldName; ws+="\n"; S.OleProcedure("TypeText",ws); while(!Table1->Eof) { ws=IntToStr(++j)+"."; for(i=0; iFieldCount; i++) ws+="\t"+Table1->Fields->Fields[i]->AsString; ws+="\n"; S.OleProcedure("TypeText",ws); Table1->Next(); } PosEnd = S.Exec(PropertyGet("Start")); Table1->Close(); // D.OleFunction("Range",PosBeg,PosEnd).Exec(
13 D.Exec(Function("Range")<
С трокикомментариев показываю т ал ьтернативные способы обращ ения к д испинтерф ей су. У ч е бный п ри м е р к ли е нт а Microsoft Excel П остроим новый д емонстрационный генератор отчетов по выборкеизбазы д анных : теперь в качестве сервераавтоматизациииспол ьзуем Excel. Т акой выбор д аж ебол ееестественен, чем пред ыд ущ ий , поскол ьку, пол учив эл ектронную табл ицу с резул ьтатами запросаиз базы д анных , конечный пользовател ь смож ет провестиих д ал ьней ш ую обработку. В новь напомним о необх од имости изучения д окументациипо программированию Microsoft Excel приразработке его кл иентов автоматизации. В д анном пособии мы имеем возмож ность л иш ь сл ед ую щ его краткого пояснения. Рассмотрим примерную сх ему иерарх ии внутренних объектов, экспортируемых Excel. Application
Workbooks Workbooks[1]
Worksheets Worksheets[1]
Cells Cells[1,1] Cells[1,2]
Worksheets[2] Workbooks[2]
Cells[2,1] Cells[2,2]
Р ис. 2. У прощ еннаясх емаиерарх ииобъектов Excel Этасх емапоказывает неиерарх ию насл ед ования, аил л ю стрирует способ д оступа к тем ил и иным объекта. И так, на верш ине иерарх ии – объект Excel.Application . С вой ства миобъектов Excel могут явл яться так называемыекол л екцииобъектов. Н апример, колл екция Workbooks явл яетсясвой ством объектаExcel.Application , приэтом онасод ерж ит набор влож енных объектов – рабочих книг Excel, а те, в свою очеред ь, обл ад аю т свой ством Worksheets , пред ставл яю щ им собой кол л екцию ра бочих л истов, каж д ый из которых обл ад ает свой ством Cells, явл яю щ имся кол л екцией ячеек. Д оступ к
14
конкретной ячей ке, таким образом, мож но пол учить через свой ство Cells соответствую щ его рабочего л иста: Sheet.Cells[1,1].Value := 'Hello, World!';
А мож но зад ать д иапазон, размером в од ну ячей ку, ипол учить к ней д оступ черезсвой ство Range: Sheet.Range['A1'].Value := 'Hello, World!';
Д остоинство второго способапроявл яется в сл учае необх од имостивывод ав Excel бол ьш их массивов д анных , что явл яется обычной практикой . У скорить такой вывод мож но, используя сл ед ую щ ий прием. В место посл ед овател ьного вывод ад анных в каж д ую ячей ку: for i:=1 to 10 do Sheet.Cells[1,i].Value := 'Hello, World!';
сначалаф ормируется вариантный массив, посл е чего он вывод ится в д иапазон ячеек од ним обращ ением к д испинтерф ей су: Arr := VarArrayCreate([1,10],varVariant); for i:=1 to 10 do Arr[i] := 'Hello, World!'; Sheet.Range['A1:J1'].Value := Arr;
П ринеобх од имостимож но вывод ить заод ин прием ид вумерные табл ицы, образовываянакл иентской сторонед вумерныевариантныемассивы. О барассмотренные способавывод амассивов проил л ю стрированы в примере реал изации откл икананаж атие кнопки запускагенератораотчетов (остальные д ей ствия при разработке кл иентапол ностью повторяю т аналогичные д ей ствия, прод ел анныенамид л яреал изациикл иентаWord): procedure TForm1.Button1Click(Sender: TObject); var Exl,Book,Sheet,Arr: Variant; i,j: Integer; begin with Table1 do begin DatabaseName:='DBDEMOS'; TableName:='country.db'; Open end; try // если Excel запущен - подключиться к нему Exl := GetActiveOleObject('Excel.Application'); except // если нет - запустить Exl := CreateOleObject('Excel.Application'); end; Exl.Visible:=True; Book := Exl.WorkBooks.Add; Sheet := Book.ActiveSheet; Sheet.Range['A1'].Value := 'Hello, World!'; Sheet.Range['A2'].Value := ' №'; j:=0;
15 for i:=0 to Table1.FieldCount-1 do Sheet.Cells[2,i+2].Value := Table1.Fields.Fields[i].FieldName; Arr := VarArrayCreate([0,Table1.FieldCount],varVariant); with Table1 do while not Eof do begin j:=j+1; Arr[0] := IntToStr(j); for i:=0 to FieldCount-1 do Arr[i+1] := Fields.Fields[i].AsString; Sheet.Range['A'+IntToStr(j+2)+':'+ Chr(Ord('A')+FieldCount)+IntToStr(j+2)].Value:=Arr; Next end; Table1.Close end;
Заметим, что привывод е ш апкитабл ицы каж д ая ячей каExcel запол няется инд ивид уально, ад л я вывод ад анных запол няется вариантный массив, который затем испол ьзуетсяд л яперед ачиExcel строкитабл ицы цел иком:
Р ис. 3. О тчет в книгеMicrosoft Excel Д л я пол ноты изл ож ения материал апривед ем текст программы наC++ д л яразработчиков кл иентав сред епрограммированияBorland C++Builder: void __fastcall TForm1::Button1Click(TObject *Sender) { Table1->DatabaseName="DBDEMOS"; Table1->TableName="country.db"; Table1->Open(); Variant Exl,Book,Sheet,Arr;
16 try // если Excel запущен - подключиться к нему { Exl = GetActiveOleObject("Excel.Application"); } catch(...) // Excel не запущен - запустить его { Exl = CreateOleObject("Excel.Application"); } Exl.OlePropertySet("Visible", true); Book=Exl.OlePropertyGet("WorkBooks").OleFunction("Add"); Sheet = Book.OlePropertyGet("ActiveSheet"); Sheet.OlePropertyGet("Range","A1"). OlePropertySet("Value","Hello, World!"); Sheet.OlePropertyGet("Range","A2"). OlePropertySet("Value"," №"); int i,j=0; for(i=0; iFieldCount; i++) Sheet.OlePropertyGet("Cells",2,i+2). OlePropertySet("Value", Table1->Fields->Fields[i]->FieldName); int Bounds[]={0,Table1->FieldCount}; Arr = VarArrayCreate(Bounds,1,varVariant); while(!Table1->Eof) { Arr.PutElement(IntToStr(++j),0); for(i=0; iFieldCount; i++) Arr.PutElement( Table1->Fields->Fields[i]->AsString,i+1); Sheet.OlePropertyGet("Range", Sheet.OlePropertyGet("Cells",j+2,1), Sheet.OlePropertyGet("Cells",j+2, Table1->FieldCount+1)). OlePropertySet("Value", Arr); Table1->Next(); } Table1->Close(); }
П рограмма испол ьзует описанные в пред ыд ущ ем разд ел е мех анизмы управл ения д испинтерф ей сом. Н овым зд есь явл яется л иш ь испол ьзование вариантного массива, д л я созд ания которого ф ункцией VarArryCreate потребовалсявспомогател ьный массив Bounds, описываю щ ий егоразмерности. И с по л ьзо в а ни е би бл и о т ек и т и по в дл я ра ннего с в язы в а ни я В пред ыд ущ их разд ел ах д остаточно под робно рассмотрен способ созд ания кл иентов с испол ьзованием типаVariant , основанного намех анизме ди нам и че с к ого (позд него) связывания. П ритаком способекл иент (контрол л ер автоматизации) явно ил и неявно испол ьзует метод IDispatch::GetIDsOfNames , авозмож но, такж е д ругие метод ы IDispatch , д л я генерирования д инамического запроса к объекту во время выпол нения. Д анный способ наибол ее прост в испол ьзовании изнутри Delphi (как и
17
C++Builder), поскол ьку все под робности мех анизмаскрыты от программиста. Т ем не менее, он явл яется наименее производ ительным: д остаточно пред ставить себемногократные вызовы GetIDsOfNames д л я уд аленного сервераавтоматизации, перед аваемые по сети! В ысокопроизвод ител ьная альтернатива– р анне е с вязы вани е наэтапекомпил яцииил икомпоновкираспред ел енного прил ож ения. Д анный мех анизм пред пол агает, что на момент созд ания кл иента пол ностью известнаи нфор м аци я о т и пе испол ьзуемых объектов автоматизации: список под д ерж иваемых интерф ей сов и их метод ов, параметры каж д ого метод а, типы свой ств объектов ипараметров метод ов имногое д ругое. О ткуд а программист кл иента(ил и соответствую щ ая сред апрограммирования) мож ет пол учить всю эту инф ормацию ? О д ин из источников нам уж е известен – это д окументация, сопровож д аю щ ая сервер автоматизации. Т ем не менее, в таком серьезном д ел е, как раннее связывание, нел ьзя сл епо пол агаться над обросовестность авторов д окументации. В о-первых , пред оставл яемой инф ормации мож ет оказаться нед остаточно, во-вторых , этой неф ормал изованной инф ормацией не смож ет воспользоваться сред апрограммирования д л я автоматизации процессов сборкираспред ел енного прил ож ения. Бол ее над еж ный источник – библ иотекатипов, сопровож д аю щ аяпрактическил ю бой скол ько-нибуд ь серьезный сервер автоматизации. Би бли от е к а т и пов (Type Library) – независимое от языкапрограммирования сред ство исчерпываю щ его д окументирования COM-объекта. Ф ормат библ иотеки типов станд артизован в COM. П оставкабибл иотеки типов мож ет осущ ествл яться разнымиспособами. Н апример, ее сод ерж имоемож ет быть интегрировано в COM-сервер в качестве ресурсаил ираспространяться независимо в отд ел ьных ф ай л ах с расш ирением .TLB ил и.OLB . П осл ед неерасш ирение трад иционно д л япоставкибибл иотек типов прилож ений Microsoft Office. И зуч е ни е би бли от е к и т и п ов Delphi-п рог рам м и ст ом С танд артный способ специф икации библ иотек типов – язык Microsoft IDL (Interface Definition Language). П о д анной специф икациикомпил ятор MIDL мож ет сгенерировать библ иотеку в станд артном д воичном ф ормате, и именно этот посл ед ний ф ормат – обязател ен д л якомпл ектапоставкисервераавтоматизации. И сх од ный текст наIDL, как правил о, непоставл яется. Ч тобы воспол нить этот пробел современные интегрированные сред ы программирования пред оставл яю т д вамех анизмаиспол ьзованияд оступной инф ормациио типе: • просмотр и ред актирование библ иотеки типов при помощ и специал ьной утил иты – ред акторабибл иотекитипов; • импорт библ иотекитипов в проект кл иентского прил ож ения. О бамех анизмаобеспечены как в сред еDelphi, так ив C++Builder. В строенный р е дак т ор би бли от е к и т и пов позвол яет осущ ествл ять просмотр и ред актирование библ иотеки, д оступной в д воичном ф ормате. Бол еетого, приж ел ании мож но автоматически сгенерировать исх од ный текст описания библ иотеки типов наIDL (осущ ествить экспорт библ иотеки типов). П роцед ураи м пор т а би бли от е к и т и пов закл ю чается, упрощ енно говоря, в генерациинеобх од имой совокупности мод ул ей , присоед иняемых к проекту и д ел аю щ их д ос-
18
тупной инф ормацию о типах наэтапе компил яции. Д ругимисл овами, испол ьзуя библ иотеку типов в д воичном ф ормате, сред апрограммирования автоматически генерирует исх од ный текст насоответствую щ ем языке программирования (Object Pascal ил и C++) специал ьных мод ул ей , накоторые мож но буд ет ссыл атьсяизостал ьных мод ул ей , составл яю щ их проект. Такаяпроцед ураимеет общ ее название (из терминологии распред ел енных вычисл ений ) – от обр аж е ни е к язы к у пр огр ам м и р овани я. И зучение библ иотеки типов незнакомого сервераавтоматизации мы рекоменд уем начинать с ее просмотрав ред акторе библ иотекитипов. П оскол ьку речь ид ет о Delphi, аред актор интегрирован в сред у программирования, прощ е всего открыть библ иотеку типов во время разработкикл иентского проекта: меню File→ Open и указать ф ай л библ иотеки в д воичном ф ормате (мож но ф ай л *.EXE прилож ения д л я Windows). Д а вай те, как ираньш е, экспериментировать с прил ож ениямиMicrosoft Office. В д анном сл учае важ наверсия: д ал ьней ш ие конкретные примеры рассматриваю т версию 2000, од нако общ ая метод икаот версии, разумеется, независит. И так, начнем с изучения библ иотекитипов Microsoft Word, открыв ф ай л MSWORD9.OLB , в котором онара змещ ена. П ервое, что нуж но сд ел ать – это узнать, какие объекты автоматизацииэкспортирует сервер. В библ иотеке типов каж д ый объект описан при помощ и так называемого с опр яж е нного к лас с а (CoClass). В наш ем сл учае мож но обнаруж ить, что сервер реал изует цел ый ряд объектов: Global, Application, Document, Font и д р. (см. рисунок ниж е). Д л я объектов, которыепред пол агается испол ьзовать, необх од имо выяснить, какиеинтерф ей сы каж д ый изних реал изует. Н апример, объект Application , без испол ьзования которого невозмож но обой тись, реал изует показанные нарисунке интерф ей сы, причем, интерф ей с _Application описан, как и нт е р фе йс по ум олчани ю. П осл ед няяинф ормациячрезвычай но важ над л япрограммистов, пл анирую щ их связыватьсяс объектом черезинтерф ей с IDispatch , поэтому на д анный ф акт такж ецел есообразно обращ ать вниманиев первую очеред ь. П осл е изучения необх од имых сопряж енных кл ассов мож но перех од ить к реал изуемым имиинтерф ей сам. В кл адкаText ред акторасод ерж ит автоматическисгенерированный ф рагмент описаниябибл иотекитипанастанд артном языке IDL, причем, пред ставл енный ф рагмент относится к выбранному над ереве сл еваузл у. Н апример, так выгл яд ит описание интерф ей са_Application (в сил ьном сокращ ении): [ uuid(00020970-0000-0000-C000-000000000046), version(8.1), helpcontext(0x00000970), hidden, dual, nonextensible, oleautomation ]
19 interface _Application: IDispatch { . . . [propget, id(0x00000006), helpcontext(0x09700006)] HRESULT _stdcall Documents([out,retval] Documents **prop ); [propget, id(0x00000002), helpcontext(0x09700002)] HRESULT _stdcall ActiveDocument( [out,retval]Document **prop ); . . . [id(0x00000451), helpcontext(0x09700451)] HRESULT _stdcall Quit([in, optional] VARIANT * SaveChanges, [in, optional] VARIANT * OriginalFormat, [in, optional] VARIANT * RouteDocument ); [id(0x00000168), helpcontext(0x09700168)] HRESULT _stdcall Move([in] long Left, [in] long Top ); [id(0x00000169), helpcontext(0x09700169)] HRESULT _stdcall Resize([in]long Width, [in]long Height ); . . . };
Р ис. 4. Библ иотекатипов Microsoft Word в ред акторе П рограммист, пред пол агаю щ ий использовать д анный интерф ей с, д ол ж ен отметить сл ед ую щ ее. В о-первых , это д уальный (dual) интерф ей с, д оступ к которому возмож ен д вумя способами: как к д испинтерф ей су черезIDispatch и как к обычному интерф ей су с виртуальной табл ицей . Д ал ее– интерф ей с совместим с OLE-автоматизацией (oleautomation ), что позвол яет при вызове
20
его метод ов использовать станд артный марш алинг параметров при помощ и упаковкив Variant. Н аконец, описания свой ств иметод ов интерф ей сасод ерж ат всю необх од имую д л я их использования инф ормацию : д испетчерские ид ентиф икаторы (DISPID) специф ицированы кл ю чевым сл овом id, типы свой ств (в наш ем сл учаеDocuments иActiveDocument ) снабж ены специф икаторами типов и всеми необх од имыми атрибутами, метод ы (у нас – Quit, Move иResize) – списка мипараметров вызова. П осл еизучения сод ерж имого библ иотекитипов в ред акторе мож но перех од ить к процед уре ееимпортав проект разрабатываемого кл иентского прил ож ения. Запускается процед ураиз меню Project→ Import Type Library. В д иалоговом окне « Import Type Library» необх од имо выбрать нуж ную библ иотеку из готового списка, перечисл яю щ его установл енные наваш ем компью тере серверы автоматизации(в наш ем примере– Microsoft Word). Л ибо указать конкретный ф ай л библ иотеки(MSWORD9.OLB ), наж ав кнопку « Add» . П оскол ьку мы х отим ограничиться л иш ь созд анием импортированного мод ул я, снимем ф л аж ок « Generate Component Wrapper» , зад ад им катал ог д л я записи ф ай л ов генерируемого мод ул яв строкеввод а« Unit dir name» инаж мем кнопку « Create Unit» . П о заверш ениипроцед уры импорта, выпол нениекоторой мож ет занять некоторое время из-забол ьш их размеров генерируемых ф ай л ов, к проекту буд ет присоед инен вновь созд анный мод ул ь Word_TLB.pas . В аж ное зам ечани е . О писанная процед ураимпортамож ет потребовать д еинстал л яциикомпонентов вкл ад ки« Servers» пал итры, есл итаковые установл ены наваш ем компью тере. Д ел о в том, что все эти компоненты пол учены именно путем импортированиябибл иотек типов соответствую щ их серверов автоматизации и сред аDelphi не считает возмож ным повторять эту процед уру. Е сл и вы все-таких отите ее прой ти, вам необх од имо вызвать д иалог из меню Component→ Install Packages иснять ф л аж ок напротив пакета, в который соответствую щ иекомпоненты был иустановл ены. О д новременно с импортированным мод ул ем Word_TLB.pas могут быть созд аны ид ругие ф ай л ы. Н апример, в наш ем сл учае их д ва: Office_TLB.pas и VBIDE_TLB.pas . П осл ед нее означает, что импортированная библ иотекатипов сод ерж алассыл ки над ругие ф ай л ы, сл ед овател ьно, импортированный в проект мод уль – такж есод ерж ит соответствую щ иессыл ки: uses Office_TLB, VBIDE_TLB; // в файле Word_TLB.pas
В кл ю чать этид опол нител ьные мод ул ив проект не нуж но, поскол ьку разрабатываемыевамимод ул ибуд ут испол ьзовать описаниятолько изWord_TLB.pas . Н езабуд ьтед л яэтого вставить соответствую щ иессыл ки: uses Word_TLB;
// в ваших модулях
Рассмотрим импортированный мод ул ь бол ее под робно. Заметим, что при просмотре его сод ерж имого неоценимую помощ ь оказывает д ерево « Code Explorer» , поскол ьку объем мод ул я д остаточно вел ик (бол еемегабай танамоем компью тере). П реж д е всего, необх од имо обратить внимание наош ибкиимпор-
21
тирования, пред упреж д енияо которых сод ерж атся в самом началемод ул яв вид екомментариев. В от некоторыеизних : //Errors: // Hint: Symbol 'Application' renamed to 'WordApplication' // Hint: Symbol 'Document' renamed to 'WordDocument' // Hint: Symbol 'Font' renamed to 'WordFont' // Hint: Member 'Repeat' of'_Application' changed to'Repeat_' // Hint: Member 'Type' of '_Document' changed to 'Type_' // Hint: Member 'End' of 'Range' changed to 'End_' // Hint: Member 'Case' of 'Range' changed to 'Case_' // Hint: Parameter 'End' of Range.SetRange changed to 'End_'
К ак вид ите, все эти ош ибочные ситуации связаны с конф л иктом имен импортируемой библ иотеки с кл ю чевыми сл овами ил и встроенными ид ентиф икаторамиязыкапрограммирования (Object Pascal). В ых од , од нако, най д ен: в каж д ом конкретном сл учае конф л иктный ид ентиф икатор заменяется пох ож им, о чем инф ормируется программист. П осл ед ний ж е обязател ьно д ол ж ен просмотреть всеэтисообщ ения с цел ью поискаид ентиф икаторов, которыеон пл анирует испол ьзовать в своей программе. К ак ираньш е, начнем с поискаинф ормацииоб импортированных сопряж енных кл ассах . И х список вместе с объявл ением реализуемых имиинтерф ей сов по умол чанию мож но обнаруж ить в сл ед ую щ ем вид е: // // // //
*******************************************************// Declaration of CoClasses defined in Type Library (NOTE: Here we map each CoClass to its Default Inter face) *******************************************************// Global = _Global; WordDocument = _Document; WordFont = _Font; WordParagraphFormat = _ParagraphFormat; WordOLEControl = _OLEControl; WordLetterContent = _LetterContent; WordApplication = _Application;
Т ак, рассмотренный выш есопряж енный кл асс Application , переименованный в процессе импорта в WordApplication , реализует интерф ей с по умол чанию с именем _Application . П омимо этого в самом конце текстамод ул я нах од ятся описания специальных кл ассов (Object Pascal), по од ному д ля каж д ого импортированного сопряж енного кл асса, которые имею т д остаточно простой вид . Н апример, д л я кл асса WordApplication созд ано сл ед ую щ ее описание, снабж енноеисчерпываю щ им комментарием:
22 ********************************************************// The Class CoWordApplication provides a Create and CreateRemote method to create instances of the default interface _Application exposed by the CoClass WordApplication. The functions are intended to be used by clients wishing to automate the CoClass objects exposed by the server of this typelibrary. ********************************************************// CoWordApplication = class class function Create: _Application; class function CreateRemote(const MachineName: string): _Application; end;
// // // // // // // //
К ак вид но, этикл ассы пред назначены искл ю чител ьно д л я созд ания соответствую щ их объектов автоматизации по команд е кл иентского прил ож ения, посл е чего мож но буд ет использовать сервисы, пред оставл яемые объектом через его интерф ей сы. П ерей д ем к изучению посл ед них . Код , ответственный за описание импортированного интерф ей са_Application , в сил ьном сокращ ениипривод итсяниж е: _Application = interface(IDispatch) ['{00020970-0000-0000-C000-000000000046}'] ... function Get_Documents: Documents; safecall; function Get_Windows: Windows; safecall; function Get_ActiveDocument: WordDocument; safecall; function Get_ActiveWindow: Window; safecall; function Get_Selection: Selection; safecall; ... property Documents: Documents read Get_Documents; property Windows: Windows read Get_Windows; property ActiveDocument: WordDocument read Get_ActiveDocument; property ActiveWindow: Window read Get_ActiveWindow; property Selection: Selection read Get_Selection; ... end;
Это описание – обычно д л я программы наObject Pascal. С л ед ует л иш ь обратить внимание накл ю чевое слово safecall, специф ицирую щ ее описание л ю бого метод аинтерф ей са. В связис этим необх од имо рассмотреть с оглаш е ни е о бе зопас ном вы зове, принятое в Object Pascal. Рассматривая библ иотеку типов в ред акторе, вы уж е, наверное, обратил ивнимание наспециал ьный тип возвращ аемого значения метод ов. Д ело в том, что д л я серверов автоматизации сущ ествует ж есткое ограничение: все их метод ы д ол ж ны возвращ ать значение типаHResult. Этот тип опред ел ен в COM мод ел и и д ает значение, которое свид етельствует о том, успеш но л изаверш ил ось выпол нениеоперацииил инет,
23
причем в посл ед нем сл учаеперед анноезначениесод ерж ит код ош ибки. Д ругие д анные, пол ученные в резул ьтате работы метод а, возвращ аю тся через вых од ные параметры (с мод иф икатором out). Т аким образом, есл ибы Object Pascal не пред усматривал клю чевое сл ово safecall, импортированное описание метод аGet_Documents , например, выгл яд ел о бы так: function
Get_Documents(var Docs: Documents): HResult;
В ызывать такой метод был о бы неуд обно. Д ирективаsafecall, активирую щ ая согл аш ение о безопасном вызове, заставл яет Delphi взять насебя ответственность заанал из возвращ енного код аHResult . П риэтом генерируется искл ю чение припол учениикод аош ибки. П рограммист ж е, со своей стороны, пиш ет уд обный код вызова, соответствую щ ий импортированному описанию . У п равле ни е Microsoft Word ч е ре з и м п орт и рованные и нт е рф е й сы Зд есь мы буд ем мод иф ицировать код разработанного ранее генератора отчетов по выборкам избазы д анных . Н апомним, что этот код испол ьзует д инамическое связывание, скрытое от программиста внутри встроенного типа Variant. В ыш е ска зано, что реал изация программируемости через Variant х отя и уд обна, но малоэф ф ективна. Т еперь, изучив библ иотеку типов сервера Microsoft Word, мы пол учаем возмож ность испол ьзованияод ного изд вух бол ее эф ф ективных способов управл ения, зад ей ствую щ их мех анизм раннего связывания. Н аибол ее эф ф ективным из них явл яется вызов метод ов COM-интерф ей санапрямую черезви р т уальную т абли цу. Этот способ рассматривается в д анном разд ел е. А в сл ед ую щ ем рассмотрен второй способ – обращ ениек свой ствам иметод ам д испинтерф ей сачерезIDispatch:Invoke . И так, начнем с ред актирования описаний пред ыд ущ его примера, испол ьзовавш их Variant. Т еперь мы буд ем испол ьзовать л ибо типы интерф ей сов, описанные в импортированном мод ул е библ иотекитипов, л ибо OleVariant – специальный тип Object Pascal, тож е пред ставл яю щ ий вариант, но тол ько л иш ь д л ятипов, совместимых с COM: var W:_Application; D:_Document; S: Selection; PosBeg,PosEnd: OleVariant;
Заметьте, мы буд ем использовать _Application и_Document , которые явл яю тся интерф ей самипо умолчанию д л я соответствую щ их объектов автоматизации. К од , инициирую щ ий связываниессервером, преобразуем к вид у: try // если Word запущен - подключиться к нему W := GetActiveOleObject( ClassIDToProgID(CLASS_WordApplication))as _Application; except // если нет - запустить W:=CoWordApplication.Create; end;
24
Зд есь
в
ил л ю стративных цел ях испол ьзуется ф ункция ClassIDToProgID , позвол яю щ а я извл ечь из реестрапрограммный ид ентиф икатор ProgId по зад анному ид ентиф икатору кл ассаCLSID. П оскол ьку, с од ной стороны, отображ ение ProgId–CLSID в реестре сох раняется при инстал л яции сервера, ас д ругой стороны, значение параметраCLASS_WordApplication описано в импортированном мод ул е библ иотеки типов, мы гарантированно под кл ю чаемся именно к тому серверу, библ иотекатипов которого испол ьзованав проекте. В сл учае неуд ачи соед инения сервер запускается при помощ и кл ассаCoWordApplication , образованного в процессе импортасопряж енного кл ассабибл иотекитипов. П осл ед нее, о чем сл ед ует сказать перед тем как привестиисх од ный код цел иком, это о способе вызоваметод ов с необязател ьными параметрами. Рассмотритесл ед ую щ ий прием: D := W.Documents.Add(EmptyParam,EmptyParam, EmptyParam,EmptyParam);
Е сл ивернуться к просмотру библ иотекитипов, мож но заметить, что метод Add имеет четыре необязател ьных параметра, д л я которых сервер, повид имому, пред усматривает значения по умол чанию . Е сл инас устраиваю т эти значения, мож но в качестве параметров перед ать EmptyParam. А теперь – обещ анный пол ный текст генератораотчета, переработанный в соответствиис изл ож еннымипринципами: procedure TForm1.Button1Click(Sender: TObject); var W:_Application; D:_Document; S: Selection; PosBeg,PosEnd,v1,v2,v3: OleVariant; i,j: Integer; ws: WideString; begin with Table1 do begin DatabaseName:='DBDEMOS'; TableName:='country.db'; Open end; try // если Word запущен - подключиться к нему W := GetActiveOleObject( ClassIDToProgID(CLASS_WordApplication))as _Application; except // если нет - запустить W:=CoWordApplication.Create; end; W.Visible := True; D := W.Documents.Add(EmptyParam,EmptyParam, EmptyParam,EmptyParam); S:=W.Selection; S.TypeText('Hello, World!'#13); PosBeg := S.Start; j:=0; ws:='№'; for i:=0 to Table1.FieldCount-1 do ws:=ws+#9+Table1.Fields.Fields[i].FieldName;
25 ws:=ws+#13; S.TypeText(ws); with Table1 do while not Eof do begin j:=j+1; ws:=IntToStr(j)+'.'; for i:=0 to FieldCount-1 do ws:=ws+#9+Fields.Fields[i].AsString; ws:=ws+#13; S.TypeText(ws); Next end; PosEnd := S.Start; Table1.Close; v1:=#9; v2:=True; v3:=1; D.Range(PosBeg,PosEnd). ConvertToTable(v1,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam, v2,v3,v3) end;
Е сл итеперь построить проект изапустить прил ож ение, резул ьтат его работы буд ет тем ж е, что иприработе клиентачерезVariant. Т ем не менее, затраченные усил ия окупаю тся как в процессе разработки прил ож ения (раннее связывание безопаснее, поскольку выявл яю тся ош ибкиприкомпил яцииикомпоновке), так ив реж имевыпол нения (эф ф ективен д оступ к сервисам объектов автоматизации). Ранне е связывани е ч е ре з ди сп и нт е рф е й с В д анном разд ел е рассмотрен способ обращ ения к свой ствам иметод ам д испинтерф ей сачерезIDispatch:Invoke , испол ьзую щ ий так ж е, как пред ыд ущ ий , инф ормацию избибл иотекитипов ираннее связывание. О баэтимех анизмауправл ениясервером Microsoft Word стал ивозмож ными, бл агод арятому, что бол ьш инство экспортируемых интерф ей сов явл яю тся д уал ьными. С пособ, описываемый ниж е, по эф ф ективности занимает промеж уточное полож ение меж д у обращ ением через виртуальную табл ицу интерф ей са(как показано в пред ыд ущ ем разд ел е) и управл ением с испол ьзованием Variant (д инамическое связывание черезд испинтерф ей с). П оэтому материал, привод имый ниж е, необх од им как ил л ю страция работы с серверами автоматизации, имею щ ими только д испинтерф ей сы: при нал ичии д уал ьных интерф ей сов пред почтение, очевид но, сл ед ует отд авать их виртуальным табл ицам. В ернувш ись к рассмотрению мод ул я Word_TLB, построенного в резул ьтате импортабибл иотеки типов Microsoft Word, мож но заметить, что все интерф ей сы, импортированные из д уальных интерф ей сов библ иотеки, имею т « д вой ников» . Н апример, использованный ранее интерф ей с _Application (часть его описания привод ится выш е по тексту) сопровож д ается сл ед ую щ им ф рагментом (в сил ьном сокращ ении):
26 _ApplicationDisp = dispinterface ['{00020970-0000-0000-C000-000000000046}'] ... property Documents: Documents readonly dispid 6; property Windows: Windows readonly dispid 2; property ActiveDocument: WordDocument readonly dispid 3; property ActiveWindow: Window readonly dispid 4; property Selection: Selection readonly dispid 5; property Visible: WordBool dispid 23; ... procedure Move(Left: Integer; Top: Integer); dispid 360; procedure Resize(Width: Integer; Height: Integer); dispid 361; function CheckGrammar(const String_:WideString):WordBool; dispid 323; ... end;
О тметим, что д анный интерф ей с ид ентиф ицирован тем ж е самым гл обальным ид ентиф икатором (IID), что и_Application . К рометого, многиеего свой стваи метод ы – такж е д убл ирую т соответствую щ ие возмож ности « д вой ника» _Application . Тол ько в д анном сл учае их описания вместо д иректив safecall сна бж ены д испетчерскими ид ентиф икаторами (dispid), заимствованнымиизбибл иотекитипов. П од обныед вой ники, описанные кл ю чевым сл овом dispinterface , есть и у всех остал ьных д уальных интерф ей сов: _DocumentDisp , SelectionDisp и т.д . И менно они д ел а ю т д л я кл иентана Object Pascal вызовы черезIDispatch:Invoke прозрачными. И спол ьзуем рассмотренный прием д л я мод иф икации наш его учебного генератораотчетов. В место _Application зад ей ствуем его « д вой ника»: var W:_ApplicationDisp;
П рипод кл ю чениик серверу требую тся д опол нител ьные операциипривед енияк использованному типу интерф ей са: try // если Word запущен - подключиться к нему W := GetActiveOleObject( ClassIDToProgID(CLASS_WordApplication)) as _ApplicationDisp; except // если нет - запустить W:=CoWordApplication.Create as _ApplicationDisp; end; W.Visible := True;
П осл ед няя строкаил л ю стрирует д оступ к свой ству объектаавтоматизациичерезего д испинтерф ей с.
27
Кли е нт Microsoft Excel с м е хани зм ом ранне г о связывани я У соверш енствуем пред л ож енным способом разработанный ранее генератор отчетов в книге Microsoft Excel. Н ачнем с того, что изучим библ иотеку типов, поставл яемую в ф ай л е excel9.olb , сначал ав ред акторе библ иотек, азатем – импортируем еев состав проектакл иентского прил ож ения. В се д ей ствия при этом аналогичны тол ько что описанным. Заменим привед енным ниж е ф рагментом код откл иканасобытие запускагенератора, азатем рассмотрим особенности программирования по сравнению с метод ом д оступа через Variant : procedure TForm1.Button1Click(Sender: Tobject); var Exl:_Application; Book:_WorkBook; Sheet:_WorkSheet; i,j: Integer; Arr: Variant; begin with Table1 do begin DatabaseName:='DBDEMOS'; TableName:='country.db'; Open end; try // если Excel запущен – подключиться к нему Exl := GetActiveOleObject( ClassIDToProgID(CLASS_ExcelApplication)) as _Application; except // если нет – запустить Exl:=CoExcelApplication.Create; end; Exl.Visible[0]:=True; Book := Exl.WorkBooks.Add(EmptyParam,0); Sheet := Book.ActiveSheet as _WorkSheet; Sheet.Range['A1',EmptyParam].Value := 'Hello, World!'; Sheet.Range['A2',EmptyParam].Value := ' №'; j:=0; for i:=0 to Table1.FieldCount-1 do Sheet.Cells.Item[2,i+2].Value := Table1.Fields.Fields[i].FieldName; Arr := VarArrayCreate([0,Table1.FieldCount],varVariant); with Table1 do while not Eof do begin j:=j+1; Arr[0] := IntToStr(j); for i:=0 to FieldCount-1 do Arr[i+1] := Fields.Fields[i].AsString; Sheet.Range['A'+IntToStr(j+2), Chr(Ord('A')+FieldCount)+IntToStr(j+2)].Value := Arr; Next end; Table1.Close end;
И так, соед инение с сервером реал изовано так ж е, как и сервером Word. Н о вызывает уд ивл ение то, что свой ство Visible явл яется векторным. Д ей ствител ьно, приизучениибибл иотекитипов мож но обратить вниманиенато, что
28
многие описанные в ней метод ы и свой стватребую т перед ачи специального вх од ного параметраlcid (local ID) – 32-битового ид ентиф икаторал окал изации, испол ьзуемого в системе языковой под д ерж ки Win32 National Language Support. Рассмотрите, например, ф рагмент IDL-описания интерф ей са _Application , вклю ча ю щ ий метод SaveWorkspace и свой стваVisible и Width : [ uuid(000208D5-0000-0000-C000-000000000046), helpcontext(0x00020001), dual, oleautomation ] interface _Application: IDispatch { ... [id(0x000000D4), helpcontext(0x000100D4)] HRESULT _stdcall SaveWorkspace( [in, optional] VARIANT Filename, [in, lcid] long lcid ); ... [propget, id(0x0000022E), helpcontext(0x0001022E)] HRESULT _stdcall Visible([in, lcid] long lcid, [out, retval] VARIANT_BOOL * RHS ); [propput, id(0x0000022E), helpcontext(0x0001022E)] HRESULT _stdcall Visible([in, lcid] long lcid, [in] VARIANT_BOOL RHS ); ... [propget, id(0x0000007A), helpcontext(0x0001007A)] HRESULT _stdcall Width([in, lcid] long lcid, [out, retval] double * RHS ); [propput, id(0x0000007A), helpcontext(0x0001007A)] HRESULT _stdcall Width([in, lcid] long lcid, [in] double RHS ); ... };
Н ескол ько по-иному, неж ел ив программес Variant, организованаработасо свой ствамиCells иRange интерф ей са_Worksheet . П ривед ем их описаниянаIDL избибл иотекитипов: interface _Worksheet: IDispatch { ... [propget, id(0x000000EE), helpcontext(0x000100EE)] HRESULT _stdcall Cells([out, retval] Range ** RHS ); ...
29 [propget, id(0x000000C5), helpcontext(0x000100C5)] HRESULT _stdcall Range([in] VARIANT Cell1, [in, optional] VARIANT Cell2, [out, retval] Range **RHS); ... };
К ак вид ите, обаэтисвой ствавозвращ аю т значенияод ного итого ж етипа. П риэтом, д л я того, чтобы испол ьзовать значение Cells как указател ь накол л екцию ячеек, необх од имо явное применение д вумерного векторного свой ства Item . Зд есь не прох од ит « трю к» , который мы использовал и в програ мме с Variant : Sheet.Cells[2,i+2].Value:=Table1.Fields.Fields[i].FieldName;
Т акая конструкция непред усмотренабибл иотекой типов, но д опустимаприиспол ьзованиимех анизмад инамического связывания. С вой ство Range имеет д вавх од ных параметра, из которых посл ед ний – необязател ьный . М ы в своей программеиспол ьзуем обаварианта: как с явным зад анием второго параметра, так ис его пропуском, указав EmptyParam вместо него. И м п орт и ровани е би бли от е к и т и п ов в п рое к т C++Builder С ред апрограммирования C++Builder реализует всеописанные выш е возмож ностипо использованию библ иотекитипов в цел ях созд ания контрол л еров автоматизациис ранним связыванием. П омимо основных преимущ еств, связанных собственно с испол ьзованием раннего связывания, в д анном сл учае пол учается горазд о бол еекомпактный иуд обочитаемый исх од ный код : отпад ает необх од имость в многочисл енных вызовах метод ов кл асса Variant OleProcedure , OleFunction , OlePropertyGet , OlePropertySet ит.п. К ак уж е говорилось, разработчикиC++Builder д л я реализациивозмож ностиCOM-программирования везд е, гд еэто возмож но, обх од ятся станд артными сред ствамиязыкаC++, избегая расш ирения станд артав угод у упрощ ению синтаксиса. В резул ьтате иминаписано огромное кол ичество программного обеспечения наC++, обл егчаю щ его COM-программирование. П ричем оно открыто д л я понимания программисту, испол ьзую щ ему соответствую щ ие загол овочные ф ай л ы. В этом смысл е программист наC++ наход ится в бол еевыгод ном пол ож ении, неж ел ипрограммист наObject Pascal. Т еперь приступим к реш ению поставл енной зад ачиконкретно, созд ад им кл иентское прил ож ение, испол ьзую щ ее импорт библ иотеки типов. В се под готовител ьные процед уры описаны в пред ыд ущ их разд ел ах . Т ак ж е, как в сред е Delphi, мож но открыть библ иотеку типов в ред акторе ипросмотреть ее сод ерж имое. Е сл и библ иотека типов Microsoft Excel, поставл яемая в ф ай л е excel9.olb , В ами уж е изученав д остаточной степени, мож но перех од ить к процед уреееимпортирования в состав проекта. В резул ьтатеимпорта, в проект буд ет д обавл ен мод ул ь Excel_TLB.cpp с заголовочным ф ай лом Excel_TLB.h . И нструмент Class Explorer помож ет В а м в поиске нуж ных
30
ф рагментов при просмотре этих ф ай лов, поскол ьку они имею т поистине впечатл яю щ иеразмеры (бол еевосьмис половиной мегабай т намоем компью тере)! Н еобх од имо понять принципы, по которым строится мод ул ь импортированной библ иотеки, тогд авообщ е незачем буд ет обращ аться к его исх од ному тексту. В д анном руковод стве мы сд ел аем л иш ь первый ш аг напутиизучения этих принципов. П реж д евсего, рассмотрим ф ай л Excel_TLB.cpp , который имеет относител ьно небольш ой размер. О н пол езен, поскольку именно он в вид е комментариев сод ерж ит сообщ енияоб ош ибках импортаид ентиф икаторов библ иотеки: // Errors: // Hint: Symbol 'Windows' renamed to 'Windoz' // Hint: Symbol 'Application' renamed to 'ExcelApplication' // Hint: Symbol 'Chart' renamed to 'ExcelChart' // Hint: Symbol 'Worksheet' renamed to 'ExcelWorksheet' // Hint: Symbol 'Workbook' renamed to 'ExcelWorkbook' ...
Д ал ее сл ед ую т опред ел ения гл обальных ид ентиф икаторов всех объектов библ иотекитипов (самой библ иотеки, интерф ей сов исопряж енных кл ассов) в вид еопред ел ений констант: const { const {
GUID LIBID_Excel = {0x00020813, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} }; GUID IID_Adjustments = {0x000C0310, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} };
П росмотр загол овочного ф ай л аExcel_TLB.h мож ет занять сущ ественно бол ее прод ол ж ител ьное время. М ы сосред оточим свое внимание натех конструкциях , в которые превратил ись импортированные интерф ей сы. Н иж е привед ен ф рагмент, поясняю щ ий некоторые особенности процед уры импортах орош о знакомого нам д уального интерф ей са_Application : interface _Application : public IDispatch { . . . __property Excel_tlb::WorkbooksPtr Workbooks = {read = get_Workbooks}; . . . }; . . . template class TCOM_ApplicationT : public TComInterface<_Application>, public TComInterfaceBase { . . . }; typedef TCOM_ApplicationT<_Application> TCOM_Application; . . .
31 template class _ApplicationDispT : public TAutoDriver<_Application> { public: . . . HRESULT BindDefault() { return OLECHECK(Bind(CLSID_ExcelApplication)); } HRESULT BindRunning() { return BindToActive(CLSID_ExcelApplication); } . . . }; typedef _ApplicationDispT<_Application> _ApplicationDisp;
М ы
вид им зд есь описание сразу пяти объектов: интерф ей са _Application , кл асса TCOM_Application , построенного по описа нному зд есь ж еш аблону TCOM_ApplicationT , ш аблон кл ассов _ApplicationDispT ипостроенный по нему кл асс _ApplicationDisp . В резул ьтате программист пол учил в распоряж ение д варабочих инструментад л я программирования импортированного интерф ей са: кл ассы TCOM_Application и _ApplicationDisp , инка псул ирую щ иесоответственно интерф ей с с виртуал ьной табл ицей ид испинтерф ей с. Это значит, что д л я программистанаC++ оба рассмотренные выш е способад оступак д уальному интерф ей су столь ж е л егко реал изуемы, как ид л япрограммистанаObject Pascal. И з привед енного ф рагментавид но, что _ApplicationDisp пред усматривает уд обные метод ы д л я установл ения соед инения с уж е работаю щ им сервером ид л я запускасервера. В оспользуемся ими, чтобы переписать соответствую щ ий код наш его учебного генератораотчетов: _ApplicationDisp Exl; if(!SUCCEEDED( // если Excel работает Exl.BindRunning())) // подключиться к нему; Exl.BindDefault(); // не запущен - запустить его
П росматривая заголовочный ф ай л Excel_TLB.h , мож но заметить такж е, что многие свой ства и метод ы возвращ аю т типы, ид ентиф икаторы которых имею т од ин итот ж есуф ф икс Ptr. Т ак в привед енном выш еф рагментесвой ство Workbooks интерф ей са_Application имеет тип WorkbooksPtr . О писаниявсех этих типов тож емож но най тив ф ай л еExcel_TLB.h, например: interface DECLSPEC_UUID( "{000208DA-0000-0000-C000-000000000046}") _Workbook; typedef TComInterface<_Workbook,&IID__Workbook> _WorkbookPtr; interface DECLSPEC_UUID( "{000208DB-0000-0000-C000-000000000046}") Workbooks; typedef TComInterface<Workbooks,&IID_Workbooks> WorkbooksPtr;
32
Т аким образом, все этитипы такж е пред назначены д л я д оступак виртуал ьной табл ице соответствую щ их интерф ей сов. В закл ю чениид анного руковод ства обратим внимание на уд обную особенность кл ассов – насл ед ников TAutoDriver . Е сл и этот насл ед ник инка псул ирует д уальный интерф ей с, он позвол яет д оступ к метод ам посл ед него не тол ько черезIDispatch::Invoke , но инапрямую – через виртуальную табл ицу. Д л я реал изациитакого прямого д оступав ш аблоне TAutoDriver соответствую щ им образом перегруж енаоперация обращ ения по указателю -> . Т аким образом, имея например, объект кл асса_ApplicationDisp , мы мож ем испол ьзовать л ю бой из д вух способов д оступак д уальному интерф ей су _Application : Exl.Visible = true; // Visible - свойство _ApplicationDisp _WorkbookDisp Book = Exl->Workbooks->Add(); // Workbooks - свойство _Application
За клю чени е: о сно в ны е ш а ги п ри ра з ра бо тке ко нтро ллеро в а в то м а ти з а ци и К онтрол л ер автоматизациисозд ается с цел ью управл ения сервером автоматизации и испол ьзует мех анизмы, пред оставл яемые тех нологией OLEавтоматизации. Бол ьш инство попул ярных серверов реал изую т объекты автоматизации с д уал ьными интерф ей сами, что позвол яет применять в кл иентском прил ож ениитриразл ичных способауправл ения: • испол ьзовать мех анизм позд него (д инамического) связывания через метод ы IDispatch ; • импортировать библ иотеку типов сервера и испол ьзовать мех анизм раннего связываниячерезвиртуал ьныетабл ицы интерф ей сов; • испол ьзовать вызовы д испинтерф ей сов через IDispatch::Invoke при раннем связывании, такж еимпортировав библ иотеку типов. П ервый из рассматриваемых способов наибол ее прост в реал изации, но наименее эф ф ективен в реж име выпол нения. В д анном сл учае в процессе разработки контрол л ера автоматизации в сред ах программирования Delphi ил и C++Builder необх од имо: 1. И зучить д окументацию , сопровож д аю щ ую сервер автоматизации в части описанияиспользуемых объектов иинтерф ей сов. 2. Н аписать текст программы контрол л ера, в котором интерф ей сы объявить л ибо как экземпл яры встроенного типаVariant (Object Pascal), л ибо как объекты кл ассаVariant (С ++). В посл ед нем сл учае д л я д оступак свой ствам и метод ам интерф ей са использовать специальные метод ы кл асса Variant. В торой способ управл ения явл яется наибол ее эф ф ективным в реж име выпол нения итребует от программистов контрол л ераавтоматизациид опол нител ьных усил ий :
33
1. И зучить библ иотеку типов сервераавтоматизации, открыв ее в интегрированном в сред у программирования ред акторе библ иотек типов. О братить вниманиенасопряж енныекл ассы объектов автоматизации, которыепред пол агается использовать, описания реализуемых этими объектами интерф ей сов, атакж е– выяснить, какие из интерф ей сов объявл ены как интерф ей сы по умол чанию . 2. И мпортировать библ иотеку типов в проект кл иентского прил ож ения. П роцед ураимпортасгенерирует мод ул ь описания библ иотекитипов насоответствую щ ем языке программирования (Object Pascal ил иC++), посл е чего на него мож но ссыл аться из собственных мод ул ей проекта(д ирективы uses ил и#include соответственно). 3. И зучить части импортированного мод ул я, ответственные заописания испол ьзуемых сопряж енных кл ассов и интерф ей сов библ иотекитипов. О братить внимание насообщ ения об ош ибках импортирования, вкл ю ченные в текст мод ул яв вид екомментариев. 4. Н аписать текст программы контрол л ера, в котором интерф ей сы объявить как экземпл яры соответствую щ их кл ассов импортированного мод ул я. Д оступ к интерф ей сам реал изовать по правил ам, пред усмотренным испол ьзованнымикл ассамииих описаниями. П осл ед ний из способов управл ения серверами автоматизации, рекоменд уется д л яд оступак д испинтерф ей сам, которыесервер нереализует как д уальные. Этот способ пред пол агает объявление интерф ей сав программе кл иента припомощ испециал ьных кл ассов, описанных в мод ул е импортированной библ иотекитипов, имею щ их специф ические особенностид л я сред ы программирования(Delphi ил иC++Builder).
П ра кти чески е з а да ни я 1. Д оработай те учебный пример контрол л ераMicrosoft Word с мех анизмом позд него связываниятак, чтобы генерируемый отчет уд овл етворял ваш ему пред ставл ению о х орош ем д изай не. Н апример, измените цвета и размеры ш риф тов, вставьте загол овок и кол онтитул ы, разработай те процед уру автоматического под бораш ирины кол онок табл ицы ит.п. 2. Д оработай те учебный пример контрол л ераMicrosoft Excel с мех анизмом позд него связывания так, чтобы генерируемый отчет вкл ю чал д опол нител ьные числ овые значения, рассчитываемые по ф ормул ам Excel. Н апример, д опол ните табл ицу итоговыми строками, суммирую щ ими значения столбцов; д обавьте новые стол бцы д л я расчетапо значениям ячеек текущ их строк, скаж ем, пл ощ ад ь, прих од ящ аясянаод ного человеканасел ениястраны, ит.п. 3. Д оработай те учебный пример контрол л ераMicrosoft Excel с мех анизмом позд него связывания так, чтобы вся табл ицагенерируемого отчетавывод ил ась в д иапазон ячеек од ним обращ ением к д испинтерф ей су. Н апомним, что д л яэтого сначаланеобх од имо сф ормировать накл иентской сторонед вумерный вариантный массив.
34
4. Д оработай те учебный пример контрол л ераMicrosoft Excel с мех анизмом позд него связываниятак, чтобы генерируемый отчет уд овл етворял ваш ему пред ставл ению о х орош ем д изай не. Н апример, измените цвета и размеры ш риф тов, вставьте загол овок, поэкспериментируй те с цветами заливки ячеек, стил ямиих рамок ит.п. 5. Разработай те контрол л ер Microsoft Word с мех анизмом позд него связывания, под обный рассмотренному в пособии генератору отчетов, но с испол ьзованием упомянутого объектаWord.Basic . Т ем самым вы обеспечите совместимость реализованного контрол л ера с преж ними версиями сервера: Word version 6.0 иWord for Windows 95. 6. Разработай те контрол л ер автоматизации, испол ьзую щ ий мех анизм позд него связывания од новременно с д вумя серверами: Microsoft Word иExcel; д л я реш ения сл ед ую щ ей зад ачи. Табл ицав книге Excel д ол ж набыть скопированав д окумент Word исоответствую щ им образом отф орматирована. П риж ел ании мож но комбинировать разл ичные варианты мех анизмов связывания с серверамиавтоматизации. 7. Разработай теконтрол л ер с мех анизмом позд него связыванияд ля л ю бого д оступного вам сервераавтоматизации, не описанного в д анном пособии. Н апример, Microsoft Access, Outlook, PowerPoint ил ид р. 8. Разработай те контрол л ер автоматизацииMicrosoft Word ил иExcel, под обный рассмотренным в пособии генераторам отчетов, но с использованием мех анизмараннего связываниечерезд испинтерф ей с описанным в пособииспособом обращ ения к свой ствам и метод ам д испинтерф ей са через IDispatch:Invoke . 9. В оспол ьзуй тесь компонентами вкл ад ки « Servers» палитры, пол ученными путем импортирования библ иотек типов соответствую щ их серверов автоматизации, д л я разработки контрол лераавтоматизации Microsoft Word ил и Excel, под обного рассмотренным в пособиигенераторам отчетов. С равните затраты нареал изацию такого контрол л ерасописаннымив пособииспособами. 10. Разработай те контрол л ер автоматизации Microsoft Word ил и Excel, реал изую щ ий обработку каких -л ибо событий , возникаю щ их на сервере. Н апример, выд ел ение абзацаWord ил ид иапазонаячеек Excel ит.п. В ам необх од имо изучить COM-тех нологию « объектов с под кл ю чением» (Connectable Objects), обеспечиваю щ ей мех анизм событий в мод ел иCOM. Затем, просматривая библ иотеку типов сервера, выбрать требую щ ий ся вам исх од ящ ий интерф ей с (outgoing interface) и реал изовать накл иенте соответствую щ ий ему объект– приемник событий (event sink). Н апример, сервер Excel под д ерж ивает исх од ящ ий интерф ей с IAppEvents с бол ьш инством испол ьзуемых напрактикесобытий . Реал изация приемникапри помощ и рассматриваемых в пособии инструментал ьных сред ств не пред ставл яет затруд нений . Н апример, библ иотека C++Builder сод ерж ит специал ьный ш абл он кл ассов TEventDispatcher (см. уж е испол ьзованный нами загол овочный ф ай л utilcls.h ), который уд обно испол ьзовать в качестве базового при разработке путем насл ед ования собственного кл ассаприемника.
35
С оставител ь Ф ертиков В ад им В алериевич Ред актор БунинаТ .Д .