Embedding Documents in Word 2007 by Using the Open XML SDK 2.0 for Microsoft Office

Summary:  Learn how to use the Open XML Software Development Kit 2.0 for Microsoft Office to embed a Word 2007 document programmatically into another Word 2007 document. (14 printed pages)

Office Visual How To

Applies to:  Open XML SDK 2.0 for Microsoft Office, 2007 Microsoft Office System, Microsoft Office Word 2007

Joel Krist, iSoftStone

August 2009

Overview

The Open XMLSoftware Development Kit 2.0 for Microsoft Office makes it possible to create and manipulate Microsoft Office Word 2007, Microsoft Office Excel 2007, and Microsoft Office PowerPoint 2007 documents programmatically via the Open XML formats. The typesafe classes included with the SDK provide a layer of abstraction between the developer and the Open XML formats, simplifying the process of working with Office 2007 documents and enabling the creation of solutions that are not dependent on the presence of the Office client applications to handle document creation.

The sample code in this visual how-to article shows how to programmatically create a Word 2007 document that has a Word 2007 document embedded in it. The code uses the EmbeddedPackagePart, EmbeddedObject, and ImagePart classes from the Open XML SDK 2.0 for Microsoft Office to create the required document parts.

See It Video startup screen

Watch the Video

Length: 07:51 | Size: 11.60 MB | Type: WMV file

Code It | Read It | Explore It

Code It

Download the sample code

This visual how-to article presents a solution that creates a Word 2007 document, which itself contains another embedded Word 2007 document. The resulting document is similar to the document that you create when you manually insert an existing Word document into another Word document by using the Insert Object dialog box. At the end of that process, Word 2007 displays the embedded document as an icon in the document that contains it.

Figure 1. Inserting a document using the Object dialog box

Inserting a document using the Object dialog box

 

To illustrate how to programmatically create a Word 2007 document that has a Word 2007 document embedded in it, this section walks through the following steps:

  1. Creating a Windows console application solution in Visual Studio 2008.

  2. Adding references to the DocumentFormat.OpenXml and WindowsBase assemblies.

  3. Adding the sample code to the solution.

Creating a Windows Console Application in Visual Studio 2008

This visual how-to article uses a Windows console application to provide the framework for the sample code. However, you could use the same approach that is illustrated here with other application types as well.

To create a Windows Console Application in Visual Studio 2008

  1. Start Microsoft Visual Studio 2008.

  2. On the File menu, point to New, and then click Project.

  3. In the New Project dialog box select the Visual C# Windows type in the Project types pane.

  4. Select Console Application in the Templates pane, and then name the project EmbedDocument.

    Figure 2. Create new solution in the New Project dialog box

    Create new solution in the New Project dialog box

     

  5. Click OK to create the solution.

Adding References to the DocumentFormat.OpenXml and WindowsBase Assemblies

The sample code uses the classes and enumerations that are in the DocumentFormat.OpenXml.dll assembly that is installed with the Open XML SDK 2.0 for Microsoft Office. To add the reference to the assembly in the following steps or to build the sample code that accompanies this visual how-to, you must first download and install the Open XML SDK 2.0 for Microsoft Office so that the assembly is available.

To add References to the DocumentFormat.OpenXml and WindowsBase Assemblies

  1. Add a reference to the DocumentFormat.OpenXml assembly by doing the following:

    1. On the Project menu in Visual Studio, click Add Reference to open the Add Reference dialog box.

    2. Select the .NET tab, scroll down to DocumenFormat.OpenXml, select it, and then click OK.

      Figure 3. Add Reference to DocumentFormat.OpenXML

      Add Reference to DocumentFormat.OpenXML

       

  2. The classes in the DocumentFormat.OpenXml assembly use the System.IO.Packaging.Package class that is defined in the WindowsBase assembly. Add a reference to the WindowsBase assembly by doing the following:

    1. On the Project menu in Visual Studio, click Add Reference to open the Add Reference dialog box.

    2. Select the .NET tab, scroll down to WindowsBase, select it, and then click OK.

      Figure 4. Add Reference to WindowsBase

      Add Reference to WindowsBase

       

