【问题标题】:OLE Automation: How do i copy text between Word documents without using the clipboardOLE 自动化:如何在不使用剪贴板的情况下在 Word 文档之间复制文本
【发布时间】:2011-03-22 15:11:52
【问题描述】:

在从 Delphi XE 进行 som Word 自动化时,我同时打开了两个文档。我想将一个文档的给定范围的内容复制到另一个文档中的另一个范围。我该怎么做?

考虑以下代码:

procedure TForm1.ManipulateDocuments;
var
  vDoc1,vDoc2 : TWordDocument;
  vFilename : olevariant;
  vRange1,vRange2 : Range;
begin
  vDoc1 := TWordDocument.Create(nil);
  vDoc2 := TWordDocument.Create(nil);
  try
    vFilename := 'c:\temp\test1.doc';
    vDoc1.ConnectTo(FWordApp.Documents.Open(vFilename,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam));

    vFilename := 'c:\temp\test2.doc';
    vDoc2.ConnectTo(FWordApp.Documents.Open(vFilename,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam));

    vRange1 := GetSourceRange(vDoc1);
    vRange2 := GetDestinationRange(vDoc2);

    vRange2.CONTENTS := vRange1.CONTENTS; //What should I substitute for CONTENTS?
  finally
    vDoc1.Free;
    vDoc2.Free;
  end;
end;

有什么东西可以代替 CONTENTS 吗?我不能使用文本,因为我想复制格式、书签、域代码等。我必须以另一种方式一起做吗?有什么建议吗?

【问题讨论】:

    标签: delphi automation clipboard ole delphi-xe


    【解决方案1】:

    我不知道早期版本的 Word 的方法,但对于较新版本(2007 及更高版本),您可以从文档到片段文件 export a range,然后从另一个文档 import 它。如果要提前绑定,可能需要导入类型库(msword.olb),不知道Delphi XE有没有。否则代码可能如下所示:

    function GetTempFileName(Prefix: string): string;
    begin
      SetLength(Result, MAX_PATH);
      GetTempPath(MAX_PATH, PChar(Result));
      windows.GetTempFileName(PChar(Result), PChar(Prefix), 0, PChar(Result));
    end;
    
    procedure TForm2.Button1Click(Sender: TObject);
    const
    //  wdFormatDocument = 0;
      wdFormatRTF = $00000006;
    var
      WordApp : OleVariant;
      fragment: string;
      vDoc1, vDoc2: OleVariant;
      vRange1, vRange2: OleVariant;
    begin
      try
        WordApp := GetActiveOleObject('Word.Application');
      except
        WordApp := CreateOleObject('Word.Application');
      end;
      WordApp.Visible := True;
    
      vDoc1 := WordApp.Documents.Open(ExtractFilePath(Application.ExeName) + 'test1.doc');
      vRange1 := vDoc1.Range(20, 120);     // the export range
      fragment := GetTempFileName('frg');
      vRange1.ExportFragment(fragment, wdFormatRTF);
      try
        vDoc2 := WordApp.Documents.Open(ExtractFilePath(Application.ExeName) + 'test2.doc');
        vRange2 := vDoc2.Range(15, 15);    // where to import
        vRange2.ImportFragment(fragment);
      finally
        DeleteFile(fragment);
      end;
    end;
    

    在我的测试中,“文档”格式引发了错误(类似于无法插入 XML 格式),因此使用了 RTF 格式。

    编辑:

    在早期版本中,似乎可以将一个文档中的命名选择插入到另一个文档中的选择中。如果其中一个选择恰好位于某些文本的中间,则结果在格式方面似乎并不完美。但除此之外,它似乎运作良好。

      ...
      WordApp.Visible := True;
    
      vDoc1 := WordApp.Documents.Open(ExtractFilePath(Application.ExeName) + 'test1.doc');
      vRange1 := vDoc1.Range(20, 188);                 // the transfer range
      vDoc1.Bookmarks.Add('TransferSection', vRange1); // arbitrary bookmark name
    
      vDoc2 := WordApp.Documents.Open(ExtractFilePath(Application.ExeName) + 'test2.doc');
      vRange2 := vDoc2.Range(103, 104);           // where to import the bookmark
      vRange2.Select;
      vDoc2.ActiveWindow.Selection.InsertFile(vDoc1.FullName, 'TransferSection');
    
      vDoc1.Bookmarks.Item('TransferSection').Delete; // no need for the bookmark anymore
     
    

    【讨论】:

    • 我注意到了这些功能(exportfragment/importfragment),它们非常适合我的需要。不幸的是,Word 2007 不适合我。我们的解决方案需要可供运行 Word 2003 的用户使用,甚至可能更早,因为这些功能不可用。不过还是谢谢。迄今为止最好的建议:-)
    • 更新:由于没有其他答案,我会接受这个作为最好的答案。尽管如此,让我感到困扰的是,在不涉及剪贴板或使用外部文件的情况下,没有好的方法可以做到这一点。看起来很基础:-/
    • @Svein - 我已经用替代方法更新了答案。如果仍然不能令人满意,我建议将msword 添加到标签中,并让问题暂时无人回答。
    【解决方案2】:

    如果您可以使用Office Open XML-格式(即 Word 2007 中引入的 docx 文件格式),那么您无需自动化即可执行此操作。

    2007 之前的 Word 版本必须安装 compatibility pack,这将为 Word 2003、2002 和 2000 启用 docx 文件。

    docx 文件实际上是一个包含多个 xml 文件的 zip 文件。尝试将 docx 文件的扩展名从 .docx 更改为 .zip 并在例如打开此文件。 WinZip。

    所以...解压缩 docx 文件并获取您需要的 xml 部分。作为纯字符串或 xml 文档。然后您可以将此 xml 部分注入到另一个 docx 文件中。不过,您需要知道 xml 结构中的 where 才能抓取/插入 xml。这取决于您对文档结构的了解程度以及允许用户在文档中进行多少编辑。

    我不知道 Word 将如何使用这种方法处理重复的书签名称等。

    【讨论】:

      【解决方案3】:

      似乎我在研究类似问题时找到了该问题的规范解决方案。 Range 对象的 FormattedText 属性正是您所需要的。只需使用:

      vRange2.FormattedText := vRange1;
      

      vRange1 的内容将被复制到 vRange2 中。此外,这也有效:

      vRange2 := vRange1;
      

      不过,第二个语句不会复制格式。

      【讨论】:

        【解决方案4】:

        为什么不使用剪贴板?如果在 vDoc1 中选择了所有文本,那么将其复制到剪贴板只需一个简单的调用:vDoc1.copy。同样,将剪贴板的内容复制到第二个文档需要一个简单的调用:vDoc2.paste。剪贴板缓冲区将保存所有格式信息。

        【讨论】:

        • 首先,如果我使用剪贴板,我将删除用户放在那里的任何内容。可不是什么好事。此外,此应用程序通常在剪贴板与本地剪贴板同步的终端服务器上运行,从而导致性能问题。
        • -1 剪贴板属于用户,而不是你。除非用户启动它(例如复制或剪切或粘贴),否则您绝对不应做任何影响剪贴板内容的操作。
        猜你喜欢
        • 1970-01-01
        • 2010-10-02
        • 2019-11-08
        • 1970-01-01
        • 1970-01-01
        • 2013-04-17
        • 1970-01-01
        • 1970-01-01
        • 2017-08-26
        相关资源
        最近更新 更多