简体   繁体   中英

Manipulating MS Word Open Dialog from Delphi

Every time I run this code, I manually confirm that I want to convert "PDF Files".

Is there any way to automate it?

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;

在此处输入图片说明

Both of the problems you have mentioned namely how to avoid the Convert File dialog and the pop-up prompt about saving data copied to the Clipboard can by avoided by specifiying the correct values in calls to Word's automation.

1. Avoiding the Convert File dialog

Update the line of your code which opens the document to

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

This should open the document without the Confirm Conversion dialog being invoked.

Assuming that works, you should be able to reinstate your second and third arguments, so that you have

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

Note that the syntax

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

was added at the same time (in D2) at the same time as OLE automation via OleVariants, to support optional arguments being passed to automation calls.

PS: With this change, you may find that your call to Sleep in unnecessary. I say "may" because my test code did not need it in the first place.

2. Avoiding the prompt to save the contents of the Clipboard.

This prompt pops if you attempt to close Word using automation when you have copied a large amount of data to the Clipboard.

To avoid it, simply replace

WordApp.Quit;

by

WordApp.Quit(SaveChanges := False);

That should be all you need. The fact that this works is slightly counter-intuitive: As you saved the data from your WordDocument, you might expect that using WordDocument is the way to clear the Clipboard data (see the now-superfluous update below). However, by setting up a test app with a number of checkboxes which control the parameter values for WordDocument.Close and WordApp.Close, and testing the various permutations of their settings, I established that only the value of SaveChanges passed to WordApp.Quit influences this behaviour and avoids the dialog (if it would otherwise have been displayed).

The remainder of this answer can be disregarded but I have let it remain aas it may help future readers with similar problems. I have also added the VBA tag to the q, as I found numerous questions about how to avoid the Clipboard-save prompt in VBA questions, but none with a definitive solution which worked with the code here.

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

Update The OP reported that the above code can result in a prompt from Word as it closes down saying that there is a large amount of data on the Clipboard, and queried whether it was possible to automate responding to the prompt.

Google found several suggestions for avoiding the prompt, but I found that none of them worked reliably working with a 17Mb .Pdf file. The method shown below, which I arrived at by experiment, does seem to work reliably but is not as simple as I would like it to be.

The reason the prompt occurs is that Word evidently sets up internal pointers to the contents provided to the Clipboard, so I wondered if setting the text of the Range to something much smaller and then discarding it before closing the document would work. I ran into 2 problems:

  • calling vRange.End := 1 had no effect

  • trying to call vRange.Set_Text := ' ' provoked an exception claiming that vRange does not support the Set_Text method despite the fact that the Range interface in the Word2000.Pas import unit for MS Word clearly does. So, the code below picks up the Range object contained in the vRange variant and calls Set_Text on that. This works but means that you need to add Word2000.Pas (or one of the more recent Word import units) to the Uses clause.

Note that I removed the call to GetActiveOle object to avoid an exception being raised when it failed, which disrupted debugging.

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;

Tested with MS Word 2010 on Windows 10 64-bit/

Here is the working code:

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM