0

I am trying to embed pdf files into OPEN XML document. This requires creating *.bin files. I dont want to use automation.

Approach which Ive taken from this question works for all file types Ive tested except *.pdf.

For some reason pdf files always get the result from OleCreateFromFile(..) to be 0x80004005 and the pOle is NULL.

I am new on the field of invoking and OLE. What could be a reason for this approach not working for PDF? (I have newest Adobe Reader, Win8, invoking into Ole32.dll, projects build target is x86 and Ive test to call CoUninitialize() and CoInitializeEx((System.IntPtr)null, OLE32.CoInit.ApartmentThreaded), I am able to embed pdf files in MSWORD application).

Here is a function that I use for it:

public static string ExportOleFile(string _inputFileName, string oleOutputFileName, string emfOutputFileName)
        {
            StringBuilder resultString = new StringBuilder();           
            string newInput = MultibyteToUnicodeNETOnly(_inputFileName, 1252);

            Microsoft.VisualStudio.OLE.Interop.IStorage storage;
            var result = OLE32.StgCreateStorageEx(oleOutputFileName,
                Convert.ToInt32(OLE32.STGM.STGM_READWRITE | OLE32.STGM.STGM_SHARE_EXCLUSIVE | OLE32.STGM.STGM_CREATE | OLE32.STGM.STGM_TRANSACTED),
                Convert.ToInt32(OLE32.STGFMT.STGFMT_DOCFILE),
                0,
                IntPtr.Zero,
                IntPtr.Zero,
                ref OLE32.IID_IStorage,
                out storage
            );//vytvoří bin

            resultString.AppendLine("CreateStorageEx Result: " + result.ToString());

            var CLSID_NULL = Guid.Empty;


            Microsoft.VisualStudio.OLE.Interop.FORMATETC f = new FORMATETC();
            Microsoft.VisualStudio.OLE.Interop.IOleObject pOle;
            result = OLE32.OleCreateFromFile(
                ref CLSID_NULL,
                newInput,
                ref OLE32.IID_IOleObject,
                (uint)Microsoft.VisualStudio.OLE.Interop.OLERENDER.OLERENDER_NONE,
                ref f,
                null,
                storage,
                out pOle
            );

            resultString.AppendLine("OleCreateFromFile Result: " + result.ToString());
            try
            {

                result = OLE32.OleRun(pOle);
            }
            catch (Exception ex)
            {
                resultString.AppendLine(ex.ToString());
                return resultString.ToString();
            }

            resultString.AppendLine("OleRun Result: " + result.ToString());

            try
            {

                IntPtr unknownFromOle = Marshal.GetIUnknownForObject(pOle);
                IntPtr unknownForDataObj;
                Marshal.QueryInterface(unknownFromOle, ref OLE32.IID_IDataObject, out unknownForDataObj);
                var pdo = Marshal.GetObjectForIUnknown(unknownForDataObj) as System.Runtime.InteropServices.ComTypes.IDataObject;

                var fetc = new System.Runtime.InteropServices.ComTypes.FORMATETC();

                fetc.cfFormat = (short)OLE32.CLIPFORMAT.CF_ENHMETAFILE;
                fetc.dwAspect = System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT;
                fetc.lindex = -1;
                fetc.ptd = IntPtr.Zero;
                fetc.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_ENHMF;

                var stgm = new System.Runtime.InteropServices.ComTypes.STGMEDIUM();
                stgm.unionmember = IntPtr.Zero;
                stgm.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_ENHMF;
                pdo.GetData(ref fetc, out stgm);

                var hemf = GDI32.CopyEnhMetaFile(stgm.unionmember, emfOutputFileName);
                storage.Commit((int)OLE32.STGC.DEFAULT);

                pOle.Close(0);
                GDI32.DeleteEnhMetaFile(stgm.unionmember);
                GDI32.DeleteEnhMetaFile(hemf);
            }
            catch (Exception ex)
            {
                resultString.AppendLine(ex.ToString());
                return resultString.ToString();
            }         
            return resultString.ToString();
        }
Community
  • 1
  • 1
aerkain
  • 592
  • 1
  • 4
  • 16
  • The combination of using an ancient and heavily deprecated api and a file format that's owned by another company ought to be troublesome. If you don't want to use Automation then at least use the openxml api. – Hans Passant Jul 17 '13 at 15:58
  • Can you please provide me an example of how to embed PDF (or any file format except images) into word document using Open XML API only? I do not want to use the automation. – aerkain Jul 18 '13 at 07:27

1 Answers1

0

Actually for embedding files in OpenXML, it is necessary to work with the good old OLE functions. There is no other way around as you need to get two pieces:

  • a file that is going to be embedded
  • a picture that shows the content of the file, usually a screenshot of the first page

I did write a blog entry about that: Embedd pdf into powerpoint by usage of openxml. This is not exactly your requirement but it works identically.

There are two issues with pdfs when it comes to embedding:

  • Embedded pdf documents have a different content than the original pdf file. For all other OLE formats I know (excel, word, powerpoint, ...) this is not the case. You can just use the file on the hard disk, for pdf you cannot.
  • You need to take a picture of the first page. You could use pdfium or the like - there are quite some tools out there for rendering pdf, but adobe reader is free, and does the job 100%.