Delphi to Word (оптимизация ?)
От: peter_login Россия  
Дата: 16.08.02 07:51
Оценка:
Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.
Использую конструкцию типа:

MSWORD.ActiveDocument.Tables(1).Cell(1,1).Range.InsertAfter('текст')




MSWORD — созданный COM объект "WordApplication".
Может быть знаете конструции более эфективные?
Re: Delphi to Word (оптимизация ?)
От: Whisperer  
Дата: 16.08.02 11:26
Оценка:
Здравствуйте peter_login, Вы писали:

PL>Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.

PL>Использую конструкцию типа:

PL>
PL>MSWORD.ActiveDocument.Tables(1).Cell(1,1).Range.InsertAfter('текст')
PL>

PL>
PL>

PL>MSWORD — созданный COM объект "WordApplication".

PL>Может быть знаете конструции более эфективные?

Может стоит написать на VBA процедуру которая будет из например массива который ты ей передашь и формировать таблицу — а процедуру добавляй уже когда объект word — a создашь. Я думаю быстрее получится — но реализацию неспрашивай — я тебе только идею подкинул.
Re: Delphi to Word (оптимизация ?)
От: Аноним  
Дата: 16.08.02 12:00
Оценка:
Здравствуйте peter_login, Вы писали:

PL>Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.

PL>Использую конструкцию типа:

PL>
PL>MSWORD.ActiveDocument.Tables(1).Cell(1,1).Range.InsertAfter('текст')
PL>

PL>
PL>

PL>MSWORD — созданный COM объект "WordApplication".

PL>Может быть знаете конструции более эфективные? :???:

Вот один приемчик. Создать длиииииннннууую строку, содержащую все ячейки твоей таблицы с первой по последнюю. Разделителем между ячейками нужно использовать что-то, что не попадется в содержимом ячеек (например, символ табуляции или '|').
Пример для таблицы 3 строки * 2 колонки:

AnsiString FutureTable = "строка1колонка1|строка1колонка2|строка2колонка1|строка2колонка2|строка3колонка1|строка3колонка2".

Далее что-нибудь вроде

WordDoc->Paragraphs->Last->Range->InsertAfter(StringToOleStr(FutureTable));

и тут же

WordDoc->Paragraphs->Last->Range->ConvertToTable(
Variant(WideString("|")),
Variant(3),
Variant(2),
Variant(28.35 * 2),
Variant(Word_2k::wdTableFormatGrid1));

Параметры см. в справочной система Word.

Синтаксис сишный, — но все равно понятно.

Мгновенно тоже не будет, но быстрее в РАЗЫ.

Надеюсь, что поможет.

Незарегистрированный Igorhere .
:shuffle:
Re[2]: Delphi to Word (оптимизация ?)
От: Аноним  
Дата: 16.08.02 12:44
Оценка:
Здравствуйте Аноним,

Спасибо за совет, но скорее всего такой подход очень сложен,
так как таблица не однородная есть объединения и разделения
ячеек по ходу формирования последней.
Может будут еще предложения.

:shuffle:
Re: Delphi to Word (оптимизация ?)
От: achp  
Дата: 16.08.02 12:50
Оценка: 21 (1)
Здравствуйте peter_login, Вы писали:

PL>Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.


Если речь о Ворде-2000, то можно отказаться от автоматизации.

Для него можно сгенерировать HTML, это довольно просто и работает быстро.

Для того, чтобы поглядеть, как сей HTML выглядит, в Ворде открой документ и нажми Alt+Shift+F11. Формат HTML в Ворде-2000 сохраняет практически все атрибуты оформления (в отличие от Ворда-97, где используется только HTML-совместимое подмножество).
Re[2]: Delphi to Word (оптимизация ?)
От: peter_login Россия  
Дата: 16.08.02 13:15
Оценка:
Здравствуйте achp, Вы писали:

A>Здравствуйте peter_login, Вы писали:


