Работаем с Word
    , COM
  ![]()  | 
Наши проекты:
 Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту  | 
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS | 
| [216.73.216.5] | 
 
 | 
		
  | 
    Работаем с Word
    , COM
  | 
         
         
         
          
           Сообщ.
           #1
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
        ![]() ![]() Если у Вас нет на панели инструментов закладки  Servers  - то можно  проделать следующее : Создаем новый пакет с использованием библиотеки типов. Выберите Project | Import  Type library.  Из списка зарегистрированных серверов выберите библиотеку типов Word (Microsoft  Word 9.0 Object Library (на моем компьютере установлен Microsoft Office 2000,  поэтому в списке присутствует 9.0, для предыдущих версий Office, номера версий  будут меньше)).  Укажите имя закладки палитры компонентов (Pallete Page), куда будут установлены  новые классы - TWordGlobal, TWordApplication, TWordDocument, TWordFont,  TWordParagraphFormat, TWordLetterContent. Выберите закладку Servers.  Установите флажок General Component Wraper для генерации компонентов на основе  библиотеки типов и размещения ее на палитре компонент, а затем нажмите кнопку  Install.  Установите сервер на палитру компонент.  Если закладка -  Servers есть то выше перечисленные действия делать не надо. Фундаментальным объектом любого приложения является Application. Давайте получим  к нему доступ .  ·  создаем новый проект;  ·  на главную форму выкладываем компонент WordApplication с закладки  Servers;  ·  устанавливаем свойства компонента AutoConnect и AutoQuit в True;  ·  запускаем приложение на выполнение.  Не забудьте добавить в #include <COMOBJ.hpp>.  #pragma link "Word_2K_SRVR"- для 2000  #pragma link "Word_97_SRVR"- для 97  Если у вас обе строки добавлены то не избежать ошибок Ambiguity between  В большинстве случаев нам надо подключиться  к уже существующему интерфейсу, а  не создать его заново. Также это может быть необходимо, когда контроллер должен  отслеживать события, происходящие в COM сервере. Рассмотрим следующий пример:  ·  создаем новое приложение;  ·  помещаем на форму компоненты WordApplication и WordDocument;  ·  устанавливаем в True свойства AutoConnect и AutoQuit компонента  WordApplication;  ·  устанавливаем в значение ckAttachToInterface свойство ConnectKind для  объекта WordDocument;  ·  для события onDokumentChange прописываем такой код:  ·      //производим подключение к текущему документу ·      WordDocument1->ConnectTo( WordApplication1.ActiveDocument); ·      //Контроллер добавляет новую строку в текущий документ ·      WordDocument1->Range->InsertAfter(#13+'Переход к документу'+#13+ ·         WordApplication1->ActiveDocument->Get_FullName+' произведен :'+ ·         DateTimeToStr(Now)); для события OnFormCreate прописываем следующее:  ·      WordApplication1->Visible=true; После запуска приложения будет автоматически загружен Microsoft Word, создайте в  нем несколько новых документов и "попереключайтесь" между ними. Вы увидите, что  контроллер автоматизации добавляет новые строки в текущий активный документ.  Точно так же можно управлять и сервером ExcelApplication. При создании новой  рабочей книги на сервере, в контроллере будет проинициализировано событие  onNewWorkBook, которое можно обработать аналогично примеру с Word.  Теперь рассмотрим еще один пример.  Пусть существует необходимость формировать некий отчет в виде документа  Microsoft Word, для чего нами используется файл-шаблон (к примеру, с именем  test.doc). Поля, которые должны быть заменены, помечены символом «~» или другим  сиволом который не встречается в отчете .Необходимо получить данные, а затем  заменить метки реальными данными, после чего сформированный документ должен быть  отправлен на печать, сохранен.   В test.doc имеется шапка таблицы и нам необходимо заполнить таблицу данными из  запроса (может бать любой контейнер с данными). Создадим новый проект и поместим на форму компоненты WordApplication(WApp),  WordDocument(WDoc) и кнопку (TButton). В качестве обработчика события нажатия на  кнопку укажем следующий код:   //Следующие переменные понадобятся нам для выполнения методов сервера  OleVariant FileName;  OleVariant oldStr,newStr;  OleVariant EmptyPar=False;  OleVariant Yes=True;  FileName=GetCurrentDir()+"\\test.doc";   //Открываем шаблон документа  WApp->Visible=false; // что бы не моргал при заполнении данными но можно  поставить в true                       // тогда весь процесс заполнения , замены будет на экране  WApp->Caption = StringToOleStr("Отчет");//Задание заголовка для окна Word  WApp->Documents->Add(FileName,EmptyParam);  WDoc->ConnectTo(WApp->ActiveDocument);  //Связываем компонент с существующим интерфейсом /*  WDoc->ConnectTo(WordApplication1->Documents->Item(ItemIndex));  Если есть несколько открытых документов. */  //Находим в документе метки и производим их замены  oldStr=AnsiString("~1");  newStr=AnsiString("Метка 1");  WDoc->Range(EmptyParam,EmptyParam)->Find->Execute(oldStr,  EmptyParam,EmptyParam,EmptyParam,EmptyParam,  EmptyParam,EmptyParam,EmptyParam,EmptyParam,  newStr,Yes); TablePtr MyTable=WApp->ActiveDocument->Tables->Item(1) ; // получаем указатель на нашу таблицу RangePtr MyRange =MyTable->Range ;   String s;   TADOQuery * QF; Создадим запрос к примеру «select * from table1» как создавать запросы и  работать с ними сдесь рассматривать не будем. В принципе это могут быть и таблицы (TTable)  String pole;  int Current=0; //счетчик  QF->First();  long j; while (!QF->Eof)  {   MyTable->Rows->Add(); // вставляем новую строку в таблицу   int fild= QF->Fields->Count;   String nPole;   for (int p=1 ;p<fild-3 ;p++) // цикл по полям   {   MyTable->Borders->set_OutsideLineWidth(wdLineWidth300pt);   MyTable->Borders->set_InsideLineStyle(wdLineStyleThinThickSmallGap);   nPole=Table1->Fields->Fields[j]->AsString;//Можно делать проверку на тип и  формат данных    MyTable->Cell(1,p)->Range->InsertAfter(StringToOleStr(nPole));   }   QF->Next();  } FileName= GetCurrentDir()+"\\newtest.doc";  Сохраняем в формате Word 6.0/95 (*.doc) OleVariant EmptyS=StringToOleStr(""); WDoc->SaveAs(FileName,(OleVariant)104,EmptyParam,           EmptyS,Yes,EmptyS,           EmptyParam,EmptyParam,           EmptyParam,EmptyParam,EmptyParam); WDoc->Close(EmptyParam,EmptyParam,EmptyParam);  WApp->Visible=1;  WApp->Disconnect(); Некоторые полезные замечания :    MyTable->Cell(j,1)->VerticalAlignment=wdCellAlignVerticalCenter;    MyTable->Cell(j,1)->Range->Paragraphs->Alignment=wdAlignParagraphCenter; //Создание таблицы WordApplication1->Selection->Font->Bold = false; WordApplication1->ActiveDocument->Tables->Add(WordApplication1->Selection->Range , MainFrm->Query???->RecordCount + 9, 6); Этот код, он вставляет данные после таблицы //   String stn = "\n"; //   String koltnS;       // строка для форматирования общей суммы в ??? //   koltnS = koltnS.FormatFloat("0.00000", QF->?????->Value); //   stn = stn + "                                Сумма реализации:  "+ koltnS; //   WDoc->Range(EmptyParam,EmptyParam)->InsertAfter(StringToOleStr(stn)); //   WordFont1->ConnectTo(WordDocument1->Sentences->get_Last()->get_Font()); //   WordFont1->Size = 12; //   WordFont1->Bold = true; //   WordFont1->Color = wdColorIndigo; // Если понадобиться код объединения ячеек  WordApplication1->Selection->Tables->Item(1)->Cell(4,1)->  Merge(WordApplication1->Selection->Tables->Item(1)->Cell(4,6)); Еще вариант сохранения док-та    stn = MainFrm->DBEdit5->Text;    int n = stn.Length();    if (n == 1)   stn = "0" + stn;    stn = "?????" + stn + MainFrm->Edit1->Text + ".doc";    //Сохранение документа    WordDocument1->SaveAs(&TVariant(WideString(stn)), &TVariant(wdFormatDocument));  | 
    
