将 OLE 对象插入 MS Word 文档并保持底层格式 WMF 不变

Ran*_*dom 8 c# vba ms-word

我正在尝试在 C# Word interop (NetOffice) 中复制以下方法

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False
Run Code Online (Sandbox Code Playgroud)

我说“复制”是因为我不想实际使用该PasteSpecial方法,因为我需要更新许多field类型link一次性,并且不喜欢依靠复制和粘贴来与excel进行通信。

我已经有以下代码,它主要完成我想要的但有一些我无法克服的问题。

Selection.InlineShapes.AddOLEObject ("Excel.Sheet.12", fileName + $"!{label}", true)
Run Code Online (Sandbox Code Playgroud)

此方法失败并显示错误消息

Word 无法创建指向您指定的对象的链接。请将对象直接插入到您的文件中,而无需创建链接

当且仅当我使用带有标签的网络驱动器或 unc 路径时,我才会收到此错误消息。例如。

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
Run Code Online (Sandbox Code Playgroud)

如果我不使用标签,例如。

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

\\TestShare\TestFile.xlsx
\\TestShare\TestFile.xlsx
Run Code Online (Sandbox Code Playgroud)

或本地驱动器,例如。C:(有无标签)

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

C:\TestFile.xlsx!Sheet1!TestRange
C:\TestFile.xlsx!Sheet1!R1C1:R2C2
Run Code Online (Sandbox Code Playgroud)

一切正常。

因此,只有组合网络驱动器或 unc + a 标签会产生该错误消息。

我想,好吧没问题我已经知道如何更改生成的路径和标签,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();
}
Run Code Online (Sandbox Code Playgroud)

但是这个解决方案,将图像的底层格式从 WMF(Windows 元文件)更改为 EMF(增强型元文件),但我需要它以 WMF 格式存储,因为 Office 2010无法正确呈现 EMF。

为了获取底层文件,我将 my 重命名docx为 tozip并将其解压缩以查看word\media目录。

PasteSpecial 不会抛出该错误,并生成所需的 WMF 格式,但我似乎无法 100% 复制发生的例程 PasteSpecial.

正如我旁注的那样,我不想有pngbmp要么,因为这些是在字体周围模糊生成的,所以最好的结果wmfOffice 2010.

对于Office 2013及更高版本,我使用以下代码emf从一开始就正确处理,并且不会遇到有关网络驱动器/unc + 标签错误的问题。

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

编辑:

在这里,我试图解决的主要问题的屏幕截图,因为我的提醒,这是它的外观在Office 2010Office 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
Run Code Online (Sandbox Code Playgroud)

word文档中的第二个表生成一个WMF文件,同时使用粘贴特殊格式“图片(Windows元文件)”,宏录制生成以下代码:

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False
Run Code Online (Sandbox Code Playgroud)

在右侧,您可以看到我复制粘贴到左侧word文档中的excel文件。

正如您可以清楚地看到的,Office 2010渲染/绘制 WMF 文件(word 文档中的第二个表)更好,所以这将是我想要的输出,但正如我提到的,我很难复制PasteSpecial并保持WMF更好地呈现/绘制的文件.

编辑2:

我记录了我的屏幕以显示错误,请原谅我的环境是德语。 https://imgur.com/a/50wcBGQ

我使用的代码是这样的:

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False
Run Code Online (Sandbox Code Playgroud)

C5在excel文件中写了“UsedRange”,如果标签正在使用或未使用,则在word中显示不同的输出,如果我不指定标签,它使用UsedRange第一张纸的。

仅供参考,我已经编写了简单的代码vba来证明它与此无关,C#并且可以在没有任何特殊情况的情况下进行本地复制。最后,如果有解决方案,将包含在我的C#应用程序中。

编辑3:

只是为了澄清,如果有人知道一种更好地Office 2010渲染/绘制EMF文件的方法,这对于我的问题来说也是一个有效的解决方案,因为在一天结束时,我只想在我的word文档。我真的不在乎是否EMFWMF,我只是想尝试使用WMF它,因为它看起来更好,并且有我描述的问题,告诉Office 2010继续WMF格式。

因为只有这样,我知道的,克服了错误信息,是通过操纵Field,如上图所示,但一旦我打电话field.Update()WMF文件被替换为EMF,我结束了与难看渲染/绘制的EMF文件。

编辑4:

根据要求,我查看了文档的内部结构并查看了差异。实际差异基本上是 0,只有一些应该无关紧要的东西,比如修订号、字符数等等。

但我注意到以下内容,即使这段代码

Selection.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, _
    Placement:=wdInLine, DisplayAsIcon:=False
Run Code Online (Sandbox Code Playgroud)

生成一个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"/>
Run Code Online (Sandbox Code Playgroud)

XMLOLE 对象的实际有以下内容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>
Run Code Online (Sandbox Code Playgroud)

如您所见,LinkType定义为EnhancedMetaFile(EMF)。

由于 OLE 对象是这样定义的,我尝试了一个简单的调用是否field.Update会触发从WMFto的更改EMF,可悲的是就是这种情况,所以即使我不修改field代码,像这样的简单调用

Selection.InlineShapes(1).Field.Update
Run Code Online (Sandbox Code Playgroud)

将已经触发从WMF到的转换,EMF因为 OLE 对象只是像这样简单地定义,转换也可以在没有任何自定义代码的情况下实现,只需选择内联形状并点击F9或右键单击并选择Update Links(从我的德国环境翻译)

请注意,无论出于何种原因,这段代码

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

不会触发转换,但如果您保存word文档并再次打开它,则可以调用field.Update以触​​发转换。

因此,要一次性完成转换,而无需保存/关闭 Word 文档,您至少需要调用它

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
Run Code Online (Sandbox Code Playgroud)