Работа с файлами, созданными не текстовыми редакторамиРабота с распространенными файлами типа .doc и .xml не так удобна при использовании компоненет Borland С++ Builder и для доступа к с этими файлами приходится идти по довольно запутанным дорожкам кодов. Причина - эти файлы, привычные для Windows, (и не только эти - .dot, .xla, .wiz, .cag, .fla, .ppt и другие) устроены по правилам структурированного хранилища. Сам же файл на диске, хранящий внутри себя это хранилище, называется "файл-документ" (docfile) или "составной файл" (compound file). Первый термин применялся во времена OLE 1, второй появился вместе с OLE 2, сейчас они обычно используются как синонимы. Кроме того в OLE существует понятие "составной документ" (compound document) - термин обозначающий абстрактный подкласс хранилищ особого вида, о чем речь пойдет несколько позже. Составной файл состоит из следующих элементов:
Для доступа к таким файлам используется идея экспорта объектов, заключается в том, что один модуль создает объект, а другой его использует посредством обращения к его доступным методам (сервисам) - или "Технология COM" (Component Object Model- Модель Компонентных Объектов). Технология COM позволяет создавать и открывать составные файлы в различных режимах, обращаться к их каталогам и т.п. и явилась результатом развития принципов упрощения доступа к составным файлам Windows. COM объект можно представить классом, который имеет много своийств и методов доступ к которым возможен при помощи так называемых интерфейсов. Это стандарт, описывающий как должны работать интерфейсы класса (или объекта) - включая такие вопросы, как, например, работа с памятью или многопоточностью, и каким образом приложения могут использовать компоненты, созданные в стандарте COM. COM является стандартом, независимым от языка программирования и независимым от аппаратного окружения. Для идентификации интерфейса используется структура типа GUID (Global Universal Identifier) или CLSID - 128 - битное целое число, которое, гарантирует уникальность COM-объекта на всех компьютерахи для всех. Для того, чтобы воспользоваться COM-объектом, клиенту необходимо знать его GUID и кроме того это единственный тип данных, которые предопределены для интерфейса. Если известен GUID COM-объекта, то для создания его экземпляра можно воспользоваться стандартным WinAPI, например, вызовом функции CoCreateInstance. Для определения форматов данных интерфейс использует свои определенные типы данных - так называемые OLE Automation Datatypes. Точнее сказать, что если ссылка на данный интерфейс может быть передана в другой модуль, то список формальных параметров методов интерфейса обязан содержать только определенные типы данных. Технология COM позволила перейти от технологии OLE 1.0 (Windows 3.1 - щелчок на внедренном объекте в документе приложения, вызов приложения для работы с внедренным объектом, редактирование внедрения, и сохранение изменений путем редактирования соответствующих ссылок в исходном документе) к технологии OLE 2.0, которая позволила обеспечить взаимодействие между компонентами, написанными разными компаниями и на разных языках. СОМ модель объекта в системном обеспечении предусматривает полную совместимость за счет модульности разработки компонентов. Новая особенность, появившаяся в OLE 2.0, - это автоматизация OLE, которая обеспечивает доступ к объектам приложения и манипуляцию с ними извне. Основное отличие объектов OLE 2.0 от обычных объектов OLE состоит в том, что они доступны только программно, они создаются и используются при помощи программного кода и, следовательно, в принципе временны. Они не могут быть внедрены или связаны. Они могут существовать только в течение времени выполнения использующей их программы. Работа с файлами с использованием компонента TOleContainerПростейшим примером, позволяющим использовать OLE в C++Builder является контейнер OLE OleContainer(вкладка System) - компонент, позволяющий использовать механизмы внедренния и связывание. OLE-контейнер инкапсулирует все интерфейсы, необходимые для создания клиента OLE документов. Поместив его на форму форму и, в обработчике события нажатия кнопки, написав код: void __fastcall TForm1::Button1Click(TObject *Sender) { if(OleContainer1->InsertObjectDialog()) { OleContainer1->DoVerb(ovShow); } } После запуска приложения и нажатия кнопки появляется диалоговое окно - "Вставка объекта". Выбрав в окошечке "Тип объекта" - "Документ Microsoft Word" (аналогично как и любого другого) и выбрав опцию "Создать из файла" после нажатия кнопочки "OK" в наше приложение внедряется Word, в котором открывается выбранный документ. Маленькое отличие внедренного приложения (не важно Word, Excel, WordPad, PaintBrush... )- в нем нет некоторых функций,и хотя документ межет редактироваться, но, например, он не может быть сохранен стандартными для приложения методами. Для сохранения необходимо написать примерно такой код: void __fastcall TForm1::Button2Click(TObject *Sender) { if(SaveDialog1->Execute ()) OleContainer1->SaveToFile(SaveDialog1->FileName)); } Для закрытия контейнера необходимо при закрытии приложения предусмотреть код: OleContainer1->DestroyObject(); Особенность - вместо меню Файл, имеющегося в Microsoft Word, встраивается меню разрабатываемого приложения, в котором также можно предусмотреть команды открытия и закрытия файла - естественно в приложении должно быть это меню создано обычным для создания приложений образом. Диалог позволяет выбирать доступный тип документа. Однако, если тип нового объекта известен, можно внедрять его программно. OleContainer1->CreateObject("Word.Document",false); //или OleContainer1->CreateObject ("Excel.Sheet",false); ... OleContainer1->DoVerb (ovShow); Кроме того, если выберать при создании документа опцию "Создать из файла" и в нем с помощью кнопки "Обзор" выбрать необходимый файл, а в опции "Связь" поставить галочку, то в приложении создаается внедренный и связанный объект OLE, который при его сохранении можно будет открыть из приложения, но открыть можно только как объект OLE - открытие его из родного редактора становится невозможным. Однако все изменения в исходном файле отражаются в приложении и наоборот. Кроме того, "родная" программа редактора открывается в полноценном приложении. Можно открыть документ и программно: void __fastcall TForm1::Button3Click(TObject *Sender) { if(OpenDialog1->Execute ()) { OleContainer1->CreateObjectFromFile(OpenDialog1->FileName,false); OleContainer1->Repaint(); } } Метод GreateLinkToFile позволяет создать внедренный и связанный объект: void CreateLinkToFile(OpenDialog1->FileName,false); Связанный объект можно сохранить и как обычный документ: OleContainer1->SaveAsDocument(SaveDialog1->FileName,false); Работа с любым нетекстовым файлом подобного типа полностью аналогична работе с документами формата .doc. Доступ к файлам с использованием контроллеров и серверов автоматизацииЭтот раздел оказался настолько большим, что его пришлось определить в отдельный раздел - Контроллеры и серверы автоматизации Word и Excel. Кроме того принципы работы и доступа к файлам .doc и .xls могут быть использованы и при доступе к файлам других приложений. Работа с файлами через компоненты вкладки OffiseЭтот пункт рассмотрим напримере доступа к файлам Word. Из вкладке Office паместим на форму вновь создаваемого приложения коипоненты TWordApplicaton и TWordDocument. Код работы с файлом будем писать в любом обработчике, например, события нажатия кнопки компонента TButton. Целью поставим создание (открытие) файла в приложении Word, внесение в документ некоторой информации и сохранение файла. Все пояснения к данному примеру будут описаны в качестве пояснений к коду. Доступ к файлам при применении компонент вкладки Office основан на механизмах, описанных в предыдущем параграфе и используют механизмы OLE - компоненты лишь немного упрощают работу. void __fastcall TForm1::Button1Click(TObject *Sender) { //Переменные лучше объявить быть как TVariant TVariant tvTemplate,tvNewTemplate,tvPath,tvParam1, tvParam2,tvParam3,tvParam4,tvParam5; //Место шаблона документов Word tvTemplate= "C:\\WINDOWS\\Application Data\\Microsoft\\Шаблоны\\Normal.dot"; tvNewTemplate=false; tvPath=StringToOleStr("c:\\a.doc"); tvParam1 =(TVariant)True; tvParam2 =(TVariant)False; tvParam3 =(TVariant)1; tvParam4 =(TVariant)0; tvParam5 =(TVariant)""; //Двойной перехват исключений для разделения причин их вызвавших try { try { //Проверяем наличие Word WordApplication1>Connect(); WordApplication1>Application>Visible=true; } catch(Exception &exception) { MessageDlg("Word скорее всего не установлен", mtError,TMsgDlgButtons() << mbYes,0); Abort; } // Создаем или чтение рабочего документа //1. Можно указать шаблон документа по умолчанию WordApplication1>Documents>Add(EmptyParam,tvNewTemplate); //2. Тоже можно указать шаблон непосредственно WordApplication1>Documents>Add(tvTemplate,tvNewTemplate); //3. Или с использованием всех параметров - интересны параметры // тип документы - 0 = Word и четвертый - видимомсть документа - false // Последний параметр (Word_2k::WordDocument** prop) - идентификатор // документа можно опустить по умолчанию WordApplication1>Documents>Add(tvTemplate,tvNewTemplate, tvParam3,tvParam1); // Функция не обязательна если указан полный путь к файлу // WordApplication1>ChangeFileOpenDirectory((wchar_t*)"C:\\"); //Сделать доступным интерфейс WordApplication1>GetDefaultInterface()>Visible = true; //4. Можно просто открыть документ так - все параметры по умолчанию WordApplication1>Documents>Open(&tvPath); //5. Можно открыть документ с указанием всех параметров - //наиболее интересные закоментированы WordApplication1>get_Documents()>Open(&tvPath,tvParam2, tvParam2/*ReadOnly*/,tvParam1,tvParam5/*PasswordDocument*/, tvParam5,tvParam2,tvParam5/*WritePasswordDocument*/,tvParam5, (TVariant)wdOpenFormatDocument/*Format*/,tvParam1/*Visible*/); //6. Или воспользоваться функцией OpenOld WordApplication1>get_Documents()>OpenOld(&tvPath,tvParam2, tvParam2/*ReadOnly*/,tvParam1,tvParam5/*PasswordDocument*/, tvParam5,tvParam2,tvParam5/*WritePasswordDocument*/,tvParam5, (TVariant)wdOpenFormatAuto/*Format*/); // Открыть документ можно в следующих форматах - файл word_2k.h /* typedef enum WdOpenFormat { wdOpenFormatAuto = 0, wdOpenFormatDocument = 1, wdOpenFormatTemplate = 2, wdOpenFormatRTF = 3, wdOpenFormatText = 4, wdOpenFormatUnicodeText = 5, wdOpenFormatEncodedText = 5, wdOpenFormatAllWord = 6, wdOpenFormatWebPages = 7 } WdOpenFormat; */ //Имя документа WordApplication1>set_Caption(StringToOleStr("Word документ")); //Подключение WordDocument к WordApplication WordDocument1>ConnectTo(WordApplication1>Documents>Item(tvParam3)); //Отключение/Включение проверки правописаня WordApplication1>Options>CheckSpellingAsYouType=false; WordApplication1>Options>CheckGrammarAsYouType=false; //Выбор параграфа SelectionPtr Sel = WordApplication1>get_Selection(); //Отступ Sel>Paragraphs>set_LeftIndent(20); for(int i = 0; i < 10; i++) { //Следующий параграф Sel>TypeParagraph(); //Выводим текст Sel>TypeText(StringToOleStr(IntToStr(i)+" - строка")); } //1. Сохраняем и закрываем. WordDocument1->SaveAs(tvPath); //2. Можно тспользовать и другие параметры из которых // интересен пожалуй только формат сохранения FileFormat WordDocument1->SaveAs( tvPath,(TVariant)wdFormatDocument/*FileFormat*/, tvParam2,tvParam5,tvParam1,tvParam5,tvParam2,tvParam1,tvParam1, tvParam2,tvParam2); WordApplication1->Disconnect(); /* typedef enum WdSaveFormat { wdFormatDocument = 0, wdFormatTemplate = 1, wdFormatText = 2, wdFormatTextLineBreaks = 3, wdFormatDOSText = 4, wdFormatDOSTextLineBreaks = 5, wdFormatRTF = 6, wdFormatUnicodeText = 7, wdFormatEncodedText = 7, wdFormatHTML = 8 } WdSaveFormat; */ } catch (Exception &exception) { Application>ShowException(&exception); WordApplication1>Disconnect(); } } Тема "Работа с файлами через компоненты вкладки Office" столь же
интересна и обширна как и тема "Работа с файлами с использованием
контроллеров и серверов автоматизации" и ы дальнейшем планируеися
посвятить ей отдельный раздел (ближе к лету).
|