PL>>Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.


A>Если речь о Ворде-2000, то можно отказаться от автоматизации.


A>Для него можно сгенерировать HTML, это довольно просто и работает быстро.


A>Для того, чтобы поглядеть, как сей HTML выглядит, в Ворде открой документ и нажми Alt+Shift+F11. Формат HTML в Ворде-2000 сохраняет практически все атрибуты оформления (в отличие от Ворда-97, где используется только HTML-совместимое подмножество).


К сожелению гарантии, что у клиента будет 2000-й нет гарантии. А заставлять его переходить несолидно. :crash:
Re[3]: Быстрый экспорт в Word
От: Anatolix Россия https://www.linkedin.com/in/anatolix/
Дата: 17.08.02 07:55
Оценка: 16 (2)
Небольшой измышлизм на тему subj + идея решения.

Меня тоже всегда интересовал вопрос почему экспорт в Word такой медленный. Многие говорили что это из-за IDispatch, многие из-за общего торможения Outprocess COM серверов.Но тем не менее другие программы здесь работают идеально, только Word & Excel тормозит.

Как то очень давно я услышал от одного человека такое мнение: "Зачем этот COM вообще нужен, ведь DDE работает быстрее, весь эффективный экспорт в офис должен быть на основе DDE, именно из-за этого его до сих пор поддерживают Word и Excel".

У меня этот тезис вызвал сильные сомнения, но я решил его проверить. Получилось естественно абсолютно такая же производительность. Но при этом я получил любопытный побочный эффект который и побудил меня написать данное сообщение.

При работе с DDE ты просто передаешь Word строку c синтаксисом WordBasic, а он ее выполняет. В принципе это логично сделать похожий синтаксис, но если например передать неправильную строку то будет интересная бага. Отладчик Word остановится внутри макроса состоящей из единственной строки — той которую ты передал. Т.е. получается следующее что ты передаешь строку по DDE, word ее парсит и выполняет, т.е. Parser включается при посылке каждой команды, тогда как в макросе Word парсер разбирает весь макрос в самом начале, естественно Word Basic работает быстрее.

И вот здесь у меня появилось подозрение: скорость экспорта на основе DDE была абсолютно такой же как и на основе COM. Сам макрос в списке не появляется, поэтому я не смог поймать Word за руку, но похоже при вызове по COM word просто генерит макрос, потом парсит его и выполняет.

Решение естественно кривое, но вспомните когда проявился Word. Если вы сейчас решите сделать что-то похожее, то вы сначала реализуете COM сервер, а потом на его основе сделаете скриптовый язык и все будет быстро и клево. Но Word старше технологий COM и DDE на несколько лет, поэтому там COM сервер врезался в готовое приложение. Притом
Word написан навярняка на голом C(т.к. он опять же старше C++) и в нем наверняка не применялся idl(по той же причине) который сам генерит IDispach, т.е. IDispath там реализован руками. Именно этим объясняется различие возможностей у IDispatch и библиотеки типов Word.

Вывод: для того чтобы быстро работать с Word надо поменьше вызывать его через COM. На прошлой работе у ныс было замечательное и быстрое решение когда на Word был написан макрос который делал обратный вызов к нашей программе и тащил данные из нее. Все было очень быстро. К сожалению данный способ вообщем-то мертв т.к. есть много
побочных эффектов.

Мне кажется что самый эффективный метод это генерация макроса Word целиком в вашей программе, а потом передача его Word-у. Большие табличные данные можно закатывать в Variant-ы или в ADO Recordset-ы.

Сейчас я вообще не занимаюсь этой темой, по причине того что больше не программирую на Delphi и BCB, и не занимаюсь экспортом в Word, но буду рад продолжить обсуждение этой темы.
Любая проблема дизайна может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев
Re: Delphi to Word (оптимизация ?)
От: Аноним  
Дата: 19.08.02 08:17
Оценка:
Здравствуйте peter_login, Вы писали:

