Invoking OLE in C# through OleCreateFromFile does not work for pdf files

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

Answers


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%.

Need Your Help

Rails style fixture deserializer for c#

c# ruby-on-rails fixtures

Is there an open source deserializer in C# that could read a RoR style fixture into a given type? I tried googling it, but there really was not much that came up. It seems like a really simple thin...

Not sure why my jquery smooth div scroller isn't working

jquery smooth-scrolling

I'm using the smooth div scroller as seen in this site: http://www.smoothdivscroll.com/.