11

I am trying to replicate the following method in C# Word interop (NetOffice)

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

I am saying "replicate" since I don't want to actually use the PasteSpecial method, since I need to update many fields of type link in one go, and don't like to communicate with excel by relying on copy and paste.

I already have the following code that does mostly what I want but has some issues that I am not able to overcome.

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

This method fails with an error message

Word is unable to create a link to the object you specified. Please insert the object directly into your file without creating a link

I am only getting this error message, if and only if I use a network drive or unc path with a label. eg.

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

If I dont use the label eg.

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

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

or a local drive eg. C: (with or without label)

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

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

everything works fine.

So, only the combination network drive or unc + a label produces that error message.

I thought, okay no problem I already know how to change the path and label of the produced field and wrote the following code to include the label in a second step.

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();
}

BUT this solution, changes the underlying format of the image from WMF (Windows Meta File) to EMF (Enhanced Meta File), but I need it to be stored in the WMF format, since Office 2010 doesn't render EMF correctly.

To get the underlying file, I rename my docx to zip and extract it to look into the word\media directory.

PasteSpecial doesn't throw that error, and produces that desired WMF format, but I can't seem to 100% replicate the routine that happens while PasteSpecial.

As I side note, I don't want to have png or bmp either, since those are generated with a blur around the font, so the best result delivers wmf for Office 2010.

For Office 2013 and higher, I am using the following code to get emf right from the start and don't face issue about network drive/unc + label error.

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

Edit:

Here a screenshot of the main problem that I try to solve, as I reminder this is how it looks in Office 2010 in Office 2013 and higher both look decent:

For both I am using paste special https://support.office.com/en-us/article/paste-special-e03db6c7-8295-4529-957d-16ac8a778719

The first table in the word document produces an EMF File, while using the paste special format "Picture (Enhanced Metafile)", macro recording produces this code:

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

The second table in the word document produces an WMF File, while using the paste special format "Picture (Windows Metafile)", macro recording produces this code:

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

On the right side, you can see the excel file I did copy to paste in the left word document.

As you can clearly see, Office 2010 renders/draws the WMF file (the second table in the word document) alot nicer, so that would be my desired output, but as I mentioned I have struggle replicating the PasteSpecial and keeping the WMF file that renders/draws better.

Edit2:

I recorded my screen to show the error, pls excuse that my environment is in german. https://i.stack.imgur.com/sQNBo.jpg

The code I have used is this:

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

I wrote "UsedRange" in C5 of the excel file, to show the differnt output in word if a label is or isn't in use, if I don't specify the label, it uses the UsedRange of the first sheet.

FYI, I have written the code in simple vba to demonstrate that it has nothing to do with C# and can nativly reproduced without anything special. In the end the solution, if there is one, will be included in my C# application.

Edit3:

Just to clarify, if someone knows a way to make Office 2010 render/draw the EMF file better, that would also be a valid solution, for my problem, because at the end of the day, I simply want to have a decent looking linked excel file in my word document. I don't really care if EMF or WMF, I am just trying to work with WMF because it looks better, and have the issues that I described, telling Office 2010 to stay on the WMF format.

Because the only way, I know of, to overcome the error message, is by manipulating the Field, as shown above, but once I call field.Update() the WMF file gets replaced with EMF, and I end up with the bad looking render/draw of the EMF file.

Edit4:

As requested, I had a look into the internal structure of the document and had a look at the differences. The actual difference is basically 0, only had stuff that should be irrelevent, like revisionnumber, characters count and stuff like this.

But I noticed the following, even though this code

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

generates a WMF file, which I can see either by looking into the word\media folder and seeing there the produced image1.wmf, or by looking at the file word\_rels\document.xml.rels which has the following entry

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

The actual XML for the OLE Object has the following in 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>

As you can see the LinkType is defined as EnhancedMetaFile (EMF).

Since the OLE Object is defined like this, I tried if a simple call to field.Update would trigger the change from WMF to EMF, and sadly thats the case, so even without me modifing the field's code, a simple call like this

Selection.InlineShapes(1).Field.Update

will already trigger the conversion from WMF to EMF since the OLE Object is just simply defined like this, the conversion can also be achieved without any custom code, just select the inline shape and hit F9 or right click and select Update Links (translated from my german environment)

Notice that for what ever reason, this code

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

Will not trigger the conversion, but if you save the word document and open it again, than you can call field.Update to trigger the conversion.

