2010-07-23 19 views
6

Pasé mucho tiempo tratando de encontrar una buena manera de incrustar cualquier archivo en Microsoft Word usando OpenXML 2.0; Los documentos de Office son bastante fáciles pero ¿qué pasa con otros tipos de archivos como PDF, TXT, GIF, JPG, HTML, etc.?¿Cómo puedo incrustar cualquier tipo de archivo en Microsoft Word usando OpenXml 2.0

¿Cuál es una buena manera de hacer que esto funcione para cualquier tipo de archivo, en C#?

+2

Nota para los implementadores del siguiente código: utiliza Interop, por lo que no es una solución pura de Open XML SDK. –

Respuesta

18

incrustación de objetos extraños (PDF, TXT, GIF, etc ...) en Microsoft Word utilizando OpenXml 2.0 (Bueno, en colaboración con el COM)

Tengo un montón de este sitio, así que aquí le pregunté y respondí mi propia pregunta para volver un poco sobre un tema en el que tuve dificultades para encontrar respuestas, espero que ayude a las personas.

Hay varios ejemplos por ahí que muestran cómo incrustar un documento de Office en otro documento de Office utilizando OpenXml 2.0, lo que no está ahí fuera y fácilmente comprensible es cómo insertar casi cualquier archivo en y documento de Office.

He aprendido mucho del código de otras personas, así que este es mi intento de contribuir. Como ya estoy usando OpenXml para generar documentos, y necesito incrustar otros archivos en Word, he decidido utilizar una colaboración de OpenXml y COM (Microsoft Office 2007 dll) para lograr mi objetivo. Si eres como yo, "invocar la aplicación del servidor OLE para crear un IStorage" no significa mucho para ti.

En este ejemplo, me gustaría mostrar cómo utilizo COM para obtener progresmáticamente la información de datos OLE-binary del archivo adjunto, y luego cómo usé esa información en mi documento OpenXml. Básicamente, estoy mirando programáticamente OpenXml 2.0 Document Reflector para obtener la información que necesito.

Mi código de abajo se divide en varias clases, pero aquí es un esbozo de lo que estoy haciendo:

  1. Crear una WordProcessingDocument OpenXml, obtener el System.IO.FileInfo para el archivo que desea incrustar
  2. crear un objeto OpenXmlEmbeddedObject personalizada (esto es lo que mantiene todos los datos binarios)
  3. uso de los datos binarios desde el paso anterior para crear datos e imagen Streams
  4. usar esas corrientes como el objeto de archivo y archivo de la imagen de tu OpenXml Documento

Sé que hay una gran cantidad de código, y no mucho explicación ... Es de esperar que es fácil de seguir y ayudará a la gente a cabo 

Requisitos: • DocumentFormat.OpenXml DLL (OpenXml 2.0) • WindowsBase dll • Microsoft.Office.Interop.DLL Word (Office 2007 - Versión 12)

• Este la clase principal que comienza todo, se abre una WordProcessingDocument y clase a tener el archivo adjunto

using DocumentFormat.OpenXml.Packaging; 
using System.IO; 
using DocumentFormat.OpenXml; 
using DocumentFormat.OpenXml.Wordprocessing; 

public class MyReport 
{ 
    private MainDocumentPart _mainDocumentPart; 

    public void CreateReport() 
    { 
     using (WordprocessingDocument wpDocument = WordprocessingDocument.Create(@"TempPath\MyReport.docx", WordprocessingDocumentType.Document)) 
     { 
      _mainDocumentPart = wpDocument.AddMainDocumentPart(); 
      _mainDocumentPart.Document = new Document(new Body()); 

      AttachFile(@"MyFilePath\MyFile.pdf", true); 
     } 
    } 

    private void AttachFile(string filePathAndName, bool displayAsIcon) 
    { 
     FileInfo fileInfo = new FileInfo(filePathAndName); 

     OpenXmlHelper.AppendEmbeddedObject(_mainDocumentPart, fileInfo, displayAsIcon); 
    } 
} 

• Esta clase en una clase de ayuda OpenXml , tiene toda la lógica para incrustar un objeto en el archivo de OpenXml