PL>Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.

PL>Использую конструкцию типа:

PL>
PL>MSWORD.ActiveDocument.Tables(1).Cell(1,1).Range.InsertAfter('текст')
PL>

PL>
PL>

PL>MSWORD — созданный COM объект "WordApplication".

PL>Может быть знаете конструции более эфективные? :???:


В свое время столкнулся с подобной траблой при экпорте данных в Excel.

Решение оказалось весьма неожиданным: формируется, что бы вы думали?, Clipboard строка и потом методом Insert вставляется в Excel... простенько и со вкусом... производительность — на два порядка выше... строки отделяются chr(13){Enter}, колонки — chr(10){Tab}...
может и здесь прокатит... пробуйте! :)
Re: Delphi to Word (оптимизация ?)
От: Romkin  
Дата: 19.08.02 10:32
Оценка:
Здравствуйте peter_login, Вы писали:

PL>Как ускорить формирование отчета в Word-е, особенно вывод в ячейки таблицы.

PL>Использую конструкцию типа:

PL>
PL>MSWORD.ActiveDocument.Tables(1).Cell(1,1).Range.InsertAfter('текст')
PL>

PL>
PL>

PL>MSWORD — созданный COM объект "WordApplication".

PL>Может быть знаете конструции более эфективные?

Прежде всего можно ускорить (и значительно)
ActDoc := MSWORD.ActiveDocument; — однократно
TMPRange := ActDoc.Tables(1).Cell(1,1).Range;
TMPRange.InsertAfter('текст');
В общем, все дело в том, что при вызове строки идут запросы значений свойств, сначала Application, потом ActiveDocement и тд.
Если сделать это однократно, скорость увеличится значительно
Re[4]: Быстрый экспорт в Word
От: Whisperer  
Дата: 19.08.02 10:58
Оценка:
Здравствуйте Anatolix, Вы писали:


A>Небольшой измышлизм на тему subj + идея решения.


A>Меня тоже всегда интересовал вопрос почему экспорт в Word такой медленный. Многие говорили что это из-за IDispatch, многие из-за общего торможения Outprocess COM серверов.Но тем не менее другие программы здесь работают идеально, только Word & Excel тормозит.


A>Как то очень давно я услышал от одного человека такое мнение: "Зачем этот COM вообще нужен, ведь DDE работает быстрее, весь эффективный экспорт в офис должен быть на основе DDE, именно из-за этого его до сих пор поддерживают Word и Excel".


A>У меня этот тезис вызвал сильные сомнения, но я решил его проверить. Получилось естественно абсолютно такая же производительность. Но при этом я получил любопытный побочный эффект который и побудил меня написать данное сообщение.


A>При работе с DDE ты просто передаешь Word строку c синтаксисом WordBasic, а он ее выполняет. В принципе это логично сделать похожий синтаксис, но если например передать неправильную строку то будет интересная бага. Отладчик Word остановится внутри макроса состоящей из единственной строки — той которую ты передал. Т.е. получается следующее что ты передаешь строку по DDE, word ее парсит и выполняет, т.е. Parser включается при посылке каждой команды, тогда как в макросе Word парсер разбирает весь макрос в самом начале, естественно Word Basic работает быстрее.


A>И вот здесь у меня появилось подозрение: скорость экспорта на основе DDE была абсолютно такой же как и на основе COM. Сам макрос в списке не появляется, поэтому я не смог поймать Word за руку, но похоже при вызове по COM word просто генерит макрос, потом парсит его и выполняет.


A>Решение естественно кривое, но вспомните когда проявился Word. Если вы сейчас решите сделать что-то похожее, то вы сначала реализуете COM сервер, а потом на его основе сделаете скриптовый язык и все будет быстро и клево. Но Word старше технологий COM и DDE на несколько лет, поэтому там COM сервер врезался в готовое приложение. Притом