Adding the Sample Code to the Solution

Replace the contents of the Program.cs source file with the following code.

using System;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using v = DocumentFormat.OpenXml.Vml;
using ovml = DocumentFormat.OpenXml.Vml.Office;
using System.IO;

class Program
{
  static void Main(string[] args)
  {
    string containingDocumentPath =
      @"C:\Temp\ContainingDocument.docx";

    string embeddedDocumentPath =
      @"C:\Temp\EmbeddedDocument.docx";

    CreatePackage(containingDocumentPath,
      embeddedDocumentPath);
  }

  private static void CreatePackage(string containingDocumentPath,
    string embeddedDocumentPath)
  {
    using (WordprocessingDocument package =
      WordprocessingDocument.Create(containingDocumentPath,
        WordprocessingDocumentType.Document))
    {
      AddParts(package, embeddedDocumentPath);
    }
  }

  private static void AddParts(WordprocessingDocument parent,
    string embeddedDocumentPath)
  {
    var mainDocumentPart = parent.AddMainDocumentPart();
    GenerateMainDocumentPart().Save(mainDocumentPart);

    var embeddedPackagePart =
      mainDocumentPart.AddNewPart<EmbeddedPackagePart>(
      "application/vnd.openxmlformats-" +
      "officedocument.wordprocessingml.document",
      "rId1");

    GenerateEmbeddedPackagePart(embeddedPackagePart,
      embeddedDocumentPath);

    var imagePart =
      mainDocumentPart.AddNewPart<ImagePart>(
      "image/x-emf", "rId2");

    GenerateImagePart(imagePart);
  }

  private static Document GenerateMainDocumentPart()
  {
    var element =
      new Document(
        new Body(
          new Paragraph(
            new Run(
              new Text(
                "This is the containing document."))),
          new Paragraph(
            new Run(
              new Text(
                "This is the embedded document: "))),
          new Paragraph(
            new Run(
              new EmbeddedObject(
                new v.Shape(
                  new v.ImageData()
                  {
                    Title = "",
                    RelationshipId = "rId2"
                  }
                )
                {
                  Id = "_x0000_i1025",
                  Style = "width:76.5pt;height:49.5pt",
                  Ole = v.BooleanEntryWithBlankValues.Empty
                },
                new ovml.OleObject()
                {
                  Type = ovml.OLEValues.Embed,
                  ProgId = "Word.Document.12",
                  ShapeId = "_x0000_i1025",
                  DrawAspect = ovml.OLEDrawAspectValues.Icon,
                  ObjectId = "_1299573545",
                  Id = "rId1"
                }
              )
              {
                DxaOriginal = (UInt32Value)1531UL,
                DyaOriginal = (UInt32Value)991UL
              }
            )
          )
        )
      );

    return element;
  }

  public static void GenerateEmbeddedPackagePart(OpenXmlPart part,
    string embeddedDocumentPath)
  {
    byte[] embeddedDocumentBytes;

    // The following code will generate an exception if an invalid
    // filename is passed.
    using (FileStream fsEmbeddedDocument =
      File.OpenRead(embeddedDocumentPath))
    {
      embeddedDocumentBytes =
        new byte[fsEmbeddedDocument.Length];

      fsEmbeddedDocument.Read(embeddedDocumentBytes, 0,
        embeddedDocumentBytes.Length);
    }

    using (BinaryWriter writer =
      new BinaryWriter(part.GetStream()))
    {
      writer.Write(embeddedDocumentBytes);
      writer.Flush();
    }
  }