| 
         
         
         
          
           Сообщ.
           #2
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          У меня не получается выполнить обращение к строке таблицы Word 
        
      (RowPtr)(Table->Rows->Item(1))->Select() Что я делаю не так? С объектами CellPtr никаких проблем.  | 
    
| 
         
         
         
          
           Сообщ.
           #3
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Table->Rows->Item(1)->Select()? 
        
      Цитата    Dimas51, 13.07.04, 12:19 (RowPtr*)(Table->Rows->Item(1))->Select()  | 
    
| 
         
         
         
          
           Сообщ.
           #4
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          [У меня не получается выполнить обращение к строке таблицы Word 
        
      (RowPtr)(Table->Rows->Item(1))->Select() Что я делаю не так? А как добавить строку в конец Таблицы? В Worde новая строка Tabом создается, а если в проге суешь "\t" - не хочет  | 
    
| 
         
         
         
          
           Сообщ.
           #5
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата  Леопольд, 17.07.04, 05:24 а если в проге суешь "\t" - не хочет "\n"  | 
    
| 
         
         
         
          
           Сообщ.
           #6
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата  Не забудьте добавить в #include <COMOBJ.hpp>. #pragma link "Word_2K_SRVR"- для 2000 #pragma link "Word_97_SRVR"- для 97 А для Office XP?  | 
    
| 
         
         
         
          
           Сообщ.
           #7
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 7.10.04, 13:38 А для Office XP?  А это без разницы, главное версия Word'а  | 
    
| 
         
         
         
          
           Сообщ.
           #8
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          А если ворд 2002? Кстати, эта штука нужна только для компиляции. Так? У клиента будет работать независимо от указанной строки. Да?   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #9
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 7.10.04, 14:58 Не факт. У разных версий Word'а разная функциональность.  У клиента будет работать независимо от указанной строки. Да?  | 
    
| 
         
         
         
          
           Сообщ.
           #10
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          WordDocument1->ConnectTo( WordApplication1.ActiveDocument); 
        
      Наверное должно быть так: WordDocument1->ConnectTo( WordApplication1->ActiveDocument); Да? А вот тут проблемы: На строчку: WordDocument1->Range->InsertAfter Компилятор ругается: [C++ Error] untMain.cpp(26): E2288 Pointer to structure required on left side of -> or ->* Требует что-то поставить после Range. Что делать? И есть ли дока на эти компоненты? WordApplication, WordDocument? У меня в палитре есть ещё и WordGlobal. Это что и зачем? И ещё много разных компонент. Хотел бы доку почитать, если где-то есть. Дайте, плиз, хотя бы линк  | 
    
| 
         
         
         
          
           Сообщ.
           #11
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          WordDocument1 это и есть WDoc.  
        
      Цитата Bas, 14.04.04, 17:07 WDoc->ConnectTo(WApp->ActiveDocument);  Цитата Bas, 14.04.04, 17:07 WDoc->Range(EmptyParam,EmptyParam)->; Цитата Bas, 14.04.04, 17:07 //  WDoc->Range(EmptyParam,EmptyParam)->InsertAfter(StringToOleStr(stn)); Первое сообщение читали?  | 
    
| 
         
         
         
          
           Сообщ.
           #12
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          WordDocument1->Range(EmptyPar,EmptyPar)->InsertAfter("Test"); 
        
      [C++ Error] untMain.cpp(30): E2034 Cannot convert 'char *' to 'wchar_t *' ??? Bas, поделись плиз, источниками инфы, или хотя бы ключевыми словами, по которым искать нужно  | 
    
| 
         
         
         
          
           Сообщ.
           #13
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          L"Test"   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #14
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 7.10.04, 17:04 WordDocument1->Range(EmptyPar,EmptyPar)->InsertAfter("Test"); ![]() ![]() WordDocument1->Range(EmptyPar,EmptyPar)->InsertAfter(StringToOleStr("Test")); Но всеравно главная инфа в хелпах Word,Excel.  | 
    
| 
         
         
         
          
           Сообщ.
           #15
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Bas, Искал, искал... кучу линков топиков на тему нашёл, а вот твоих ссылок и архива - не нашёл... 
        
      Сейчас у меня проблема, что при компиляции WordApplication1->Visible получаю сообщение - метод недоступен... ![]() А в Ворде - хэлпа нет на такие штуки... ?  | 
    
| 
         
         
         
          
           Сообщ.
           #16
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Скорее всего требуется: 
        
      WordApplication1->Visible[0]  | 
    
| 
         
         
         
          
           Сообщ.
           #17
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 7.10.04, 19:11 WordApplication1->Visible WordApplication1->Visible=true; Да у меня было чтото похоже когда переустановил систему и установил BCB - день мучался (ведь знал что работало). Но вспомнил что Update'ы не установил. После установки все пошло как надо. Автоматизация приложений Microsoft Office в примерах  | 
    
| 
         
         
         
          
           Сообщ.
           #18
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата  Но вспомнил что Update'ы не установил. После установки все пошло как надо По тому линку, что ты привёл - нет ни одного слова об Апдэйтах или обновлениях. Где их взять? И ещё: Как можно работать с Вордом без компонент, а используя ОЛЕ технологии? Добавлено Seva, нет ![]() ![]() WordApplication1->Visible[0]=true; При компиляции выдает ошибку: Цитата    [C++ Error] untMain.cpp(35): E2015 Ambiguity between 'TOLEBOOL::operator bool() const' and 'TOLEBOOL::operator short() const'  | 
    
| 
         
         
         
          
           Сообщ.
           #19
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 8.10.04, 12:44 Так же, как и с другими приложениями. Как можно работать с Вордом без компонент, а используя ОЛЕ технологии? ![]() ![]() ![]() Variant vApp; try {    vApp = Variant::GetActiveObject("Word.Application"); } catch(EOleSysError &ex) {    try{       vApp = Variant::CreateObject("Word.Application");    } catch(EOleSysError &ex) {       // не удалось запустить сервер    } catch(...) {       // неизвестная ошибка    } } catch(...) {    // не удалось подключиться к серверу } ![]() ![]() Variant vDoc = vApp.OlePropertyGet("Documents").OleFunction("Open",имя_файла);   Добавлено P.S. Хотя компоненты работают с соответствующим сервером тоже через OLE   	  | 
    
| 
         
         
         
          
           Сообщ.
           #20
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Выписка  
        
      ![]() ![]() Аббревиатура OLE обозначает Objects Linked and Embedded (Присоединенные И  Встроенные Объекты - ПИВО  ;) ). Данные, разделяемые между приложениями  называются OLE объектом. Приложение, которое может содержать OLE объекты,  называют OLE контейнером (OLE Container). Приложение, данные из которого  можно включить в OLE контейнер в виде OLE объекта, называют OLE сервером.  Например, MicroSoft Word может включать в документ графические объекты,  аудио- и видеоклипы и множество других объектов (такой документ иногда  называют составным документом - compound document).  Как следует из названия, OLE объекты можно либо присоединить к OLE  контейнеру, либо включить в него. В первом случае данные будут храниться в  файле на диске, любое приложение будет иметь доступ к этим данным и сможет  вносить изменения. Во втором случае данные включаются в OLE контейнер и  только он сможет просматривать и модифицировать эти данные.  OLE является дальнейшим развитием идеи разделяемых между приложениями  данных. Если с помощью DDE можно было работать с текстом, то OLE позволяет  легко встроить в приложение обработку любых типов данных. Как и в случае с  DDE, для правильной работы приложения-клиента (OLE контейнера) требуется  наличие приложения OLE сервера. Каждый раз, когда в программе-клиенте  пользователь обращается к OLE объекту с целью просмотра или редактирования  данных (обычно двойной щелчок мышкой на объекте), запускается приложение- сервер, в котором и происходит работа с данными.  В природе существует несколько видов OLE, отличающихся по способу  активации OLE сервера. OLE версии 1 запускает сервер в отдельном окне. OLE  2 реализует то, что называется in-place activation and editing.  Развитие идеи OLE привело к появлению OLE automation - приложение-клиент  может выполнить часть кода сервера. Тип OLE объекта, помещенного в  программу-клиент, определяется тем, какую версию OLE поддерживает сервер.   | 
    
| 
         
         
         
          
           Сообщ.
           #21
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          trainer, Спасибо! 
        
      Bas, Это ты к чему?  | 
    
| 
         
         
         
          
           Сообщ.
           #22
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 8.10.04, 16:43 Bas, Это ты к чему?  Для общего развития.  | 
    
| 
         
         
         
          
           Сообщ.
           #23
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Bas, та мне бы чего-то попрактичнее, тот код, который Тренер дал - тоже сбоит... Ну просто 3.14здец какой-то. 
        
      Может чего-то где-то в настройках.... Может кинешь маленький конкретный пример? seredaom@ukrpost.net.  | 
    
| 
         
         
         
          
           Сообщ.
           #24
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda, 8.10.04, 18:03 В чем это проявляется и покажи свой исходник.  который Тренер дал - тоже сбоит  | 
    
| 
         
         
         
          
           Сообщ.
           #25
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Исходник в студию или в приват.   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #26
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Budda,8.10.04, 11:44 Seva, нет ![]() ![]() WordApplication1->Visible[0]=true; При компиляции выдает ошибку: Цитата  [C++ Error] untMain.cpp(35): E2015 Ambiguity between 'TOLEBOOL::operator bool() const' and 'TOLEBOOL::operator short() const' Ну подправь соответствующим образом. Хочет TOLEBOOL? Попробуй так: ![]() ![]() WordApplication1->Visible[0]=TOLEBOOL(true);  | 
    
| 
         
         
         
          
           Сообщ.
           #27
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Подскажите, пожалуйста, где скачать компоненты для работы с Office 2007.   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #28
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата dallas0713 @  Подскажите, пожалуйста, где скачать компоненты для работы с Office 2007.  Читай эту тему с начала.  | 
    
| 
         
         
         
          
           Сообщ.
           #29
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Люди, подскажите пожалуйста, почему происходит следующее: при запуске программы в среде C++ Builder 6, она работает нормально, но когда запускаю экзешник вне среды, работает не совсем так как надо ??? 
        
      Программа должна выполнять следующие действия: 1. Открыть файл *.doc, в котором есть формулы. 2. Сохранить во временный файл, но уже с расширением *.docx (Open XML Format) 3. Извлечь из временного файла формулы в виде картинок. В среде выполняется всё норм. А "автономно" просит сохранить файл. Вот код: ![]() ![]() //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "Word_2K_SRVR" #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner)         : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { AnsiString fname;         OpenDialog1->Execute();         fname=OpenDialog1->FileName;         if (fname!="")         {         WordApplication1->Connect();         WordApplication1->set_Visible(false);         WordApplication1->GetDefaultInterface()->Visible = false;         WordApplication1->set_DisplayAlerts(false);         WordApplication1->Documents->Open(TVariant(fname));         WordApplication1->ActiveDocument->Select();         WordApplication1->Selection->Copy();         WordApplication1->Documents->Add(EmptyParam, EmptyParam);         WordDocument1->ConnectTo(WordApplication1->ActiveDocument);         WordDocument1->Activate();         WordApplication1->Selection->Paste();         WordDocument1->SaveAs(TVariant("c:\\~temp.docx"));         WordDocument1->Close(TVariant(false));         WordApplication1->Quit(TVariant(false));         WordApplication1->Disconnect();         ZipForge1->FileName="c:\\~temp.docx";         ZipForge1->OpenArchive(fmOpenRead);         ZipForge1->ExtractFiles(L"*.wmf");         ZipForge1->CloseArchive();         DeleteFileA("c:\\~temp.docx");         } } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { ShellExecute(NULL,"open","word\\media", NULL, NULL, SW_SHOWNORMAL); } //--------------------------------------------------------------------------- Заранеее благодарен !     | 
    
| 
         
         
         
          
           Сообщ.
           #30
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          При каком действии просит? Покажи скриншот диалога.   
        
       | 
    
| 
         
         
         
          
           Сообщ.
           #31
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          На будущее: 
        
      ![]() ![]() void __fastcall TForm1::Button1Click(TObject *Sender) {   if (!OpenDialog1->Execute())     return;   //-------------------------------------   AnsiString fname = OpenDialog1->FileName;   WordApplication1->Connect();   // и всё остальное }  | 
    
| 
         
         
         
          
           Сообщ.
           #32
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          Выяснил почему в среде разработки было норм, а сам экзешник не пахал... 
        
      У меня стоит на компе: Windows 7 Pro x86, MS Office 2007, BCB 6. И я впомнил, что Борланд, я ставил в режиме совместимости с WinXP SP3, тогда работало. Потому попробывал совместить и сам экзешник... о, чудо, заработало. Думаю на WinXP будет работать. Да, в коде нужно исправить WordApplication1->set_DisplayAlerts(wdAlertsNone); но это было не существенно. Изените, пожалуйста за беспокойство!!! Спасибо   !!! Добавлено Цитата #SI# @  На будущее: ![]() ![]() void __fastcall TForm1::Button1Click(TObject *Sender) {   if (!OpenDialog1->Execute())     return;   //-------------------------------------   AnsiString fname = OpenDialog1->FileName;   WordApplication1->Connect();   // и всё остальное } Спасибо, эту проверку завтыкал...     |