A>Word написан навярняка на голом C(т.к. он опять же старше C++) и в нем наверняка не применялся idl(по той же причине) который сам генерит IDispach, т.е. IDispath там реализован руками. Именно этим объясняется различие возможностей у IDispatch и библиотеки типов Word.

A>Вывод: для того чтобы быстро работать с Word надо поменьше вызывать его через COM. На прошлой работе у ныс было замечательное и быстрое решение когда на Word был написан макрос который делал обратный вызов к нашей программе и тащил данные из нее. Все было очень быстро. К сожалению данный способ вообщем-то мертв т.к. есть много

A>побочных эффектов.

A>Мне кажется что самый эффективный метод это генерация макроса Word целиком в вашей программе, а потом передача его Word-у. Большие табличные данные можно закатывать в Variant-ы или в ADO Recordset-ы.


A>Сейчас я вообще не занимаюсь этой темой, по причине того что больше не программирую на Delphi и BCB, и не занимаюсь экспортом в Word, но буду рад продолжить обсуждение этой темы.


Да я стобой обсалютно согласен и сразу написал как я думаю будед дыстрее —
Re[4]: Быстрый экспорт в Word
От: peter_login Россия  
Дата: 22.08.02 06:47
Оценка:
Здравствуйте Anatolix, Вы писали:


A>Небольшой измышлизм на тему subj + идея решения.


A>Меня тоже всегда интересовал вопрос почему экспорт в Word такой медленный. Многие говорили что это из-за IDispatch, многие из-за общего торможения Outprocess COM серверов.Но тем не менее другие программы здесь работают идеально, только Word & Excel тормозит.


A>Как то очень давно я услышал от одного человека такое мнение: "Зачем этот COM вообще нужен, ведь DDE работает быстрее, весь эффективный экспорт в офис должен быть на основе DDE, именно из-за этого его до сих пор поддерживают Word и Excel".


A>У меня этот тезис вызвал сильные сомнения, но я решил его проверить. Получилось естественно абсолютно такая же производительность. Но при этом я получил любопытный побочный эффект который и побудил меня написать данное сообщение.


A>При работе с DDE ты просто передаешь Word строку c синтаксисом WordBasic, а он ее выполняет. В принципе это логично сделать похожий синтаксис, но если например передать неправильную строку то будет интересная бага. Отладчик Word остановится внутри макроса состоящей из единственной строки — той которую ты передал. Т.е. получается следующее что ты передаешь строку по DDE, word ее парсит и выполняет, т.е. Parser включается при посылке каждой команды, тогда как в макросе Word парсер разбирает весь макрос в самом начале, естественно Word Basic работает быстрее.


A>И вот здесь у меня появилось подозрение: скорость экспорта на основе DDE была абсолютно такой же как и на основе COM. Сам макрос в списке не появляется, поэтому я не смог поймать Word за руку, но похоже при вызове по COM word просто генерит макрос, потом парсит его и выполняет.


A>Решение естественно кривое, но вспомните когда проявился Word. Если вы сейчас решите сделать что-то похожее, то вы сначала реализуете COM сервер, а потом на его основе сделаете скриптовый язык и все будет быстро и клево. Но Word старше технологий COM и DDE на несколько лет, поэтому там COM сервер врезался в готовое приложение. Притом

A>Word написан навярняка на голом C(т.к. он опять же старше C++) и в нем наверняка не применялся idl(по той же причине) который сам генерит IDispach, т.е. IDispath там реализован руками. Именно этим объясняется различие возможностей у IDispatch и библиотеки типов Word.

A>Вывод: для того чтобы быстро работать с Word надо поменьше вызывать его через COM. На прошлой работе у ныс было замечательное и быстрое решение когда на Word был написан макрос который делал обратный вызов к нашей программе и тащил данные из нее. Все было очень быстро. К сожалению данный способ вообщем-то мертв т.к. есть много

A>побочных эффектов.