  public static void GenerateImagePart(OpenXmlPart part)
  {
    #region Icon Bytes

    // Best practice is that this icon should be stored as a resource
    // in the assembly instead of as a Base64 string.

    string iconBytes = @"
    AQAAAGwAAAAAAAAAAQAAAGQAAAAuAAAAAAAAAAAAAAAODgAAGAkAACBFTUYAAAEAbBQ
    AABAAAAACAAAAAAAAAAAAAAAAAAAAQAYAALAEAAA0AgAApwEAAAAAAAAAAAAAAAAAAN
    ycCACldQYAGAAAAAwAAAAAAAAAGQAAAAwAAAD///8AcgAAAKAQAAAjAAAAAQAAAEIAA
    AAgAAAAIwAAAAEAAAAgAAAAIAAAAACA/wEAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8A
    AAAAAAAAAP///wAAAAAAbAAAADQAAACgAAAAABAAACAAAAAgAAAAKAAAACAAAAAgAAA
    AAQAgAAMAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAA/wAA/wAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuaSV/5F8av9
    4YUz/alM8/2ZON/9iSjL/YEgw/2BIMP9gSDD/YEgw/2BIMP9gSDD/YEgw/2BIMP9gSD
    D/YEgw/2BIMP9gSDD/YEgw/2BIMP9gSDD/YEgw/2BIMP9gSDD/YEgw/wAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAC6pZb//Orf/9/NxP/dxbf/3r2s/964ov/jspj/5bOQ
    /+WzkP/ls5D/5bKO/+awi//nr4j/6a2F/+qsgv/rqn//7Kd7/+6ld//vo3P/8aFv//G
    ga//znmj/851l//SbY/9gSDD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqllv
    /86+H//Ovh//zr4f/86+D/++rf//vp3//76d7/++nd//ro3P/759z/+uba//rm2f/65
    df/+uTW//rj1P/64tP/+eDS//ngz//53s7/+d3M//ncyv/528j/9Jxl/2BIMP8AAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu6aX//zu5P/77eT//O3k//vs5P/77OP//Ov
    i//vr4v/76+D/++rf//vp3//76d3/++jc//rn2v/65tr/+uTY//rk1v/54tT/+uHT//
    rg0f/538//+d7N//ncyv/znWf/YEgw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AC7p5j//O/n//zv5//77+b//O/m//zv5v/87eX//O3k//zt5P/87OP//Ovi//zq4f/8
    6t//++re//vo3P/759v/+uba//rl1//65NX/+uLT//nh0f/64ND/+t/O//Keav9gSDD
    /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyomP/88er//PHp//zx6v/88On//P
    Dp//zw6P/97+j//O/n//zu5v/87uX//O3k//zs4//87OH/06mL/9Koif/Rpof/0aWG/
    9CkhP/Po4P/+uPV//rh0v/64ND/8aBt/2BIMP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAvama//3z7f/98+3//fPs//3y7P/98+v//fLr//zy6v/98er//fHp//zw6P/
    87+f//O7m//zt5P/87eP//Ovh//vq3//76d3/++jc//rm2f/65Nf/+uPW//ri0//won
    D/YEgw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC+qpv//fXv//307//jwaj/4
    r+l/+G9o//fu6H/3rme/923nP/btZr/2rOX/9mxlf/YsJP/166R/9asj//Vq43/1KmL
    /9Koif/Spoj/0aWG//vn2v/65dj/+uPW/++jc/9gSDD/AAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAL+rnP/+9vH//fbx//328f/99vH//fbx//718P/99fD//fXw//307/
    /98+7//fPt//3y7P/88er//PDp//zv5//87uX//O3k//zr4v/86t//++jd//vn2v/65
    dj/7aV3/2BIMP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwKye//348//99/P/
    5sWt/+XDq//jwaj/4b6l/+C8ov/euqD/3rmf/923nP/ctpr/2rSY/9mylv/YsJP/166
    R/9atj//Vq43/1KqL/9Ooiv/76uD/++nd//vn2//tp3v/YEgw/wAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAADBrp7//vn1//759f/++fX//vj1//749f/++PX//vj1//339
    P/+9/P//vfz//338v/99vH//fXw//307v/98+3//PLr//zx6f/87+f//O7k//vs4v/7
    6uD/++jd/+upf/9gSDD/AAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAMKun//++vf
    //vr3/+jJsf/nx6//5sWt/+XDq//jwqj/4sCm/+G+pP/gvKH/3rqf/924nP/ctpr/2r
    SY/9mylv/YsJT/166R/9atj//Vq47//O7l//zs4//76t//6auD/2BIMP8AAAAAAAAAA
    AAAAAAAAAABAAAABQAAAA0AAAAUrpyP/9/c2f/b2NX/1dHO/9DLyv/JxcP/xcG//8rG
    xP/Oysj/8ezp//v28//9+PX//vj1//749P/+9/P//fbx//318P/99O3//fLr//zx6f/
    87+f//O3k//zs4v/orof/YEgw/wAAAAAAAAAAAAAAAQAAAAMAAAAOAAAAIgAAADWQgX
    b/tLGv/62rqf+TfGv/mIN0/6KQgv+3p5n/yrus/8Ksmf+6oY//3bqh/+C9o//gvKL/3
    rqf/924nf/ctpv/27SY/9mylv/YsJT/16+S//zx6f/97+f//O3k/+avi/9gSDD/AAAA
    AAAAAABuOSXAczwnzWw4JNF5VEbekHpw6q+dlv/FuLL/3tbS//Xx7P/8+PP/+/bv//n
    06//48uf/vqmb/9jW1P/r6Ob//fr4//77+f/++vj//vn2//749f/99/P//fbx//307/
    /98+3//fLr//3w6P/87ub/5bGP/2BIMP8AAAAAAAAAAIxLMPDeuar/vpqL/9Gmlf///
    //////////////+/vz//vz6//369v/8+PP/+/bv//n06//Bqpz/v6OO/9KznP/jwaj/
    4sCn/+G+pP/gvKL/37qg/924nf/ctpv/27SY/9qzlv/98+3//PHq//zw6P/ls5L/YEg
    w/wAAAAAAAAAAjk0z8Nq2qf+xclj/0720///////68vD/6MS9///////z4t3/2Z6T//
    369v/8+PP/+/bv/828sP/U0tL/6+no//78+//+/Pv//vz6//77+f/++vj//vn2//749
    P/99/P//fbx//307v/98u3//fHq/+S1lv9gSDD/AAAAAAAAAACQUDbw2bWm/6RTMf+4
    jXv///////nx7/+3XEX/9+3q//Hg3P+zVDv/7NTN//369v/8+PP/2MvB/9HPz//q6Oj
    //vz8///9/P/OoYH/zqGB/86hgf/OoYH/zqGB/86hgf/OoYH//vXw//307v/98uz/4r
    ea/2BIMP8AAAAAAAAAAJJSOfDYtKT/ok8s/6RoT////////v38/6RHJ/+/fWf/79/Z/
    6dNL/+5cln//Pj1//369v/j2NH/z87N/+no5//+/fz///38//PKqv/mvqL/58On/+e/
    pP/is5P/5LaX/86hgf/+9vH//fTv//3z7f/huZz/YEgw/wAAAAAAAAAAlFU88Nizpf+
    iTyz/kEUm////////////n0gk/8WQev/Il4P/oEon/9WwoP/Ooo///vz6//Dq5f/My8
    v/6Ofn//79/f///v3/88qq/9mpiP/fspL/5bmb/+Cxkv/kt5n/zqGB//728v/99vD//
    fPu/+G6n/9gSDD/AAAAAAAAAACWWD/w2LSl/6RPLf+LORb/8evp//////+lVTP/6dbO
    /7FrTv+fSSb//v38/69nSf/v4dn/+/j2/8nIyP/m5eX//fz8///+/f/zyqr/6cGl/+j
    DqP/mvqL/3q+O/+O4mf/OoYH//vfz//328f/99e//37uh/2BIMP8AAAAAAAAAAJlbQf
    Dmy8H/x451/7F3X//h1c//+/j3/6ZXNv/VsKD/7+Hc/6ZXNv//////wYly/7yAZ//+/
    vz/y8rK/+Xk5P/9/Pz///79//PKqv/049f/7NjK//v18P/kwqr/48Gn/+K/pf/eu6X/
    3rul/967pf/fvKP/YEgw/wAAAAAAAAAAm15E8OnQx//PmoX/vYZx/9bCuv/59PH/69j
    R/+zb1P/////////////////////////////////R0ND/5eTk//z7+////v3/88qq//
    359v/+/f3/69fJ/76snf+MdmP/iHJe/4FrV/96Y07/cltF/2pTPP9gSDD/AAAAAAAAA
    ACVXEPk59DG/9eql//IlH//z7Oo////////////////////////////////////////
    /////////+Df3//p6Oj//fz8///+/f/zyqr///////v07//049f/v62d/+zSv//qzrv
    /58q1/+TErv/hvqn/YEgw/yUkJCkAAAAAAAAAAG1EM6XVsKH/8N3W/9Sij//VsaL///
    ////////////////////38/P/x6eX/8+zq//Tv7v/cysL/9PPz//v6+v/+/f3///7+/
    /PKqv/zyqr/88qq//PKqv/Brp///+7k//vo3P/03tD/7tTD/2BIMP8lJCQpGBgXGgAA
    AAAAAAAAIBQPMKhrUfzkyL7/8uDa/9KllP/SpZT/0qWU/9Wol//XqZj/16mY/9iqmP/
    SpZT/0qWU/7WEbv/8+/v//v39///+/v///v7///79//7+/f///fz///37/8KwoP//7u
    T/++jc//Xe0P9lTjb/JSQkKRgYFxoAAAAAAAAAAAAAAAAAAAAAQSkgYKZrUvbUrp//9
    eXf//Tk3v/05N7/9OTe//Xl3//15d//9eXf//Xl3//15d//u4hz//79/f///v7///7+
    ///+/v///v3///39///9/P///fv/xLKj///u5P/76Nz/bFU+/yUkJCkYGBcaAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAFg4LIXFJOKWcZU3kr3JX/69yV/+vclf/r3JX/69yV/
    +vclf/r3JX/69yV/+9i3T///7+///+/v///v7///7+///+/v///v3///39///9/P/Gt
    KT//+7k/4NuWf8lJCQpGBgXGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAADRv7H////////////////////////////////////////////////////
    ////+/v////7///7+///+/v///f3///38/8i1pf+chnT/JSQkKRgYFxoAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANG/sf/Rv7H/0b+x/9G/s
    f/QvrD/z72v/8+9r//PvK7/zbut/827rP/Nuaz/zLmr/8u4qv/Kt6n/yreo/8m2p//I
    tqf/ybam/yUkJCkXFxcZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAYAAAADAAAAAAAAAISAAAADAAAAAEAAABSAAAAcAEAAAEA
    AAD1////AAAAAAAAAAAAAAAAkAEAAAAAAAAAQAAiVABhAGgAbwBtAGEAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT310CQ
    AA3LMCWf//AADy4QAAAABkWczmMADASrNZAAAAAAAAAADwtAoAAAAAAEkaZlkAAAAAv
    EqzWQAAAADLdGRZAACJAXznMAAAbI8BfOcwAAAAAAAAAAAAAAAAAAAAiQFcf0daBAAA
    AGzmMAAXdGRZAgAAAAFKT33o5TAAAAAAADD6MAA0mDN3BZtGCv7///8QTjd3IU83dwA
    AZFkAAAAAdAkAAMzmMAAAAAAAwOYwAPW4LnbA5jAAB7kudgAAZFkAAAAAAABkWQAAAA
    Dc5jAA3OYwACDnMAAhZR9YBQAAANzmMAAAbI8BfOcwAAAAAAAkAAAA3LMCWSA3A1lkd
    gAIAAAAACUAAAAMAAAAAQAAAFQAAAC0AAAAAAAAACIAAABkAAAALgAAAAEAAAAAAA1C
    AAANQgAAAAAiAAAAEQAAAEwAAAAEAAAAAAAAAAAAAABmAAAAQgAAAHAAAABFAG0AYgB
    lAGQAZABlAGQAIABEAG8AYwB1AG0AZQBuAHQAAAAGAAAACAAAAAYAAAAGAAAABgAAAA
    YAAAAGAAAABgAAAAMAAAAHAAAABgAAAAUAAAAGAAAACAAAAAYAAAAGAAAABAAAACUAA
    AAMAAAADQAAgEYAAAAgAAAAEgAAAEkAYwBvAG4ATwBuAGwAeQAAAAAARgAAADAAAAAk
    AAAARQBtAGIAZQBkAGQAZQBkACAARABvAGMAdQBtAGUAbgB0AAAARgAAAGAAAABUAAA
    AQwA6AFwAUABSAE8ARwBSAEEAfgAxAFwATQBJAEMAUgBPAFMAfgAxAFwATwBmAGYAaQ
    BjAGUAMQAyAFwAVwBJAE4AVwBPAFIARAAuAEUAWABFAAAARgAAABAAAAAEAAAAAQAAA
    EYAAAAgAAAAEgAAAEkAYwBvAG4ATwBuAGwAeQAAAAAADgAAABQAAAAAAAAAEAAAABQA
    AAA=";

    #endregion

    using (BinaryWriter writer = new BinaryWriter(part.GetStream()))
    {
      writer.Write(System.Convert.FromBase64String(iconBytes));
      writer.Flush();
    }
  }
}