using DocumentFormat.OpenXml; 
using DocumentFormat.OpenXml.Packaging; 
using DocumentFormat.OpenXml.Validation; 
using DocumentFormat.OpenXml.Wordprocessing; 
using OVML = DocumentFormat.OpenXml.Vml.Office; 
using V = DocumentFormat.OpenXml.Vml; 

public class OpenXmlHelper 
{ 
    /// <summary> 
    /// Appends an Embedded Object into the specified Main Document 
    /// </summary> 
    /// <param name="mainDocumentPart">The MainDocument Part of your OpenXml Word Doc</param> 
    /// <param name="fileInfo">The FileInfo object associated with the file being embedded</param> 
    /// <param name="displayAsIcon">Whether or not to display the embedded file as an Icon (Otherwise it will display a snapshot of the file)</param> 
    public static void AppendEmbeddedObject(MainDocumentPart mainDocumentPart, FileInfo fileInfo, bool displayAsIcon) 
    { 
     OpenXmlEmbeddedObject openXmlEmbeddedObject = new OpenXmlEmbeddedObject(fileInfo, displayAsIcon); 

     if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleObjectBinaryData)) 
     { 
      using (Stream dataStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleObjectBinaryData))) 
      { 
       if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleImageBinaryData)) 
       { 
        using (Stream emfStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleImageBinaryData))) 
        { 
         string imagePartId = GetUniqueXmlItemID(); 
         ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Emf, imagePartId); 

         if (emfStream != null) 
         { 
          imagePart.FeedData(emfStream); 
         } 

         string embeddedPackagePartId = GetUniqueXmlItemID(); 

         if (dataStream != null) 
         { 
          if (openXmlEmbeddedObject.ObjectIsOfficeDocument) 
          { 
           EmbeddedPackagePart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedPackagePart>(
            openXmlEmbeddedObject.FileContentType, embeddedPackagePartId); 
           embeddedObjectPart.FeedData(dataStream); 
          } 
          else 
          { 
           EmbeddedObjectPart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedObjectPart>(
            openXmlEmbeddedObject.FileContentType, embeddedPackagePartId); 
           embeddedObjectPart.FeedData(dataStream); 
          } 
         } 

         if (!displayAsIcon && !openXmlEmbeddedObject.ObjectIsPicture) 
         { 
          Paragraph attachmentHeader = CreateParagraph(String.Format("Attachment: {0} (Double-Click to Open)", fileInfo.Name)); 
          mainDocumentPart.Document.Body.Append(attachmentHeader); 
         } 

         Paragraph embeddedObjectParagraph = GetEmbeededObjectParagraph(openXmlEmbeddedObject.FileType, 
          imagePartId, openXmlEmbeddedObject.OleImageStyle, embeddedPackagePartId); 

         mainDocumentPart.Document.Body.Append(embeddedObjectParagraph); 
        } 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Gets Paragraph that includes the embedded object 
    /// </summary> 
    private static Paragraph GetEmbeededObjectParagraph(string fileType, string imageID, string imageStyle, string embeddedPackageID) 
    { 
     EmbeddedObject embeddedObject = new EmbeddedObject(); 

     string shapeID = GetUniqueXmlItemID(); 
     V.Shape shape = new V.Shape() { Id = shapeID, Style = imageStyle }; 
     V.ImageData imageData = new V.ImageData() { Title = "", RelationshipId = imageID }; 

     shape.Append(imageData); 
     OVML.OleObject oleObject = new OVML.OleObject() 
     { 
      Type = OVML.OleValues.Embed, 
      ProgId = fileType, 
      ShapeId = shapeID, 
      DrawAspect = OVML.OleDrawAspectValues.Icon, 
      ObjectId = GetUniqueXmlItemID(), 
      Id = embeddedPackageID 
     }; 

     embeddedObject.Append(shape); 
     embeddedObject.Append(oleObject); 

     Paragraph paragraphImage = new Paragraph(); 

     Run runImage = new Run(embeddedObject); 
     paragraphImage.Append(runImage); 

     return paragraphImage; 
    } 

    /// <summary> 
    /// Gets a Unique ID for an XML Item, for reference purposes 
    /// </summary> 
    /// <returns>A GUID string with removed dashes</returns> 
    public static string GetUniqueXmlItemID() 
    { 
     return "r" + System.Guid.NewGuid().ToString().Replace("-", ""); 
    } 

    private static Paragraph CreateParagraph(string paragraphText) 
    { 
     Paragraph paragraph = new Paragraph(); 
     ParagraphProperties paragraphProperties = new ParagraphProperties(); 

     paragraphProperties.Append(new Justification() 
     { 
      Val = JustificationValues.Left 
     }); 

     paragraphProperties.Append(new SpacingBetweenLines() 
     { 
      After = Convert.ToString(100), 
      Line = Convert.ToString(100), 
      LineRule = LineSpacingRuleValues.AtLeast 
     }); 

     Run run = new Run(); 
     RunProperties runProperties = new RunProperties(); 

     Text text = new Text(); 

     if (!String.IsNullOrEmpty(paragraphText)) 
     { 
      text.Text = paragraphText; 
     } 

     run.Append(runProperties); 
     run.Append(text); 

     paragraph.Append(paragraphProperties); 
     paragraph.Append(run); 

     return paragraph; 
    } 

} 

