В этом разделе речь пойдет об автоматизации. Кто читал шаги о VBA, тот уже знает, что это такое, а кто не читал - надеюсь, поймет сейчас. Для простоты скажем так - автоматизация - это возможность управлять поведением других программ (серверов автоматизации) или их элементов из своей программы (контроллера). Например - вам хотелось бы, чтобы данные из вашей программы сами собой преобразовывались в отчет MS Word'a? Или считались в таблице Excel'я? Это реально, потому что все приложения MS Office представляют собой серверы автоматизации, и мы можем этим пользоваться.
ВАЖНОЕ ЗАМЕЧАНИЕ! Все, что рассматривается ниже, подразумевает наличие 2000 офиса. Для обладателей 97-ого будут особые пометки.
Как всегда в ClassWizard'е подготовим проект (почти как в "Шаг 30 - Первый проект с AppWizard"). Запускаем VC++. Выбираем меню File и New. Далее Project и тип создаваемого приложения MFC AppWizard. В поле Project Name необходимо указать название проекта. Пусть это будет WordTest. В Step 1 выберем тип Dialog Based, в Step 2 "дополнительные параметры". Отключите About Box - он нам не нужен, также отключаем 3D Control, а это для красоты. Отключаем ActiveX Control, у нас очень простое приложение. Идем дальше. В Step 3 устанавливаем любую компоновку и нажимаем Finish. Проект готов. С помощью редактора ресурсов добавим на форму диалога кнопку. Назовем ее "Отчет", и зададим идентификатор ID_BUTTONREPORT. Все это проделывалось ранее и не должно вызывать трудностей.
Опять-таки с помощью ClassWizard'а зададим обработчик нажатия на эту кнопку и назовем его OnButtonreport().
После того, как мы подготовили проект, необходимо добыть у Word'a сведения о имеющихся в нашем распряжении его ресурсах (о как!). Каждое приложение МС-Офиса имеет при себе специальный файл, называемый "библиотекой типов". Именно в нем хранятся все сведения об объектах сервера автоматизации. Внутри себя приложения имеют иерархическую структуру. Самым верхним уровнем является Application (приложение), ниже которого лежат объекты и коллекции объектов. Объектами можно управлять напрямую, а из коллекции сначала нужно извлечь экземпляр, затем уже работать с ним. Но для нас все объекты и коллекции будут выглядеть просто как классы.
Для начала нам понадобятся такие объекты, как приложение и документ (Application и Document). Импортируем эти классы из библиотеки:
Вызовем ClassWizard, и нажмем кнопку AddClass.
Как мы видим, класс можно создать заново (New...), а можно извлечь его из библиотеки типов (From type library...). Выберите этот пункт, раскроется диалог выбора файла.
Найдите и выберите файл, который называется MSWORD9.OLB (для тех, у кого 97 офис - MSWORD8.OLB). Это и есть библиотека типов Word'а. Перед вами откроется окошко вида:
В нем в левом списке будут находиться все объекты Word'а. Выберите _Application, _Document и Documents, и нажмите кнопку Ok.
ClassWizard сгенерил классы по нашему запросу, и записал их в файлы, которые называются msword9.cpp и msword9.h. Файлы эти были автоматически включены в проект.
Подведем итоги: Приложения офиса представляют собой набор объектов, которыми можно управлять. Мы рассматриваем их как набор классов. Информация об объектах хранится в "библиотеке типов". С помощью ClassWizard'а на основе информации из этой библиотеки мы можем сгенерировать классы, содержащие данные и методы для работы с объектами Word'а.
Прежде чем мы поедем, хотим сказать, что в данных шагах не будет теоретического изложения СОМ и OLE. Хотя на самом деле это НЕОБХОДИМО знать, мы умышленно избегаем теории. Все наши шаги даются чисто с утилитарными целями - сделать, чтоб работало. Теорию можно изучить самостоятельно, и поверьте - это более продуктивно и интересно. Самое первое, что нужно сделать - это запусть приложение. Откуда мы знаем, что и как нам запускать? Очень просто. Сервера автоматизации заносят данные о себе и своих объектах в реестр, и к ним можно ображаться по символьным именам. Для Word'а (любого, независимо от версии) это "Word.Application". Вот так:
HKEY_CLASSES_ROOT\CLSID\{000209FF-0000-0000-C000-000000000046}\IndependentProgID = Word.Application
А если нам нужна какая-то специфичная версия - можно использовать еще одно имя "Word.Application.НомерВерсии". Вот оно:
HKEY_CLASSES_ROOT\CLSID\{000209FF-0000-0000-C000-000000000046}\ProgID = Word.Application.9.
Но нам в реестр лезть не надо, за нас это сделает MFC.
В файл WordTest.cpp в функцию InitInstance() перед вызовом AfxEnableControlContainer(), т.е. в самом начале добавляем строки:
if(!AfxOleInit()) // Your addition starts here { AfxMessageBox("Could not initialize COM dll"); return FALSE; } // End of your addition
Это заставит проинициализироваться систему OLE. Если этого не сделать, то вызов CreateDispatch не сработает. В файл WordTestDlg.cpp добавим строчку:
#include "msword9.h"
а в нашу функцию OnButtonreport добавляем следующий код:
_Application app; // app - это объект _Application, т.е. Word 9 if(!app.CreateDispatch("Word.Application")) //запустить сервер { AfxMessageBox("Ошибка при старте Wordа!"); return; } else app.SetVisible(TRUE); //и сделать его видимым
В принципе, можно компилировать и запускать.
Для работы с автоматизацией необходимо проинициализировать OLE (Object linking and embedding) функцией AfxOleInit. Это делается при инициализации нашего приложения в InitInstance. Далее, мы создаем экземпляр Word'а - app.CreateDispatch, и делаем его видимым app.SetVisible.
Теперь мы умеем запускать Word. Прямо скажем, хорошо, но неинтересно. Word, вообще говоря, предназначен для создания и редактирования текстовых документов, а их пока что не наблюдается. Давайте-ка что-нибудь создавать.
В Word'е все документы являются членами коллекции Documents. Прежде, чем начинать работу с документом (или вообще с элементом коллекции), надо коллекцию получить, элемент добавить, а затем получить добавленный элемент. Это в VBA доступ к объектам осуществляется через точку, перечислением. А здесь сложнее :(. Добавляем в нашу функцию следующие строки:
Documents oDocs; _Document oDoc; COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); //наша коллекция документов oDocs = app.GetDocuments(); //добавить к ней новый документ //Внимание! Если у вас Word 97 - то строчка будет такая: //oDocs.Add(covOptional,covOptional); //97 oDocs.Add(covOptional,covOptional,covOptional,covOptional); //2000 //и получить его как экзепляр коллекции с номером 1 oDoc = oDocs.Item(COleVariant(long(1))); //активизировать документ oDoc.Activate();
Все общение с функциями осуществляется с помощью переменных OLE. Например, чтобы извлечь документ с номером 1, мы пишем "COleVariant(long(1))". Переменная CovOptional, созданная с такими параметрами, используется для указания необязятельных параметров при создании объекта.
Теперь добавим текст в наш документ. Для этого придется вернуться к первому пункту, и точно как в нем написано, добавить следующие классы:
Paragraphs, Paragraph, Selection
Документ разбит на параграфы, текст (и картинки вставляются) печатается на место выделенного участка. Теперь добавляем код.
Paragraphs oPars; Paragraph oPar; Selection oSel; //получить выделение. Поскольку его нет, это будет позиция курсора oSel = app.GetSelection(); //параграфов в документе много, возникает коллекция. //получить текущюю коллекцию oPars = oSel.GetParagraphs(); //добавить новый параграф с установками по умолчанию oPar = oPars.Add(covOptional); // напечатать текст oSel.TypeText("Мой первый текст!");
Если внутри приложения может быть нескольуо однотипных объектов (например, документов), то они объединяются в коллекции. Прежде, чем начинать работу с элементом коллекции, надо коллекцию получить, элемент добавить, а затем получить добавленный элемент. После чего вызывать функции-члены этого класса.
Шаг прислал Yegor A. Blackheel (blackheel@rlt.ru)