Build and run the solution in Visual Studio by pressing CTRL+F5. When you build and run the sample code, it creates a document named ContainingDocument.docx in the C:\Temp folder. ContainingDocument.docx contains the embedded document and displays that document as an icon that you can double-click to open. To change the name or location of the document, modify the sample code and change the value of the containingDocumentPath variable.

The sample code specifies that the document to embed is named EmbeddedDocument.docx and is located in the C:\Temp folder. That document must exist in order for the solution to run successfully. To create the document to embed, open Word 2007, create a new document named EmbeddedDocument.docx, and then save it to the C:\Temp folder. To change the name or location of the embedded document, modify the sample code and change the value of the embeddedDocumentPath variable.

Figure 5. ContainingDocument.docx open in Word

ContainingDocument.docx open in Word

Read It

The sample code in this visual how-to article illustrates how to create a Word 2007 document that contains an embedded Word 2007 document. This section uses code snippets from the Code It section to describe the approach to the solution.

The code first creates a WordprocessingDocument package via the WordprocessingDocument.Create method. It then calls the AddParts helper method to add the document parts that are needed to support the embedded document.

using (WordprocessingDocument package =
  WordprocessingDocument.Create(containingDocumentPath,
    WordprocessingDocumentType.Document))
{
  AddParts(package, embeddedDocumentPath);
}

 

