Вставьте объект OLE в документ MS Word и сохраните основной формат WMF без изменений - PullRequest
8 голосов
/ 06 марта 2020

Я пытаюсь повторить следующий метод в C# Word Interop (NetOffice)

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False

Я говорю «реплицировать», так как я не хочу на самом деле использовать метод PasteSpecial, так как мне нужно обновить field типа link в одном go, и я не люблю общаться с Excel, полагаясь на копирование и вставку.

У меня уже есть следующий код, который выполняет в основном то, что я хочу, но есть некоторые проблемы, которые я не могу решить.

Selection.InlineShapes.AddOLEObject ("Excel.Sheet.12", fileName + $"!{label}", true)

Этот метод завершается ошибкой с сообщением об ошибке

Word не может создать ссылку на объект, который вы указали. Пожалуйста, вставьте объект непосредственно в ваш файл, не создавая ссылку

Я получаю это сообщение об ошибке только в том случае, если я использую сетевой диск или путь c с меткой. например.

T:\TestFile.xlsx!Sheet1!TestRange
T:\TestFile.xlsx!Sheet1!R1C1:R2C2
//notice that T is a network drive and not a local drive

\\TestShare\TestFile.xlsx!Sheet1!TestRange
\\TestShare\TestFile.xlsx!Sheet1!R1C1:R2C2

Если я не использую ярлык, например.

T:\TestFile.xlsx
T:\TestFile.xlsx
//notice that T is a network drive and not a local drive

\\TestShare\TestFile.xlsx
\\TestShare\TestFile.xlsx

или локальный диск, например. C: (с меткой или без)

C:\TestFile.xlsx
C:\TestFile.xlsx

C:\TestFile.xlsx!Sheet1!TestRange
C:\TestFile.xlsx!Sheet1!R1C1:R2C2

все работает нормально.

Таким образом, только комбинированный сетевой диск или un c + метка выдают это сообщение об ошибке.

Я подумал, ладно, нет проблем, я уже знаю, как изменить путь и метку производимого field, и написал следующий код для включения метки во второй шаг.

var inlineShape = Selection.InlineShapes.AddOLEObject("Excel.Sheet.12", fileName, true);
field = inlineShape.Field;
if (!string.IsNullOrEmpty(label))
{
    var fieldCode = field.Code.Text;
    //replace the produced empty label "" with the label I desire eg. "Sheet1!R1C1:R2C2"
    fieldCode = fieldCode.Replace(" \"\" ", $" \"{label}\"");

    //write the updated fieldcode back to the field        
    field.Code.Text = fieldCode;

    //update the field
    field.Update();
}

НО это решение меняет базовый формат изображения с WMF (Windows Meta File) на EMF (Enhanced Meta File), но мне нужно, чтобы он был сохранен в формате WMF, так как Office 2010 неправильно отображает EMF .

Чтобы получить базовый файл, я переименовываю свой docx в zip и извлекаю его, чтобы посмотреть в каталог word\media.

PasteSpecial не выдает эту ошибку и создает желаемый формат WMF, но я не могу на 100% повторить процедуру, которая происходит, пока PasteSpecial.

Как я отмечаю, я не хочу иметь png или bmp либо, так как они генерируются с размытостью вокруг шрифта, поэтому лучше всего Sult обеспечивает wmf для Office 2010.

Для Office 2013 и выше, я использую следующий код для получения emf с самого начала и не сталкиваюсь с проблемой сетевого диска / un c + ошибка метки.

var field = range.Fields.Add(range, WdEnums.WdFieldType.wdFieldLink);
field.LinkFormat.SourceFullName = fileName + $"!{label}";

Редактировать:

Вот скриншот основной проблемы, которую я пытаюсь решить, напоминая вот как это выглядит в Office 2010 в Office 2013 и выше оба выглядят прилично:

Для обоих я использую специальную пасту https://support.office.com/en-us/article/paste-special-e03db6c7-8295-4529-957d-16ac8a778719

Первая таблица в Word-документ создает файл EMF. При использовании специального формата вставки «Рисунок (расширенный метафайл)» при записи макросов получается следующий код:

Selection.PasteSpecial Link:=False, DataType:=wdPasteEnhancedMetafile, _
    Placement:=wdInLine, DisplayAsIcon:=False

Вторая таблица в документе Word создает файл WMF при использовании специальный формат вставки «Picture (Windows Metafile)», запись макроса производит этот код:

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False

На правой стороне вы можете увидеть файл Excel, который я скопировал, чтобы вставить в левое слово документа .

Как вы можете ясно видеть, Office 2010 рендерит / др aws файл WMF le (вторая таблица в текстовом документе) намного лучше, так что это был бы мой желаемый результат, но, как я уже упоминал, у меня есть проблемы с копированием PasteSpecial и сохранением файла WMF, который делает / dr aws лучше.

Edit2:

Я записал свой экран, чтобы показать ошибку, пожалуйста, извините, что моя среда на немецком языке. https://imgur.com/a/50wcBGQ

Я использовал следующий код:

Sub NetworkAndLabel()
    'this will fail

    Dim fileName As String
    Dim label As String

    'T is a mapped drive for the share \\NAS1\Ablage
    fileName = "T:\rfa\TestFile.xlsx"

    'label is in german, in english it would be Sheet1!R1C1:R1C2
    label = "Tabelle1!Z1S1:Z2S2"

    Selection.InlineShapes.AddOLEObject "Excel.Sheet.12", fileName & "!" & label, True
End Sub
Sub Network()
    'this will run successfully

    Dim fileName As String
    Dim label As String

    'T is a mapped drive for the share \\NAS1\Ablage
    fileName = "T:\rfa\TestFile.xlsx"

    Selection.InlineShapes.AddOLEObject "Excel.Sheet.12", fileName, True
End Sub
Sub LocalAndLabel()
    'this will run successfully

    Dim fileName As String
    Dim label As String

    'E is a local drive (second partition, not a seperate drive)
    'up till now, I only tested with C and wanted to see if a simple second partition works or not
    fileName = "E:\rfa\TestFile.xlsx"

    'label is in german, in english it would be Sheet1!R1C1:R1C2
    label = "Tabelle1!Z1S1:Z2S2"

    Selection.InlineShapes.AddOLEObject "Excel.Sheet.12", fileName & "!" & label, True
End Sub
Sub Local_()
    'this will run successfully

    Dim fileName As String
    Dim label As String

    'E is a local drive (second partition, not a seperate drive)
    'up till now, I only tested with C and wanted to see if a simple second partition works or not
    fileName = "E:\rfa\TestFile.xlsx"

    Selection.InlineShapes.AddOLEObject "Excel.Sheet.12", fileName, True
End Sub

Я написал "UsedRange" в C5 файла Excel, чтобы показать разницу вывод в слове, если метка используется или не используется, если я не указываю метку, она использует UsedRange первого листа.

К вашему сведению, я написал код простым vba, чтобы продемонстрировать, что он не имеет ничего общего с C# и может воспроизводиться без особого особенного воспроизведения. В конце концов решение, если оно есть, будет включено в мое приложение C#.

Edit3:

Просто чтобы уточнить, если кто-то знает способ улучшить Office 2010 рендеринг / отрисовку файла EMF, это также будет правильным решением для моей проблемы, потому что в конце дня я просто хочу иметь прилично выглядящий связанный файл Excel в моем текстовом документе. Мне все равно, если EMF или WMF, я просто пытаюсь работать с WMF, потому что он выглядит лучше, и у меня есть проблемы, которые я описал, говорящие Office 2010, чтобы остаться в формате WMF .

Поскольку я знаю, что единственный способ преодолеть сообщение об ошибке - это манипулировать Field, как показано выше, но после вызова field.Update() файл WMF заменяется на EMF, и в результате я получаю плохо выглядящий файл рендеринга / отрисовки EMF файла.

Edit4:

В соответствии с просьбой я посмотрел в Внутренняя структура документа и взглянул на различия. Фактическая разница, в основном, равна 0, есть только вещи, которые должны быть необратимыми, такие как номер редакции, количество символов и тому подобное.

Но я заметил следующее, хотя этот код

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False

генерирует файл WMF, который я могу увидеть, заглянув в папку word\media и увидев там созданный image1.wmf, или просмотрев файл word\_rels\document.xml.rels, который имеет следующую запись

<Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.wmf"/>

Фактический XML для объекта OLE имеет следующее значение в word\document.xml

<o:OLEObject Type="Link" ProgID="Excel.Sheet.12" ShapeID="_x0000_i1025" DrawAspect="Content" r:id="rId8" UpdateMode="Always"><o:LinkType>EnhancedMetaFile</o:LinkType><o:LockedField>false</o:LockedField></o:OLEObject>

Как вы можете видеть, LinkType определяется как EnhancedMetaFile (EMF).

Поскольку объект OLE определен следующим образом, я попытался, если простой вызов field.Update вызовет изменение с WMF на EMF, и, к сожалению, так и есть, так что даже без меня модифицируя field код, простой вызов, подобный этому

Selection.InlineShapes(1).Field.Update

уже будет запускать преобразование из WMF в EMF, поскольку объект OLE просто определяется следующим образом, преобразование также можно выполнить без какого-либо специального кода просто выберите встроенную форму и нажмите F9 или щелкните правой кнопкой мыши и выберите Update Links (перевод из моей немецкой среды)

Обратите внимание, что по какой-либо причине этот код

Selection.InlineShapes.AddOLEObject("Excel.Sheet.12", "E:\rfa\TestFile.xlsx", True).Field.Update

не сработает преобразование, но если вы сохраните слово document и снова откроете его, то вы можете вызвать field.Update, чтобы вызвать преобразование.

Таким образом, чтобы преобразование было одним go, без необходимости сохранения / закрывая слово document, вам нужно как минимум назвать это

With Selection.InlineShapes.AddOLEObject("Excel.Sheet.12", "E:\rfa\TestFile.xlsx!Tabelle1!Z1S1:Z2S2", True).Field

    .Code.Text = Replace(.Code.Text, "Z1S1:Z2S2", "Z2S2:Z3S3")
    .Update

End With
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...