#delphi #automation #ms-word #delphi-7
#delphi #автоматизация #ms-word #delphi-7
Вопрос:
У меня есть программа, написанная на Delphi-7, которая открывает новый документ Word, основанный на шаблоне.
Как только документ открыт, автоматизация переходит к закладке (предопределенной в шаблоне) и добавляет туда некоторый текст.
Следующий код отлично работает в Word 2003, но вызывает invalid variant operation
сообщение об ошибке в Word 2010 (я опустил try/except
блоки для большей ясности).
wrdapp:= CreateOleObject ('Word.Application');
wrdDoc:= wrdapp.documents.add (wrdApp.Options.DefaultFilePath[wdUserTemplatesPath] '1.dot'
wrdApp.selection.goto (wdGotoBookmark, unassigned, unassigned, 'B1')
Если я заменю третью строку на
wrdDoc.bookmarks.item ('B1').select
программа отлично работает в Word 2003, но по-прежнему вылетает в Word 2010.
Какой правильный код для Word 2010 для «перехода» к закладке?
Комментарии:
1. Просто любопытно, если вы разместите 10-секундное ожидание (
Sleep(10000);
) между первой и второй строками, вы все равно получите ошибку?2. Невероятно, но факт! Сделайте свой комментарий ответом, потому что sleep — это то, что заставило код работать. Я сократил время до 5 секунд, но это тоже сработало.
3. Подождите минутку… Должен быть способ получше, чем фиксированный интервал ожидания. Конечно, этот подход может сработать почти в каждом экземпляре, но, вероятно, есть способ, который гарантированно сработает в каждом экземпляре. Можно было бы ожидать чего-то подобного
wrdApp.WaitUntilReady
…
Ответ №1:
В Word 2010 есть ошибка, связанная с загрузкой Normal.dotm (и, возможно, плагинов тоже, кто знает?). Когда вы запускаете Word 2010, как обычно, вы видите заставку, и Word выполняет некоторую инициализацию, включая загрузку Normal.dotm. Когда вы запускаете Word через automation — CreateOleObject('Word.Application')
— он не ждет загрузки Normal.dotm и немедленно возвращается. Но выполнение операций, когда Normal.dotm все еще загружается, похоже, приводит к сбою Word. Что я сделал для решения этой проблемы, так это создал цикл, который просто ожидает загрузки шаблона. Вы также можете выбрать задержку, чтобы дать Word время для инициализации, но пока цикл работает.
Что-то вроде этого:
wrdapp := CreateOleObject('Word.Application');
//loop that waits for the normal template to load
while wrdapp.Templates.Count = 0 do
Sleep(200);
//continue operations
PS: У меня здесь нет Delphi, поэтому код может содержать ошибки, но вы поняли идею
Комментарии:
1. Ну, «ошибка» — это under заявление …
2. Отключенный ‘sleep’ работает хорошо, хотя я думаю, что буду использовать цикл, поскольку это, вероятно, сэкономит время. При запуске исправленной программы я заметил, что во время сна на экране появилось маленькое окно и закрылось, но это произошло так быстро, что я не смог увидеть, что было написано в окне. Вероятно, что-то связанное с шаблонами….
3. @No’am Ньюман: действительно, в заголовке окна написано что-то вроде «Загрузка»
Ответ №2:
Я думаю, вам следует заменить константы в вызове «GoTo_» переменными. Вот так:
...
var
vWhat, vBookmark:OleVariant;
begin
...
vWhat:=wdGoToBookmark;
vBookmark:='B1';
wrdApp.Selection.GoTo_(vWhat,emptyParam,emptyParam,vBookmark);
...
end;
Комментарии:
1. Использование переменных выдало это сообщение об ошибке: «Ошибка при переходе к закладке B1 — нарушение доступа по адресу 00458BCB в модуле «Testword.exe ‘. Считывание адреса 00000000». Кстати, я пишу ‘wrdApp.Selection.goto’, а не ‘wrdApp.selection.goto _’, потому что последнее вызывает ошибку «метод goto не поддерживается объектом автоматизации» в Office 2003.
Ответ №3:
Привет, я надеюсь, что это поможет вам. Я использую D2010 и Office 2010
Что я делаю: Если я нашел название закладки, я вставляю документ word в эту точку
Часть моего кода:
try
Template := EmptyParam;
NewTemplate := true;
ItemIndex := 1;
try
Wdapplication.Connect;
except
Screen.Cursor := crDefau<
MessageDlg('No se detecta Word Puede no estar instalado(1) o versi?n incorrecta de Word', mtError, [mbOK], 0);
Abort;
result := False;
end;
Wdapplication.Visible := true; // False;
WdApplication.Caption := 'Kalemat automation';
{Turn Spell checking of because it takes a long time if enabled and slows down Winword}
WdApplication.Options.CheckSpellingAsYouType := false;
WdApplication.Options.CheckGrammarAsYouType := false;
lbInfo.Lines.Add('Word connected');
except
on E: Exception do begin
ShowMessage(E.Message);
WdApplication.Disconnect;
result := False;
Exit;
end;
end;
//-
if wdapplication.Documents.Count > 0 then begin
Screen.Cursor := crDefau<
MessageDlg(
'Por Favor cierre todos sus Word-documentos antes de proseguir...', mtWarning,
[mbRetry], 0);
wdApplication.Visible := true;
WdApplication.Disconnect;
result := False;
exit;
end
else begin
with WdApplication do begin
// OnQuit := WordAppQuit;
// OnChangeDocument := WordDocChange;
// OnOpenDocument := WordDocOpen;
// OnPreCloseDocument := WordPreClose;
// OnCloseDocument := WordDocClose;
// DisableSystemCloseBox;
end
end;
{Create new document}
Template := EmptyParam;
NewTemplate := false;
oNewDocument := ModEsc;
// abre documento
lbInfo.Lines.Add('Abriendo escritura ' ModEsc);
WdApplication.Documents.AddOld(oNewDocument, NewTemplate);
// Conecta con al instancia de Word
WdDocument.ConnectTo(WdApplication.Documents.Item(ItemIndex));
sBookMarkName := 'FPROEMIO';
lbInfo.Lines.Add('Busca marcador Proemio');
if WdDocument.Bookmarks.Exists(sBookMarkName) then begin
// ShowMessage(' -Existe: ' sBookMarkName);
owhat := wdGotoBookMark;
owhich := unAssigned;
ocount := unAssigned;
//-->>> // ShowMessage(' -Ve a..: ' sBookMarkName);
//-->>> // Ve a ese marcados addendum
wdDocument.GoTo_(oWhat, oWhich, OCount, sBookMarkName);
// ShowMessage(' GoTo_.. ya estoy en: ' sBookMarkName);
// Lo encontre
oRange := '';
oConformConv := false;
oLink := false;
oattachment := false;
fl_Name := proemi;
lbInfo.Lines.Add('Insertando Proemio ' Proemi);
if not FileExists(fl_name) then begin
Screen.Cursor := crDefau<
lbInfo.Lines.Add('No Existe Documento PROEMIO ');
MessageDlg('Documento FPROEMIO NO EXISTE, Revise el modelo de escritura', mtError, [mbRetry], 0);
end
else
wdDocument.Bookmarks.Item(sBookMarkName).Range.InsertFile(Fl_Name, oRange, oConformConv, oLink, oattachment);
// ShowMessage(' -.. inserte el addendum');
end
else begin
lbInfo.Lines.Add('No Existe Marcador PROEMIO ');
end;