So, to have the conversion in one go, without the necessity of saving/closing the word document, you need to atleast call this

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
Rand Random
  • 7,300
  • 10
  • 40
  • 88
  • 2
    Few random thoughts. Could you temporarily map the network drive to the location required, add the link to the file, then remove it? Also, this is a bit of a shot in the dark, but I wonder if the `Word is unable to create a link to the object you specified...` error is due to access. Maybe try adding the path as a Trusted Location and see if that makes a difference. – Ryan Wildry Mar 09 '20 at 20:36
  • You wrote "don't like to communicate with excel by relying on copy and paste." Why? I have solved glitches around the clipboard before. Please expand. – S Meaden Mar 10 '20 at 09:23
  • @RyanWildry - not sure what you meant with your first sentence, but if you meant that I should map the share `\\TestShare\TestFile.xlsx` as a drive, I have already done that by mapping it to the letter `T:\` - so it makes not difference if the share is mapped, or accessed by unc - about your second sentence, I already tried this, but without success, also as I mentioned the "normal" path (without the label) works fine, but once I define what sheet and range it should use I get the error message – Rand Random Mar 10 '20 at 09:41
  • @SMeaden - 1. I don't want to rely on excel to run at all, and want to insert the shape, it would than produce an error with a invalid field, but that would be a desired result 2. I made bad experience with relying on copy and paste, not only the simple user unfriendly side effect of overwriting the users clipboard 3. if excel would is running, I would need to save and restore the old position the user currently is, what workbook is active, what sheet, what range, what object and so on, which seems cumbersome – Rand Random Mar 10 '20 at 09:45
  • @RandRandom I think I misunderstood what the issue is. What you are saying is that when the file is reference via UNC or a mapped network drive the issue persists, but performing the actions locally work as expected, is that right? If that's true, my question is then, why not copy the file(s) first to a local directory, apply the changes, then move the files back? – Ryan Wildry Mar 10 '20 at 12:00
  • @RyanWildry - yes, the unc/mapped drive is a persistant error, that I can reproduce on multiple machines, and any office version, the only issue that is solely related to 2010 is the poor render/draw of emf - I thought about copying the files, but I can't do this, since the user could have the files open with unsaved changes, if the user than hits a custom refresh button in word, those unsaved changes still need to be present in word, and I wouldn't want to force the user to save his changes in excel prior, cause they do alot of temporary work in there and check how it influences that numbers – Rand Random Mar 10 '20 at 12:37
  • @RyanWildry - and yes, no issue at all if its a local drive – Rand Random Mar 10 '20 at 12:38
  • If the only limitations to check to see if the file is open (someone is working it), maybe check to see if the file is open, and only apply changes when it is closed. See: https://stackoverflow.com/a/9373914/4839827 – Ryan Wildry Mar 10 '20 at 14:17
  • I'll add this as a comment, have you done it manually, extracted the docx and examined the raw files? If you are intending to bypass Interop this would be the way. – Jeremy Thompson Mar 11 '20 at 05:28
  • @RyanWildry - thx, for the input so far, and I want to apologize if it seems that I am basically saying no to all the suggestions, but sadly this isn't a way I can move on, since this would interupt the workflow of my users, the user would need to save and close his excel file, for him to see the changes in his word document, and this would be required frequently, since a user most often only works at one part of the word document at a time and than move on, with a document that has around 20-50 excel links, you can imagine that it would get rather annoying – Rand Random Mar 11 '20 at 08:39
  • @RyanWildry - also saving the excel file to frequently isn't easy aswell since the documents are part of a document management and every save is treated as a commit that has to be protocolled and the reason the user would than state is "my software provider tells me to save the excel file to see changes in word", that would put me on the spotlight – Rand Random Mar 11 '20 at 08:42
  • @JeremyThompson - do you mean to check if the raw files are `emf` or `wmf`? yes, I did that, I renamed the `docx` to `zip` and extracted it to have a look eg. https://i.stack.imgur.com/sECjd.png – Rand Random Mar 11 '20 at 08:52
  • @JeremyThompson - or do you mean, I should check eg. what got written to `document.xml` and replicate the function using `Open XML SDK` and manipulate the `document.xml` that way? if thats the case, if I am not mistaken the word document can't be open while I do this or can it? if I would force the user to save/close the word document before I can do it, the same applies here as with the excel file, worflow gets interupted and commits in document managment – Rand Random Mar 11 '20 at 08:52
  • The latter and yes 100% the Open XML SDK! Just to see what the actual difference is, could you add the diff to your question as that maybe a clue to why it's happening. And/or potentially be a last resort to edit the zipped files programmatically.to stop the EMF conversion. – Jeremy Thompson Mar 11 '20 at 10:11
  • 1
    If instead of mapped drive you create a symbolic link to shared folder (mklink) the `LocalAndLabel` seems to work. – BrakNicku Mar 11 '20 at 10:16
  • @JeremyThompson - updated my question, hope it is understandable – Rand Random Mar 12 '20 at 09:41
  • @BrakNicku - thx for your input, and I can happily report that this works, already told the support team about the solution, lets see if our client is happy :) - though, I still would prefer a solution without the symbolic link – Rand Random Mar 12 '20 at 09:44

0 Answers0