Управление открытым диалогом MS Word от Delphi - PullRequest
1 голос
/ 02 марта 2020

Каждый раз, когда я запускаю этот код, я вручную подтверждаю, что хочу конвертировать «PDF-файлы».

Есть ли способ автоматизировать его?

procedure TFWordAnalyzer.Button1Click(Sender: TObject);
var
  Clipboard:TClipboard;
  WordApp,WordDocument: OleVariant;
begin
  try
    WordApp := GetActiveOleObject('Word.Application');
  except
    WordApp := CreateOleObject('Word.Application') ;
 end;

  WordApp.visible := true;
  WordApp.DisplayAlerts := False;

  WordDocument := WordApp.Documents.Open('D:\Corpus\Adyg\Hudmir.pdf', true, false);

  WordDocument.range.copy;

          sleep(1000);//Otherwise it fails
          RichEdit1.Clear;
          RichEdit1.PasteFromClipboard;

  WordDocument.close;
  WordApp.Quit;
  WordApp := Unassigned;
end;

enter image description here

Ответы [ 2 ]

2 голосов
/ 02 марта 2020

Обе проблемы, о которых вы упомянули, а именно, как избежать диалогового окна «Преобразовать файл» и всплывающего запроса о сохранении данных, скопированных в буфер обмена, можно избежать, указав правильные значения в вызовах автоматизации Word.

1. Избегание диалогового окна «Преобразование файла»

Обновите строку кода, открывающую документ, до

WordDocument := WordApp.Documents.Open('D:\Corpus\Adyg\Hudmir.pdf', ConfirmConversions := False);

. Это приведет к открытию документа без вызова диалога подтверждения преобразования.

Предполагая, что это работает, вы сможете восстановить второй и третий аргументы, чтобы у вас было

WordDocument := WordApp.Documents.Open('D:\Corpus\Adyg\Hudmir.pdf', true, false, ConfirmConversions := False);

Обратите внимание, что синтаксис

WordApp.Documents.Open([...], ConfirmConversions := False)

был добавлен в то же время время (в D2) одновременно с OLE-автоматизацией через OleVariants, для поддержки необязательных аргументов, передаваемых вызовам автоматизации.

PS: с этим изменением вы можете обнаружить, что ваш вызов Sleep излишен. Я говорю «может», потому что мой тестовый код в первую очередь не нуждался в этом.

2. Избегание запроса на сохранение содержимого буфера обмена.

Это приглашение появляется, если вы пытаетесь закрыть Word с помощью автоматизации, когда скопировали большой объем данных в буфер обмена.

Чтобы избежать этого, просто замените

WordApp.Quit;

на

WordApp.Quit(SaveChanges := False);

Это должно быть все, что вам нужно. Тот факт, что это работает, немного нелогичен: поскольку вы сохранили данные из своего WordDocument, вы можете ожидать, что использование WordDocument - это способ очистки данных буфера обмена (см. Теперь лишнее обновление ниже). Однако, установив тестовое приложение с несколькими флажками, которые управляют значениями параметров для WordDocument.Close и WordApp.Close, и протестировав различные варианты их настроек, я установил, что только значение SaveChanges, переданное в WordApp.Quit, влияет это поведение и позволяет избежать диалогового окна (если бы оно было отображено в противном случае).

Остальная часть этого ответа может быть проигнорирована, но я оставил его, поскольку он может помочь будущим читателям с подобными проблемами. Я также добавил тег VBA в q, так как я нашел множество вопросов о том, как избежать запроса сохранения буфера обмена в вопросах VBA, но ни одно из них не содержало окончательного решения, которое бы работало с кодом здесь.

+++++++++++++++++++++++++++++++++++++++++

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

Google нашел несколько предложений о том, как избежать приглашения, но я обнаружил, что ни одно из них не работает надежно при работе с 17-мегабайтным PDF-файлом. Метод, показанный ниже, к которому я пришел экспериментально, действительно , кажется, работает надежно, но не так просто, как хотелось бы.