A>Мне кажется что самый эффективный метод это генерация макроса Word целиком в вашей программе, а потом передача его Word-у. Большие табличные данные можно закатывать в Variant-ы или в ADO Recordset-ы.


A>Сейчас я вообще не занимаюсь этой темой, по причине того что больше не программирую на Delphi и BCB, и не занимаюсь экспортом в Word, но буду рад продолжить обсуждение этой темы.



Идея понятна. У меня появилась мысль сгенерить полный код скрипта VB (в виде текста), и потом из Delphi его запустить, но я не знаю, как запихнуть этот текст в скрипт Word-а для его активизации. Подскажи ... :wow: :wow:
Re[5]: Быстрый экспорт в Word
От: Anatolix Россия https://www.linkedin.com/in/anatolix/
Дата: 22.08.02 11:20
Оценка:
Здравствуйте peter_login, Вы писали:

PL>Здравствуйте Anatolix, Вы писали:


PL>Идея понятна. У меня появилась мысль сгенерить полный код скрипта VB (в виде текста), и потом из Delphi его запустить, но я не знаю, как запихнуть этот текст в скрипт Word-а для его активизации. Подскажи ...


У меня было вот так, код на C++ Builder но разберешься.
Работать надо обязательно через IDispatch т.е. с вариантами
т.к. код с использованием TypeLibrary не будет работать с
Microsoft Office Standart Edition, тогда как этот работает везде.

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmdline, int)
{
    Variant WordApplication,macro;
    AnsiString cmd=cmdline;
    bool batchmode=cmd.UpperCase().Pos("/BATCH");

        try
        {
                 Application->Initialize();
                 Application->ShowMainForm=false;
                 Application->CreateForm(__classid(THiddenForm), &HiddenForm);


                 WordApplication=CreateOleObject("Word.Application");
                 int Count=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OlePropertyGet("Count");

                 int num=0;


                 for(int i=1;i<=Count;i++)
                 {
                    AnsiString foo=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OleFunction("Item",i).OlePropertyGet("Name");
                    if (foo=="NewMacros")
                    {
                         macro=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OleFunction("Item",i);
                         num=i;
                         break;
                    }
                 }

                 if (macro.Type()!=varDispatch)
                 {
                    macro=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OleFunction("Add",vbext_ct_StdModule);
                    num=Count+1;

                    HiddenForm->Memo1->Lines->Add("");
                    HiddenForm->Memo1->Lines->Add("Sub renameself()");
                    HiddenForm->Memo1->Lines->Add(AnsiString("VBE.ActiveVBProject.VBComponents.Item(")+num+").Name = \"NewMacros\"");
                    HiddenForm->Memo1->Lines->Add("End Sub");

                    macro.OlePropertyGet("CodeModule").OleProcedure("AddFromString",StringToOleStr(HiddenForm->Memo1->Text));
                    WordApplication.OleProcedure("Run",AnsiString(macro.OlePropertyGet("CodeModule").OlePropertyGet("Name"))+".renameself");
                    if (!batchmode) ShowMessage("Взаимодействие с Word настроено.");
                  }
                  else
                  {
                    if (!batchmode) ShowMessage("Взаимодействие с Word уже настроено.");
                  }

                 macro=Unassigned;
                 WordApplication.OleProcedure("Quit");

        }
        catch (Exception &exception)
        {
             if (!batchmode) ShowMessage("Взаимодействие с Microsoft Word не может быть настроено.\r\n Скорее всего Word на вашей машине не установлен.\r\n Установите Word и запустите WordConnect.exe");
        }



Строка
int Count=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OlePropertyGet("Count");


на дельфи выглядит просто как

WordApplication.VBE.ActiveVBProject.VBComponents.Count



где WordApplication это Variant
Любая проблема дизайна может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев
Re[6]: Быстрый экспорт в Word
От: peter_login Россия  
Дата: 22.08.02 14:22
Оценка:
Здравствуйте Anatolix, Вы писали:

A>Здравствуйте peter_login, Вы писали:


PL>>Здравствуйте Anatolix, Вы писали:


PL>>Идея понятна. У меня появилась мысль сгенерить полный код скрипта VB (в виде текста), и потом из Delphi его запустить, но я не знаю, как запихнуть этот текст в скрипт Word-а для его активизации. Подскажи ... :wow: :wow:


A>У меня было вот так, код на C++ Builder но разберешься.

A>Работать надо обязательно через IDispatch т.е. с вариантами
A>т.к. код с использованием TypeLibrary не будет работать с
A>Microsoft Office Standart Edition, тогда как этот работает везде.

A>
A>WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmdline, int)
A>{
A>    Variant WordApplication,macro;
A>    AnsiString cmd=cmdline;
A>    bool batchmode=cmd.UpperCase().Pos("/BATCH");

A>        try
A>        {
A>                 Application->Initialize();
A>                 Application->ShowMainForm=false;
A>                 Application->CreateForm(__classid(THiddenForm), &HiddenForm);


A>                 WordApplication=CreateOleObject("Word.Application");
A>                 int Count=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OlePropertyGet("Count");

A>                 int num=0;


A>                 for(int i=1;i<=Count;i++)
A>                 {
A>                    AnsiString foo=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OleFunction("Item",i).OlePropertyGet("Name");
A>                    if (foo=="NewMacros")
A>                    {
A>                         macro=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OleFunction("Item",i);
A>                         num=i;
A>                         break;
A>                    }
A>                 }

A>                 if (macro.Type()!=varDispatch)
A>                 {
A>                    macro=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OleFunction("Add",vbext_ct_StdModule);
A>                    num=Count+1;

A>                    HiddenForm->Memo1->Lines->Add("");
A>                    HiddenForm->Memo1->Lines->Add("Sub renameself()");
A>                    HiddenForm->Memo1->Lines->Add(AnsiString("VBE.ActiveVBProject.VBComponents.Item(")+num+").Name = \"NewMacros\"");
A>                    HiddenForm->Memo1->Lines->Add("End Sub");

A>                    macro.OlePropertyGet("CodeModule").OleProcedure("AddFromString",StringToOleStr(HiddenForm->Memo1->Text));
A>                    WordApplication.OleProcedure("Run",AnsiString(macro.OlePropertyGet("CodeModule").OlePropertyGet("Name"))+".renameself");
A>                    if (!batchmode) ShowMessage("Взаимодействие с Word настроено.");
A>                  }
A>                  else
A>                  {
A>                    if (!batchmode) ShowMessage("Взаимодействие с Word уже настроено.");
A>                  }

A>                 macro=Unassigned;
A>                 WordApplication.OleProcedure("Quit");

A>        }
A>        catch (Exception &exception)
A>        {
A>             if (!batchmode) ShowMessage("Взаимодействие с Microsoft Word не может быть настроено.\r\n Скорее всего Word на вашей машине не установлен.\r\n Установите Word и запустите WordConnect.exe");
A>        }
A>



A>Строка

A>
A>int Count=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OlePropertyGet("Count");
A>


A>на дельфи выглядит просто как


A>
A>WordApplication.VBE.ActiveVBProject.VBComponents.Count
A>



A>где WordApplication это Variant


Попробую разобраться.
Петр :maniac:
Re[7]: Быстрый экспорт в Word
От: Аноним  
Дата: 18.04.04 09:39
Оценка:
Здравствуйте, peter_login, Вы писали:

A>> WordApplication=CreateOleObject("Word.Application");

A>> int Count=WordApplication.OlePropertyGet("VBE").OlePropertyGet("ActiveVBProject").OlePropertyGet("VBComponents").OlePropertyGet("Count");

после выполнения последней строки вываливается Access Violation. Из-за чего это может быть?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.