• Esta es la parte más importante de este proceso, está utilizando el servidor OLE interno de Microsoft, crea los datos binarios y la información EMF binaria para un archivo. Todo lo que tiene que hacer aquí es llamar al constructor OpenXmlEmbeddedObject y todos se preocupan. Imita el proceso que se lleva a cabo cuando arrastra manualmente cualquier archivo a Word; hay algún tipo de conversión que continúa cuando lo hace, convirtiendo el archivo en un objeto OLE, para que Microsoft pueda reconocer el archivo. o Las partes más importantes de esta clase son las propiedades OleObjectBinaryData y OleImageBinaryData; contienen la información binaria de la cadena de 64 bits para los datos del archivo y la imagen '.emf'. o Si decide no mostrar el archivo como un ícono, los datos de imagen '.emf' crearán una instantánea del archivo, como la primera página del archivo pdf, por ejemplo, en la que aún puede hacer doble clic para abierta o Si está incrustando una imagen y elige no mostrar como un icono, a continuación, las propiedades OleObjectBinaryData y OleImageBinaryData será el mismo

using System.Runtime.InteropServices; 
using System.Xml; 
using System.Diagnostics; 
using System.IO; 
using System.Drawing; 
using Microsoft.Office.Interop.Word; 

public class OpenXmlEmbeddedObject 
{ 
    #region Constants 

    private const string _defaultOleContentType = "application/vnd.openxmlformats-officedocument.oleObject"; 
    private const string _oleObjectDataTag = "application/vnd"; 
    private const string _oleImageDataTag = "image/x-emf"; 

    #endregion Constants 

    #region Member Variables 

    private static FileInfo _fileInfo; 
    private static string _filePathAndName; 
    private static bool _displayAsIcon; 
    private static bool _objectIsPicture; 

    private object _objectMissing = System.Reflection.Missing.Value; 
    private object _objectFalse = false; 
    private object _objectTrue = true; 

    #endregion Member Variables 

    #region Properties 

    /// <summary> 
    /// The File Type, as stored in Registry (Ex: a GIF Image = 'giffile') 
    /// </summary> 
    public string FileType 
    { 
     get 
     { 
      if (String.IsNullOrEmpty(_fileType) && _fileInfo != null) 
      { 
       _fileType = GetFileType(_fileInfo, false); 
      } 

      return _fileType; 
     } 
    } 
    private string _fileType; 

    /// <summary> 
    /// The File Context Type, as storered in Registry (Ex: a GIF Image = 'image/gif') 
    /// * Is converted into the 'Default Office Context Type' for non-office files 
    /// </summary> 
    public string FileContentType 
    { 
     get 
     { 
      if (String.IsNullOrEmpty(_fileContentType) && _fileInfo != null) 
      { 
       _fileContentType = GetFileContentType(_fileInfo); 

       if (!_fileContentType.Contains("officedocument")) 
       { 
        _fileContentType = _defaultOleContentType; 
       } 
      } 

      return _fileContentType; 
     } 
    } 
    private string _fileContentType; 