Причина, по которой возникает запрос, заключается в том, что Word очевидно, устанавливает внутренние указатели на содержимое буфера обмена, поэтому мне было интересно, сработает ли для текста Range меньший размер, а затем отбросить его перед закрытием документа. Я столкнулся с 2 проблемами:

  • вызов vRange.End: = 1 не имел никакого эффекта

  • попытка вызова vRange.Set_Text: = '' вызвало исключение, утверждая, что vRange не поддерживает метод Set_Text, несмотря на тот факт, что интерфейс Range в модуле импорта Word2000.Pas для MS Word явно поддерживает. Итак, приведенный ниже код выбирает объект Range, содержащийся в варианте vRange, и вызывает для него Set_Text. Это работает, но означает, что вам нужно добавить Word2000.Pas (или один из последних модулей импорта Word) в предложение Uses.

Обратите внимание, что я удалил вызов объекта GetActiveOle для избегать возникновения исключительной ситуации при ее сбое, что приводит к прерыванию отладки.

procedure TForm1.Button1Click(Sender: TObject);
var
  Clipboard:TClipboard;
  WordApp,
  WordDocument: OleVariant;
  vRange : OleVariant;
  iRange : Range;  //  or WordRange for D10.3.1+
begin
  try
    WordApp := CreateOleObject('Word.Application') ;
    WordApp.visible := true;
    WordApp.DisplayAlerts := False;

    try
      WordDocument := WordApp.Documents.Open('D:\aaad7\aaaofficeauto\test.pdf', ConfirmConversions := False); //, true, false);

      vRange := WordDocument.range;
      Label1.Caption := IntToStr(vRange.Start) + ':' + IntToStr(vRange.End);
      vRange.copy;

      sleep(1000);//Otherwise it fails
      RichEdit1.Clear;
      RichEdit1.PasteFromClipboard;

      //  vRange.Set_Text(' ');  // This provokes a "Method Set_Text not supported by automation object" exception
      //  SO ...
      //  Pick up the Range interface contained in the vRange variant
      iRange := IDispatch(WordDocument.range) as Range;
      // and call Set_Text on it to set the Range's text to a single space
      iRange.Set_Text(' ');
      //  Clear the iRange interface
      iRange := Nil;

      finally
        //   beware that the following discards and changes to the .Pdf
        //   so if you want to save any changes, you should do it
        //   before calling iRange.Set_Text
        WordDocument.close(False, False, False);
        WordDocument := UnAssigned;
      end;
  finally
    WordApp.Quit(False, False, False);
    WordApp := Unassigned;
  end;
end;

Протестировано с MS Word 2010 на Windows 10 64-bit /

0 голосов
/ 03 марта 2020

Вот рабочий код:

procedure TFWordAnalyzer.Button5Click(Sender: TObject);
var
  Clipboard:TClipboard;
WordApp,
WordDocument: OleVariant;
vRange : OleVariant;
iRange : WordRange;

begin

try
WordApp := CreateOleObject('Word.Application') ;
WordApp.visible := true;
WordApp.DisplayAlerts := False;

try
  WordDocument := WordApp.Documents.Open('D:\Corpus\Adyg\Hudmir.pdf', ConfirmConversions := False); //, true, false);

  vRange := WordDocument.range;
  Label1.Caption := IntToStr(vRange.Start) + ':' + IntToStr(vRange.End);
  vRange.copy;

  sleep(1000);//Otherwise it fails
  RichEdit1.Clear;
  RichEdit1.PasteFromClipboard;
  iRange := IDispatch(WordDocument.range) as WordRange;
  iRange.Set_Text(' ');
  iRange := Nil;

  finally

    WordDocument.close(False, False, False);
    WordDocument := UnAssigned;
  end;
 finally
   WordApp.Quit(False, False, False);
   WordApp := Unassigned;

 end;

  end;
...