See the question and my original answer on StackOverflow

Here is a code that will work for most types, but only on a Windows box, as it requires OLE technology. In fact it ultimately depends on how your machine is configured, because of OLE intimacy, so you need to try this a bit.

This is a sample code that creates a .docx file:

// make sure this all is running in an STA thread (for example, mark Main with the STAThread attribute)

// the file you want to embed
string embeddedDocumentPath = @"C:\mypath\myfile.txt";

// a temp file that will be created, and embedded in the final .docx    
string packagePath = @"C:\Temp\test.bin";

// a temp image file that will be created and embedded in the final .docx
string packageIconPath = @"C:\Temp\test.emf";

// package embeddedDocumentPath -> create the two OpenXML embeddings
Packager.PackageFile(packagePath, packageIconPath, embeddedDocumentPath);

// create the word doc
using (var doc = WordprocessingDocument.Create(@"C:\mypath\ContainingDocument.docx", WordprocessingDocumentType.Document))
    var main = doc.AddMainDocumentPart();

    // add icon embedding
    var imagePart = main.AddImagePart(ImagePartType.Emf);

    // add package embedding
    var objectPart = main.AddEmbeddedObjectPart("application/vnd.openxmlformats-officedocument.oleObject");

    // build a sample doc
    main.Document = BuildDocument(main.GetIdOfPart(imagePart), main.GetIdOfPart(objectPart), "Package");

private static Document BuildDocument(string imagePartId, string objPartId, string progId)
    var shapeId = "R" + Guid.NewGuid().ToString("N");  // come up with a unique name...

    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
                        RelationshipId = imagePartId,   // rel to image part
                        Title = ""                      // this is important!
                        Id = shapeId
                new ovml.OleObject
                    Type = ovml.OleValues.Embed,
                    DrawAspect = ovml.OleDrawAspectValues.Icon,
                    ProgId = progId,    // COM progid
                    Id = objPartId,     // rel to embedded part
                    ShapeId = shapeId,  // link to shape
                    ObjectId = "R" + Guid.NewGuid().ToString("N") // come up with a unique name...
    return element;

And here is the utility code that will create a package and an image (EMF) file from the input file. Now, for PDF, this code may fail (like I said it depends if you installed Adobe Reader or not, its version, etc.). If it fails on OleCreateFromFile, then you may try to create/add a registry key named 'PackageOnFileDrop' like this:




Which key depends on the version of Acrobat you're using, Usually, the parent key (HKEY_CLASSES_ROOT\AcroExch.Document.DC or HKEY_CLASSES_ROOT\Acrobat.Document.DC should already exist). In doubt, you can create both safely...

I'm not sure why PDF files don't support OleCreateFromFile directly (undercovers, if you have installed Acrobat Reader, this is all handled by AcroRd32.exe which is a COM server provider by Adobe), I think it may be a security feature, and I don't know how Word circumvents this...

public static class Packager
  public static void PackageFile(string outputFile, string outputImageFile, string inputFile)
      if (outputFile == null)
          throw new ArgumentNullException(nameof(outputFile));

      if (outputImageFile == null)
          throw new ArgumentNullException(nameof(outputImageFile));

      if (inputFile == null)
          throw new ArgumentNullException(nameof(inputFile));

      IStorage storage;
          out storage));

      // note 1: if you get 'Use of Ole1 services requiring DDE windows is disabled' error, make sure the executing thread is STA
      // note 2: if you want packager to succeed on PDF files instead of reporting 0x8000ffff (E_UNEXPECTED) or 0x80040005 (OLE_E_NOTRUNNING), make sure
      // there exists a key named "PackageOnFileDrop", like this: HKEY_CLASSES_ROOT\AcroExch.Document.DC\PackageOnFileDrop
      // or like this HKEY_CLASSES_ROOT\Acrobat.Document.DC\PackageOnFileDrop
     // This depends on the version of Acrobat, you can use sysinternals' ProcMon tool to check registry queries

      IDataObject ps; // from System.Runtime.InteropServices.ComTypes
          out ps));

      var format = new FORMATETC();
      format.cfFormat = CF_ENHMETAFILE;
      format.dwAspect = DVASPECT.DVASPECT_CONTENT;
      format.lindex = -1;
      format.tymed = TYMED.TYMED_ENHMF;

      STGMEDIUM medium;
      ps.GetData(ref format, out medium);

      CopyEnhMetaFile(medium.unionmember, outputImageFile);


  private static void CheckHr(int hr)
      if (hr != 0)
          throw new Win32Exception(hr);

  [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000B-0000-0000-C000-000000000046")]
  private interface IStorage
      void _VtblGap1_6(); // we only need Commit
      void Commit(int grfCommitFlags);

  private static extern int StgCreateStorageEx(
      [MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
      int grfMode,
      int stgfmt,
      int grfAttrs,
      IntPtr pStgOptions,
      IntPtr reserved2,
      [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
      out IStorage ppObjectOpen);

  private static extern int OleCreateFromFile(
      [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
      [MarshalAs(UnmanagedType.LPWStr)] string lpszFileName,
      [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
      int renderopt,
      IntPtr lpFormatEtc,
      IntPtr pClientSite,
      IStorage pStg,
      out IDataObject ppStg

  [DllImport("gdi32.dll", SetLastError = true)]
  private static extern bool DeleteEnhMetaFile(IntPtr hemf);

  [DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
  private static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, string lpszFile);

  private const int CF_ENHMETAFILE = 14;
  private const int STGM_READWRITE = 2;
  private const int STGM_SHARE_EXCLUSIVE = 0x10;
  private const int STGM_CREATE = 0x1000;
  private const int STGFMT_DOCFILE = 5;