The AddParts method calls helper methods to add the main document part to the package and then add the embedded package part to the main document part.

var mainDocumentPart = parent.AddMainDocumentPart();
GenerateMainDocumentPart().Save(mainDocumentPart);

var embeddedPackagePart = 
  mainDocumentPart.AddNewPart<EmbeddedPackagePart>(
  "application/vnd.openxmlformats-" +
  "officedocument.wordprocessingml.document",
  "rId1");

GenerateEmbeddedPackagePart(embeddedPackagePart,
  embeddedDocumentPath);

 

The main document part that the GenerateMainDocumentPart method creates contains a body with three paragraphs. The third paragraph contains the embedded document, specified by using the EmbeddedObject class.

new Paragraph(
  new Run(
    new EmbeddedObject(
      new v.Shape(
        new v.ImageData()
        {
          Title = "",
          RelationshipId = "rId2"
        }
      )
      {
        Id = "_x0000_i1025",
        Style = "width:76.5pt;height:49.5pt",
        Ole = v.BooleanEntryWithBlankValues.Empty
      },
      new ovml.OleObject()
      {
        Type = ovml.OLEValues.Embed,
        ProgId = "Word.Document.12",
        ShapeId = "_x0000_i1025",
        DrawAspect = ovml.OLEDrawAspectValues.Icon,
        ObjectId = "_1299573545",
        Id = "rId1"
      }
    )
    {
      DxaOriginal = (UInt32Value)1531UL,
      DyaOriginal = (UInt32Value)991UL
    }
  )
)

 