    /// <summary> 
    /// Gets the ContentType Text for the file 
    /// </summary> 
    public static string GetFileContentType(FileInfo fileInfo) 
    { 
     if (fileInfo == null) 
     { 
      throw new ArgumentNullException("fileInfo"); 
     } 

     string mime = "application/octetstream"; 

     string ext = System.IO.Path.GetExtension(fileInfo.Name).ToLower(); 

     Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext); 

     if (rk != null && rk.GetValue("Content Type") != null) 
     { 
      mime = rk.GetValue("Content Type").ToString(); 
     } 

     return mime; 
    } 

    public bool ObjectIsOfficeDocument 
    { 
     get { return FileContentType != _defaultOleContentType; } 
    } 

    public bool ObjectIsPicture 
    { 
     get { return _objectIsPicture; } 
    } 

    public string OleObjectBinaryData 
    { 
     get { return _oleObjectBinaryData; } 
     set { _oleObjectBinaryData = value; } 
    } 
    private string _oleObjectBinaryData; 

    public string OleImageBinaryData 
    { 
     get { return _oleImageBinaryData; } 
     set { _oleImageBinaryData = value; } 
    } 
    private string _oleImageBinaryData; 

    /// <summary> 
    /// The OpenXml information for the Word Application that is created (Make-Shoft Code Reflector) 
    /// </summary> 
    public string WordOpenXml 
    { 
     get { return _wordOpenXml; } 
     set { _wordOpenXml = value; } 
    } 
    private String _wordOpenXml; 

    /// <summary> 
    /// The XmlDocument that is created based on the OpenXml Data from WordOpenXml 
    /// </summary> 
    public XmlDocument OpenXmlDocument 
    { 
     get 
     { 
      if (_openXmlDocument == null && !String.IsNullOrEmpty(WordOpenXml)) 
      { 
       _openXmlDocument = new XmlDocument(); 
       _openXmlDocument.LoadXml(WordOpenXml); 
      } 

      return _openXmlDocument; 
     } 
    } 
    private XmlDocument _openXmlDocument; 

    /// <summary> 
    /// The XmlNodeList, for all Nodes containing 'binaryData' 
    /// </summary> 
    public XmlNodeList BinaryDataXmlNodesList 
    { 
     get 
     { 
      if (_binaryDataXmlNodesList == null && OpenXmlDocument != null) 
      { 
       _binaryDataXmlNodesList = OpenXmlDocument.GetElementsByTagName("pkg:binaryData"); 
      } 

      return _binaryDataXmlNodesList; 
     } 
    } 
    private XmlNodeList _binaryDataXmlNodesList; 

    /// <summary> 
    /// Icon Object for the file 
    /// </summary> 
    public Icon ObjectIcon 
    { 
     get 
     { 
      if (_objectIcon == null) 
      { 
       _objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName); 
      } 

      return _objectIcon; 
     } 
    } 
    private Icon _objectIcon; 

    /// <summary> 
    /// File Name for the Icon being created 
    /// </summary> 
    public string ObjectIconFile 
    { 
     get 
     { 
      if (String.IsNullOrEmpty(_objectIconFile)) 
      { 
       _objectIconFile = String.Format("{0}.ico", _filePathAndName.Replace(".", "")); 
      } 

      return _objectIconFile; 
     } 
    } 
    private string _objectIconFile; 

    /// <summary> 
    /// Gets the original height and width of the emf file being created 
    /// </summary> 
    public string OleImageStyle 
    { 
     get 
     { 
      if (String.IsNullOrEmpty(_oleImageStyle) && !String.IsNullOrEmpty(WordOpenXml)) 
      { 
       XmlNodeList xmlNodeList = OpenXmlDocument.GetElementsByTagName("v:shape"); 
       if (xmlNodeList != null && xmlNodeList.Count > 0) 
       { 
        foreach (XmlAttribute attribute in xmlNodeList[0].Attributes) 
        { 
         if (attribute.Name == "style") 
         { 
          _oleImageStyle = attribute.Value; 
         } 
        } 
       } 
      } 

      return _oleImageStyle; 
     } 

     set { _oleImageStyle = value; } 
    } 
    private string _oleImageStyle; 

    #endregion Properties 

    #region Constructor 

    /// <summary> 
    /// Generates binary information for the file being passed in 
    /// </summary> 
    /// <param name="fileInfo">The FileInfo object for the file to be embedded</param> 
    /// <param name="displayAsIcon">Whether or not to display the file as an Icon (Otherwise it will show a snapshot view of the file)</param> 
    public OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon) 
    { 
     _fileInfo = fileInfo; 
     _filePathAndName = fileInfo.ToString(); 
     _displayAsIcon = displayAsIcon; 

     SetupOleFileInformation(); 
    } 

    #endregion Constructor 

    #region Methods 

    /// <summary> 
    /// Creates a temporary Word App in order to add an OLE Object, get's the OpenXML data from the file (similar to the Code Reflector info) 
    /// </summary> 
    private void SetupOleFileInformation() 
    { 
     Microsoft.Office.Interop.Word.Application wordApplication = new Microsoft.Office.Interop.Word.Application(); 

     Microsoft.Office.Interop.Word.Document wordDocument = wordApplication.Documents.Add(ref _objectMissing, ref _objectMissing, 
      ref _objectMissing, ref _objectMissing); 

     object iconObjectFileName = _objectMissing; 
     object objectClassType = FileType; 
     object objectFilename = _fileInfo.ToString(); 

     Microsoft.Office.Interop.Word.InlineShape inlineShape = null; 

     if (_displayAsIcon) 
     { 
      if (ObjectIcon != null) 
      { 
       using (FileStream iconStream = new FileStream(ObjectIconFile, FileMode.Create)) 
       { 
        ObjectIcon.Save(iconStream); 
        iconObjectFileName = ObjectIconFile; 
       } 
      } 

      object objectIconLabel = _fileInfo.Name; 

      inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType, 
       ref objectFilename, ref _objectFalse, ref _objectTrue, ref iconObjectFileName, 
       ref _objectMissing, ref objectIconLabel, ref _objectMissing); 
     } 
     else 
     { 
      try 
      { 
       Image image = Image.FromFile(_fileInfo.ToString()); 
       _objectIsPicture = true; 
       OleImageStyle = String.Format("height:{0}pt;width:{1}pt", image.Height, image.Width); 

       wordDocument.InlineShapes.AddPicture(_fileInfo.ToString(), ref _objectMissing, ref _objectTrue, ref _objectMissing); 
      } 
      catch 
      { 
       inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType, 
        ref objectFilename, ref _objectFalse, ref _objectFalse, ref _objectMissing, ref _objectMissing, 
        ref _objectMissing, ref _objectMissing); 
      } 
     } 

     WordOpenXml = wordDocument.Range(ref _objectMissing, ref _objectMissing).WordOpenXML; 

     if (_objectIsPicture) 
     { 
      OleObjectBinaryData = GetPictureBinaryData(); 
      OleImageBinaryData = GetPictureBinaryData(); 
     } 
     else 
     { 
      OleObjectBinaryData = GetOleBinaryData(_oleObjectDataTag); 
      OleImageBinaryData = GetOleBinaryData(_oleImageDataTag); 
     } 

     // Not sure why, but Excel seems to hang in the processes if you attach an Excel file… 
     // This kills the excel process that has been started < 15 seconds ago (so not to kill the user's other Excel processes that may be open) 
     if (FileType.StartsWith("Excel")) 
     { 
      Process[] processes = Process.GetProcessesByName("EXCEL"); 
      foreach (Process process in processes) 
      { 
       if (DateTime.Now.Subtract(process.StartTime).Seconds <= 15) 
       { 
        process.Kill(); 
        break; 
       } 
      } 
     } 

     wordDocument.Close(ref _objectFalse, ref _objectMissing, ref _objectMissing); 
     wordApplication.Quit(ref _objectMissing, ref _objectMissing, ref _objectMissing); 
    } 

    /// <summary> 
    /// Gets the binary data from the Xml File that is associated with the Tag passed in 
    /// </summary> 
    /// <param name="binaryDataXmlTag">the Tag to look for in the OpenXml</param> 
    /// <returns></returns> 
    private string GetOleBinaryData(string binaryDataXmlTag) 
    { 
     string binaryData = null; 
     if (BinaryDataXmlNodesList != null) 
     { 
      foreach (XmlNode xmlNode in BinaryDataXmlNodesList) 
      { 
       if (xmlNode.ParentNode != null) 
       { 
        foreach (XmlAttribute attr in xmlNode.ParentNode.Attributes) 
        { 
         if (String.IsNullOrEmpty(binaryData) && attr.Value.Contains(binaryDataXmlTag)) 
         { 
          binaryData = xmlNode.InnerText; 
          break; 
         } 
        } 
       } 
      } 
     } 

     return binaryData; 
    } 

    /// <summary> 
    /// Gets the image Binary data, if the file is an image 
    /// </summary> 
    /// <returns></returns> 
    private string GetPictureBinaryData() 
    { 
     string binaryData = null; 
     if (BinaryDataXmlNodesList != null) 
     { 
      foreach (XmlNode xmlNode in BinaryDataXmlNodesList) 
      { 
       binaryData = xmlNode.InnerText; 
       break; 
      } 
     } 

     return binaryData; 
    } 

    /// <summary> 
    /// Gets the file type description ("Application", "Text Document", etc.) for the file. 
    /// </summary> 
    /// <param name="fileInfo">FileInfo containing extention</param> 
    /// <returns>Type Description</returns> 
    public static string GetFileType(FileInfo fileInfo, bool returnDescription) 
    { 
     if (fileInfo == null) 
     { 
      throw new ArgumentNullException("fileInfo"); 
     } 

     string description = "File"; 
     if (string.IsNullOrEmpty(fileInfo.Extension)) 
     { 
      return description; 
     } 
     description = string.Format("{0} File", fileInfo.Extension.Substring(1).ToUpper()); 
     RegistryKey typeKey = Registry.ClassesRoot.OpenSubKey(fileInfo.Extension); 
     if (typeKey == null) 
     { 
      return description; 
     } 
     string type = Convert.ToString(typeKey.GetValue(string.Empty)); 
     RegistryKey key = Registry.ClassesRoot.OpenSubKey(type); 
     if (key == null) 
     { 
      return description; 
     } 

     if (returnDescription) 
     { 
      description = Convert.ToString(key.GetValue(string.Empty)); 
      return description; 
     } 
     else 
     { 
      return type; 
     } 
    } 

    #endregion Methods 
} 
+0

