[英]Manipulating MS Word Open Dialog from Delphi
每次运行此代码时,我都会手动确认我要转换“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;
您提到的两个问题,即如何避免“转换文件”对话框和有关保存复制到剪贴板的数据的弹出提示,都可以通过在对 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)
通过 OleVariants 与 OLE 自动化同时(在 D2 中)添加,以支持传递给自动化调用的可选参数。
PS:有了这个变化,你可能会发现你对 Sleep 的调用是不必要的。 我说“可能”是因为我的测试代码一开始就不需要它。
2. 避免提示保存剪贴板的内容。
如果您在将大量数据复制到剪贴板后尝试使用自动化关闭 Word,则会弹出此提示。
为了避免它,只需更换
WordApp.Quit;
经过
WordApp.Quit(SaveChanges := False);
这应该就是你所需要的。 这样做有点违反直觉:当您从 WordDocument 保存数据时,您可能希望使用 WordDocument 是清除剪贴板数据的方法(请参阅下面现在多余的更新)。 但是,通过设置带有多个复选框的测试应用程序,这些复选框控制 WordDocument.Close 和 WordApp.Close 的参数值,并测试其设置的各种排列,我确定只有传递给 WordApp.Quit 的 SaveChanges 值会影响这种行为并避免对话框(如果它本来会被显示)。
这个答案的其余部分可以忽略,但我让它保留下来,因为它可能会帮助未来遇到类似问题的读者。 我还在 q 中添加了VBA标签,因为我发现了许多关于如何避免 VBA 问题中的剪贴板保存提示的问题,但没有一个明确的解决方案可以与此处的代码一起使用。
+++++++++++++++++++++++++++++++++++++++++++
更新OP 报告说,上述代码可能会导致 Word 在关闭时提示剪贴板上有大量数据,并询问是否可以自动响应提示。
Google 找到了一些避免提示的建议,但我发现它们中没有一个可以可靠地处理 17Mb .Pdf 文件。 如下图所示的方法,我在通过实验来了,似乎可靠地工作,但不是那么简单,因为我想它是。
出现提示的原因是 Word 显然设置了指向提供给剪贴板的内容的内部指针,所以我想知道将 Range 的文本设置为小得多的内容,然后在关闭文档之前将其丢弃是否可行。 我遇到了两个问题:
调用 vRange.End := 1 没有效果
试图调用 vRange.Set_Text := ' ' 引发了一个异常,声称 vRange 不支持 Set_Text 方法,尽管事实上 MS Word 的 Word2000.Pas 导入单元中的 Range 接口显然支持。 因此,下面的代码选取包含在 vRange 变体中的 Range 对象,并在其上调用 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;
在 Windows 10 64 位/上用 MS Word 2010 测试
这是工作代码:
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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.