The contents of the embedded document are written to the embedded package part on the main document part via the GenerateEmbeddedPackagePart helper method. The method opens a FileStream on the document to embed into the container document and reads the file contents into a byte array. It then uses a BinaryWriter to write the file contents to a stream opened on the embedded package part.

public static void GenerateEmbeddedPackagePart(OpenXmlPart part,
  string embeddedDocumentPath)
{
  byte[] embeddedDocumentBytes;

  // The following code will generate an exception if an invalid
  // filename is passed.
  using (FileStream fsEmbeddedDocument =
    File.OpenRead(embeddedDocumentPath))
  {
    embeddedDocumentBytes =
      new byte[fsEmbeddedDocument.Length];

    fsEmbeddedDocument.Read(embeddedDocumentBytes, 0,
      embeddedDocumentBytes.Length);
  }

  using (BinaryWriter writer = new BinaryWriter(part.GetStream()))
  {
    writer.Write(embeddedDocumentBytes);
    writer.Flush();
  }
}

 

To display the embedded document as an icon in the containing document, the AddParts method creates an image part on the main document, and then calls the GenerateImagePart method to write the bytes that represent the icon to the image part.

var imagePart = mainDocumentPart.AddNewPart<ImagePart>(
  "image/x-emf", "rId2");

GenerateImagePart(imagePart);

 

