OLE 自动化:如何在不使用剪贴板的情况下在 Word 文档之间复制文本

发布于 2024-10-26 09:17:07 字数 1138 浏览 5 评论 0原文

在使用 Delphi XE 进行一些 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 吗?我无法使用文本,因为我想复制格式、书签、字段代码等。我是否必须以另一种方式进行操作?有什么建议吗?

While doing som Word automation from Delphi XE, I have two documents open simultaneously. I want to copy the contents of a given range of one document to another range in the other document. How can I do this?

Consider the following code:

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;

Is there something I could substitute for CONTENTS? I can't use text, since I want to copy formatting, bookmarks, field codes etc. Do I have to do it another way alltogether? Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

没有心的人 2024-11-02 09:17:07

我不知道适用于早期版本的 Word 的方法,但对于较新版本(2007 及更高版本),您可以 将文档范围导出到片段文件,然后从另一个文档导入它。如果你想要早期绑定,你可能需要导入类型库(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
 

I don't know a way for earlier versions of Word, but for newer versions (2007 and up) you can export a range from a document to a fragment file, and then import it from another document. If you want early binding, you might need to import the type library (msword.olb), I don't know if Delphi XE has it. Otherwise the code might look like this:

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;

With my test, 'document' format threw an error (something like not being able to insert XML formatting), hence usage of RTF format.

edit:

With earlier versions, it seems to be possible to insert a named selection from one document to a selection in another document. The result seems not to be perfect regarding formatting if one of the selections happens to be in the middle of some text. But otherwise it seems to be working good.

  ...
  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
 
少女的英雄梦 2024-11-02 09:17:07

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

2007 年之前的 Word 版本必须安装 兼容包 它将启用 Word 2003、2002 和 2000 的 docx 文件。docx

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

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

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

If you can use the Office Open XML-format (ie. the docx file format that was introduced in Word 2007), then you can do this without automation.

Word versions prior to 2007 must install a compatibility pack which will enable docx-files for Word 2003, 2002 and 2000.

The docx-file is actually a zip-file that contains several xml-files. Try to change the extension of a docx-file from .docx to .zip and open this file in eg. WinZip.

So... Unzip docx-file and grab the xml-part you need. As pure string or as a xml document. Then you can inject this xml-part into the other docx-file. You need to know where in the xml-structure to grab/insert the xml, though. This will depend on how well you know the document structure and how much editing the user is allowed to do in the document.

I don't know how Word will handle duplicate bookmark names etc with this approach.

海拔太高太耀眼 2024-11-02 09:17:07

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

vRange2.FormattedText := vRange1;

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

vRange2 := vRange1;

尽管如此,第二条语句不会复制格式。

It seems I found the canonical solution to this question while digged into similar problem. The FormattedText property of Range object is the exact what do you need. Just use:

vRange2.FormattedText := vRange1;

and the contents of vRange1 will be copied into vRange2. Also, this works too:

vRange2 := vRange1;

Though, the second statement doesn't copy the formatting.

你曾走过我的故事 2024-11-02 09:17:07

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

Why not use the clipboard? If all the text is selected in vDoc1, then to copy this to the clipboard involves one simple call: vDoc1.copy. Similarly, copying the contents of the clipboard to the second document requires one simple call: vDoc2.paste. The clipboard buffer will hold all the formatting information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文