Existe una posible bug @ línea 263. Las rutas relacionales de archivos causarán un error y una ventana emergente de Word. "object objectFilename = _fileInfo.ToString();" debería leer "object objectFilename = _fileInfo.FullName;" en lugar. – bic

+0

¿Tiene alguna idea de cómo editar el objeto incrustado de Excel? Cuando hago doble clic en él, abre un nuevo programa de Excel donde puedo editarlo, pero nunca actualiza el documento original de Word. Gracias. – jn1kk

+0

Este es un buen ejemplo, pero ¿qué ocurre si tengo que hacer una búsqueda inversa (preferiblemente una imagen) de dichos objetos incrustados? – serene

0

Mi respuesta here se decir cómo hacer esto, pero no muestra con el SDK o un idioma específico.

0
_objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName); 

parece estar roto, pero

_objectIcon = System.Drawing.Icon.ExtractAssociatedIcon(_filePathAndName); 

también debería funcionar.

0

Esta es una gran respuesta y que me ha ayudado mucho, pero el error potencial que menciona bic usuario también existe

en

OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon) 

en la línea 242,

_filePathAndName = fileInfo.ToString(); 

en

SetupOleFileInformation() 

en la línea 264,

object objectFilename = _fileInfo.ToString(); 

línea 289, y

Image image = Image.FromFile(_fileInfo.ToString()); 

línea 293

wordDocument.InlineShapes.AddPicture(_fileInfo.toString(), ref _objectMissing, ref _objectTrue, ref _objectMissing); 

Todos estos necesidad de ser "FullName" en lugar de "ToString()" si el el código debería funcionar con rutas relativas también. Espero que esto ayude a cualquiera que quiera usar el código de D Lyonnais.

Cuestiones relacionadas