The GenerateImagePart method opens a stream on the part and then writes the icon bytes to the stream. For the purposes of illustration, this sample stores the bytes that represent the icon as a hardcoded Base64 string. Best practice would be to store the icon as a resource in the assembly.

public static void GenerateImagePart(OpenXmlPart part)
{
  #region Icon Bytes

  // Best practice is that this icon should be stored as a resource
  // in the assembly instead of as a Base64 string.

  string iconBytes = @"
  AQAAAGwAAAAAAAAAAQAAAGQAAAAuAAAAAAAAAAAAAAAODgAAGAkAACBFTUYAAAEAbBQ
  AABAAAAACAAAAAAAAAAAAAAAAAAAAQAYAALAEAAA0AgAApwEAAAAAAAAAAAAAAAAAAN
  ycCACldQYAGAAAAAwAAAAAAAAAGQAAAAwAAAD///8AcgAAAKAQAAAjAAAAAQAAAEIAA
  …
  BjAGUAMQAyAFwAVwBJAE4AVwBPAFIARAAuAEUAWABFAAAARgAAABAAAAAEAAAAAQAAA
  EYAAAAgAAAAEgAAAEkAYwBvAG4ATwBuAGwAeQAAAAAADgAAABQAAAAAAAAAEAAAABQA
  AAA=";

  #endregion

  using (BinaryWriter writer = new BinaryWriter(part.GetStream()))
  {
    writer.Write(System.Convert.FromBase64String(iconBytes));
    writer.Flush();
  }
}

 

NoteNote

When you use the Open XML SDK 2.0 for Microsoft Office to create a document-generation solution, it is best practice to create a template document first, and then use DocumentReflector, a tool that comes with the SDK. DocumentReflector can generate C# code that uses the SDK typesafe classes to reproduce your template document and the functionality that it contains. You can then use that code to help you add functionality or to help you understand the Open XML document parts and relationships that are required to implement a specific document feature. For more information about best practices and the Open XML SDK 2.0 for Microsoft Office, see Erika Ehrli's blog entry Getting Started Best Practices.

Explore It