OLE Automation: как скопировать текст между документами Word без использования буфера обмена - PullRequest
4 голосов
/ 22 марта 2011

При выполнении автоматизации Word в Delphi XE у меня одновременно открываются два документа. Я хочу скопировать содержимое данного диапазона одного документа в другой диапазон в другом документе. Как я могу это сделать?

Рассмотрим следующий код:

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;

Есть ли что-то, что я мог бы заменить СОДЕРЖАНИЕМ? Я не могу использовать текст, поскольку хочу скопировать форматирование, закладки, коды полей и т. Д. Нужно ли вообще делать это по-другому? Есть предложения?

Ответы [ 4 ]

3 голосов
/ 24 марта 2011

Я не знаю способа для более ранних версий 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
 
1 голос
/ 24 марта 2011

Если вы можете использовать формат Office Open XML (т. Е. Формат файла docx, представленный в Word 2007), то вы можете сделать это без автоматизации.

Версии Word до 2007 года должны установить пакет совместимости , который будет включать docx-файлы для Word 2003, 2002 и 2000.

Docx-файл на самом деле является zip-файлом, который содержит несколько xml-файлов. Попробуйте изменить расширение docx-файла с .docx на .zip и откройте этот файл, например, в. WinZip.

Итак ... Разархивируйте docx-файл и возьмите нужную xml-часть. Как чистая строка или как XML-документ. Затем вы можете вставить эту xml-часть в другой docx-файл. Вам нужно знать , где в xml-структуре, чтобы захватить / вставить xml. Это будет зависеть от того, насколько хорошо вы знаете структуру документа и насколько редактору разрешено делать в документе.

Я не знаю, как Word будет обрабатывать дубликаты имен закладок и т. Д. При таком подходе.

0 голосов
/ 21 мая 2014

Кажется, я нашел каноническое решение этого вопроса, когда копался в подобной проблеме. Свойство FormattedText объекта Range - это именно то, что вам нужно. Просто используйте:

vRange2.FormattedText := vRange1;

и содержимое vRange1 будет скопировано в vRange2. Кроме того, это тоже работает:

vRange2 := vRange1;

Хотя второе утверждение не копирует форматирование.

0 голосов
/ 23 марта 2011

Почему бы не использовать буфер обмена?Если весь текст выделен в vDoc1, то для копирования этого в буфер обмена требуется один простой вызов: vDoc1.copy.Аналогично, для копирования содержимого буфера обмена во второй документ требуется один простой вызов: vDoc2.paste.Буфер буфера обмена будет содержать всю информацию о форматировании.

...