| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 | using Syncfusion.Pdf;using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Reflection;using System.Runtime.InteropServices;using System.Runtime.InteropServices.ComTypes;using System.Text;using System.Threading.Tasks;using System.Windows;namespace InABox.Wpf;public static class DocumentUtils{    public static IEnumerable<Tuple<string, Stream?>>? HandleFileDrop(DragEventArgs e)    {        var dataObject = new OutlookDataObject(e.Data);        string? desc = null;        if (dataObject.GetDataPresent("FileGroupDescriptor")) desc = "FileGroupDescriptor";        else if (dataObject.GetDataPresent("FileGroupDescriptorW")) desc = "FileGroupDescriptorW";        if (desc is not null)        {            var result = new List<Tuple<string, Stream?>>();            var filenames = (string[])dataObject.GetData(desc);            var filestreams = (MemoryStream[])dataObject.GetData("FileContents");            for (var i = 0; i < filenames.Length; i++)            {                var filename = filenames[i];                var filestream = filestreams[i];                result.Add(new Tuple<string, Stream?>(filename, filestream));            }            return result;        }        else if (dataObject.GetDataPresent(DataFormats.FileDrop))        {            var result = new List<Tuple<string, Stream?>>();            foreach (var filename in (string[])dataObject.GetData(DataFormats.FileDrop))            {                if (File.Exists(filename))                {                    result.Add(new Tuple<string, Stream?>(filename, null));                }            }            return result;        }        return null;    }    // https://gist.github.com/MattyBoy4444/521547    public class OutlookDataObject : System.Windows.IDataObject    {        #region NativeMethods        private class NativeMethods        {            [DllImport("kernel32.dll")]            static extern IntPtr GlobalLock(IntPtr hMem);            [DllImport("ole32.dll", PreserveSig = false)]            public static extern ILockBytes CreateILockBytesOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease);            [DllImport("OLE32.DLL", CharSet = CharSet.Auto, PreserveSig = false)]            public static extern IntPtr GetHGlobalFromILockBytes(ILockBytes pLockBytes);            [DllImport("OLE32.DLL", CharSet = CharSet.Unicode, PreserveSig = false)]            public static extern IStorage StgCreateDocfileOnILockBytes(ILockBytes plkbyt, uint grfMode, uint reserved);            [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000B-0000-0000-C000-000000000046")]            public interface IStorage            {                [return: MarshalAs(UnmanagedType.Interface)]                IStream CreateStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2);                [return: MarshalAs(UnmanagedType.Interface)]                IStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2);                [return: MarshalAs(UnmanagedType.Interface)]                IStorage CreateStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2);                [return: MarshalAs(UnmanagedType.Interface)]                IStorage OpenStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr pstgPriority, [In, MarshalAs(UnmanagedType.U4)] int grfMode, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.U4)] int reserved);                void CopyTo(int ciidExclude, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] pIIDExclude, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest);                void MoveElementTo([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName, [In, MarshalAs(UnmanagedType.U4)] int grfFlags);                void Commit(int grfCommitFlags);                void Revert();                void EnumElements([In, MarshalAs(UnmanagedType.U4)] int reserved1, IntPtr reserved2, [In, MarshalAs(UnmanagedType.U4)] int reserved3, [MarshalAs(UnmanagedType.Interface)] out object ppVal);                void DestroyElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsName);                void RenameElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsOldName, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName);                void SetElementTimes([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In] System.Runtime.InteropServices.ComTypes.FILETIME pctime, [In] System.Runtime.InteropServices.ComTypes.FILETIME patime, [In] System.Runtime.InteropServices.ComTypes.FILETIME pmtime);                void SetClass([In] ref Guid clsid);                void SetStateBits(int grfStateBits, int grfMask);                void Stat([Out] out System.Runtime.InteropServices.ComTypes.STATSTG pStatStg, int grfStatFlag);            }            [ComImport, Guid("0000000A-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]            public interface ILockBytes            {                void ReadAt([In, MarshalAs(UnmanagedType.U8)] long ulOffset, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, [In, MarshalAs(UnmanagedType.U4)] int cb, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pcbRead);                void WriteAt([In, MarshalAs(UnmanagedType.U8)] long ulOffset, IntPtr pv, [In, MarshalAs(UnmanagedType.U4)] int cb, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pcbWritten);                void Flush();                void SetSize([In, MarshalAs(UnmanagedType.U8)] long cb);                void LockRegion([In, MarshalAs(UnmanagedType.U8)] long libOffset, [In, MarshalAs(UnmanagedType.U8)] long cb, [In, MarshalAs(UnmanagedType.U4)] int dwLockType);                void UnlockRegion([In, MarshalAs(UnmanagedType.U8)] long libOffset, [In, MarshalAs(UnmanagedType.U8)] long cb, [In, MarshalAs(UnmanagedType.U4)] int dwLockType);                void Stat([Out] out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, [In, MarshalAs(UnmanagedType.U4)] int grfStatFlag);            }            [StructLayout(LayoutKind.Sequential)]            public sealed class POINTL            {                public int x;                public int y;            }            [StructLayout(LayoutKind.Sequential)]            public sealed class SIZEL            {                public int cx;                public int cy;            }            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]            public sealed class FILEGROUPDESCRIPTORA            {                public uint cItems;                public FILEDESCRIPTORA fgd;            }            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]            public sealed class FILEDESCRIPTORA            {                public uint dwFlags;                public Guid clsid;                public SIZEL sizel;                public POINTL pointl;                public uint dwFileAttributes;                public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;                public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;                public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;                public uint nFileSizeHigh;                public uint nFileSizeLow;                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]                public string cFileName;            }            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]            public sealed class FILEGROUPDESCRIPTORW            {                public uint cItems;                public FILEDESCRIPTORW fgd;            }            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]            public sealed class FILEDESCRIPTORW            {                public uint dwFlags;                public Guid clsid;                public SIZEL sizel;                public POINTL pointl;                public uint dwFileAttributes;                public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;                public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;                public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;                public uint nFileSizeHigh;                public uint nFileSizeLow;                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]                public string cFileName;            }        }        #endregion        #region Property(s)        /// <summary>        /// Holds the <see cref="System.Windows.IDataObject"/> that this class is wrapping        /// </summary>        private System.Windows.IDataObject underlyingDataObject;        /// <summary>        /// Holds the <see cref="System.Runtime.InteropServices.ComTypes.IDataObject"/> interface to the <see cref="System.Windows.IDataObject"/> that this class is wrapping.        /// </summary>        private System.Runtime.InteropServices.ComTypes.IDataObject comUnderlyingDataObject;        /// <summary>        /// Holds the internal ole <see cref="System.Windows.IDataObject"/> to the <see cref="System.Windows.IDataObject"/> that this class is wrapping.        /// </summary>        private System.Windows.IDataObject oleUnderlyingDataObject;        /// <summary>        /// Holds the <see cref="MethodInfo"/> of the "GetDataFromHGLOBAL" method of the internal ole <see cref="System.Windows.IDataObject"/>.        /// </summary>        private MethodInfo getDataFromHGLOBALMethod;        #endregion        #region Constructor(s)        /// <summary>        /// Initializes a new instance of the <see cref="OutlookDataObject"/> class.        /// </summary>        /// <param name="underlyingDataObject">The underlying data object to wrap.</param>        public OutlookDataObject(System.Windows.IDataObject underlyingDataObject)        {            //get the underlying dataobject and its ComType IDataObject interface to it            this.underlyingDataObject = underlyingDataObject;            this.comUnderlyingDataObject = (System.Runtime.InteropServices.ComTypes.IDataObject)this.underlyingDataObject;            //get the internal ole dataobject and its GetDataFromHGLOBAL so it can be called later            FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("_innerData", BindingFlags.NonPublic | BindingFlags.Instance);            this.oleUnderlyingDataObject = (System.Windows.IDataObject)innerDataField.GetValue(this.underlyingDataObject);            this.getDataFromHGLOBALMethod = this.oleUnderlyingDataObject.GetType().GetMethod("GetDataFromHGLOBAL", BindingFlags.NonPublic | BindingFlags.Instance);        }        #endregion        #region IDataObject Members        /// <summary>        /// Retrieves the data associated with the specified class type format.        /// </summary>        /// <param name="format">A <see cref="T:System.Type"></see> representing the format of the data to retrieve. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <returns>        /// The data associated with the specified format, or null.        /// </returns>        public object GetData(Type format)        {            return this.GetData(format.FullName);        }        /// <summary>        /// Retrieves the data associated with the specified data format.        /// </summary>        /// <param name="format">The format of the data to retrieve. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <returns>        /// The data associated with the specified format, or null.        /// </returns>        public object GetData(string format)        {            return this.GetData(format, true);        }        /// <summary>        /// Retrieves the data associated with the specified data format, using a Boolean to determine whether to convert the data to the format.        /// </summary>        /// <param name="format">The format of the data to retrieve. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <param name="autoConvert">true to convert the data to the specified format; otherwise, false.</param>        /// <returns>        /// The data associated with the specified format, or null.        /// </returns>        public object GetData(string format, bool autoConvert)        {            //handle the "FileGroupDescriptor" and "FileContents" format request in this class otherwise pass through to underlying IDataObject             switch (format)            {                case "FileGroupDescriptor":                    //override the default handling of FileGroupDescriptor which returns a                    //MemoryStream and instead return a string array of file names                    IntPtr fileGroupDescriptorAPointer = IntPtr.Zero;                    try                    {                        //use the underlying IDataObject to get the FileGroupDescriptor as a MemoryStream                        MemoryStream fileGroupDescriptorStream = (MemoryStream)this.underlyingDataObject.GetData("FileGroupDescriptor", autoConvert);                        byte[] fileGroupDescriptorBytes = new byte[fileGroupDescriptorStream.Length];                        fileGroupDescriptorStream.Read(fileGroupDescriptorBytes, 0, fileGroupDescriptorBytes.Length);                        fileGroupDescriptorStream.Close();                        //copy the file group descriptor into unmanaged memory                         fileGroupDescriptorAPointer = Marshal.AllocHGlobal(fileGroupDescriptorBytes.Length);                        Marshal.Copy(fileGroupDescriptorBytes, 0, fileGroupDescriptorAPointer, fileGroupDescriptorBytes.Length);                        ////marshal the unmanaged memory to to FILEGROUPDESCRIPTORA struct                        //FIX FROM - https://stackoverflow.com/questions/27173844/accessviolationexception-after-copying-a-file-from-inside-a-zip-archive-to-the-c                        int ITEMCOUNT = Marshal.ReadInt32(fileGroupDescriptorAPointer);                        //create a new array to store file names in of the number of items in the file group descriptor                        string[] fileNames = new string[ITEMCOUNT];                        //get the pointer to the first file descriptor                        IntPtr fileDescriptorPointer = (IntPtr)((long)fileGroupDescriptorAPointer + Marshal.SizeOf(ITEMCOUNT));                        //loop for the number of files acording to the file group descriptor                        for (int fileDescriptorIndex = 0; fileDescriptorIndex < ITEMCOUNT; fileDescriptorIndex++)                        {                            //marshal the pointer top the file descriptor as a FILEDESCRIPTORA struct and get the file name                            NativeMethods.FILEDESCRIPTORA fileDescriptor = (NativeMethods.FILEDESCRIPTORA)Marshal.PtrToStructure(fileDescriptorPointer, typeof(NativeMethods.FILEDESCRIPTORA));                            fileNames[fileDescriptorIndex] = fileDescriptor.cFileName;                            //move the file descriptor pointer to the next file descriptor                            fileDescriptorPointer = (IntPtr)((long)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor));                        }                        //return the array of filenames                        return fileNames;                    }                    finally                    {                        //free unmanaged memory pointer                        Marshal.FreeHGlobal(fileGroupDescriptorAPointer);                    }                case "FileGroupDescriptorW":                    //override the default handling of FileGroupDescriptorW which returns a                    //MemoryStream and instead return a string array of file names                    IntPtr fileGroupDescriptorWPointer = IntPtr.Zero;                    try                    {                        //use the underlying IDataObject to get the FileGroupDescriptorW as a MemoryStream                        MemoryStream fileGroupDescriptorStream = (MemoryStream)this.underlyingDataObject.GetData("FileGroupDescriptorW");                        byte[] fileGroupDescriptorBytes = new byte[fileGroupDescriptorStream.Length];                        fileGroupDescriptorStream.Read(fileGroupDescriptorBytes, 0, fileGroupDescriptorBytes.Length);                        fileGroupDescriptorStream.Close();                        //copy the file group descriptor into unmanaged memory                        fileGroupDescriptorWPointer = Marshal.AllocHGlobal(fileGroupDescriptorBytes.Length);                        Marshal.Copy(fileGroupDescriptorBytes, 0, fileGroupDescriptorWPointer, fileGroupDescriptorBytes.Length);                        //marshal the unmanaged memory to to FILEGROUPDESCRIPTORW struct                        //FIX FROM - https://stackoverflow.com/questions/27173844/accessviolationexception-after-copying-a-file-from-inside-a-zip-archive-to-the-c                        int ITEMCOUNT = Marshal.ReadInt32(fileGroupDescriptorWPointer);                        //create a new array to store file names in of the number of items in the file group descriptor                        string[] fileNames = new string[ITEMCOUNT];                        //get the pointer to the first file descriptor                        IntPtr fileDescriptorPointer = (IntPtr)((long)fileGroupDescriptorWPointer + Marshal.SizeOf(ITEMCOUNT));                        //loop for the number of files acording to the file group descriptor                        for (int fileDescriptorIndex = 0; fileDescriptorIndex < ITEMCOUNT; fileDescriptorIndex++)                        {                            //marshal the pointer top the file descriptor as a FILEDESCRIPTORW struct and get the file name                            NativeMethods.FILEDESCRIPTORW fileDescriptor = (NativeMethods.FILEDESCRIPTORW)Marshal.PtrToStructure(fileDescriptorPointer, typeof(NativeMethods.FILEDESCRIPTORW));                            fileNames[fileDescriptorIndex] = fileDescriptor.cFileName;                            //move the file descriptor pointer to the next file descriptor                            fileDescriptorPointer = (IntPtr)((long)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor));                        }                        //return the array of filenames                        return fileNames;                    }                    finally                    {                        //free unmanaged memory pointer                        Marshal.FreeHGlobal(fileGroupDescriptorWPointer);                    }                case "FileContents":                    //override the default handling of FileContents which returns the                    //contents of the first file as a memory stream and instead return                                        //a array of MemoryStreams containing the data to each file dropped                                        //                    // FILECONTENTS requires a companion FILEGROUPDESCRIPTOR to be                                         // available so we bail out if we don't find one in the data object.                    string fgdFormatName;                    if (GetDataPresent("FileGroupDescriptorW"))                        fgdFormatName = "FileGroupDescriptorW";                    else if (GetDataPresent("FileGroupDescriptor"))                        fgdFormatName = "FileGroupDescriptor";                    else                        return null;                    //get the array of filenames which lets us know how many file contents exist                                        string[] fileContentNames = (string[])this.GetData(fgdFormatName);                    //create a MemoryStream array to store the file contents                    MemoryStream[] fileContents = new MemoryStream[fileContentNames.Length];                    //loop for the number of files acording to the file names                    for (int fileIndex = 0; fileIndex < fileContentNames.Length; fileIndex++)                    {                        //get the data at the file index and store in array                        fileContents[fileIndex] = this.GetData(format, fileIndex);                    }                    //return array of MemoryStreams containing file contents                    return fileContents;            }            //use underlying IDataObject to handle getting of data            return this.underlyingDataObject.GetData(format, autoConvert);        }        /// <summary>        /// Retrieves the data associated with the specified data format at the specified index.        /// </summary>        /// <param name="format">The format of the data to retrieve. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <param name="index">The index of the data to retrieve.</param>        /// <returns>        /// A <see cref="MemoryStream"/> containing the raw data for the specified data format at the specified index.        /// </returns>        public MemoryStream GetData(string format, int index)        {            //create a FORMATETC struct to request the data with            FORMATETC formatetc = new FORMATETC();            formatetc.cfFormat = (short)DataFormats.GetDataFormat(format).Id;            formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;            formatetc.lindex = index;            formatetc.ptd = new IntPtr(0);            formatetc.tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_ISTORAGE | TYMED.TYMED_HGLOBAL;            //create STGMEDIUM to output request results into            STGMEDIUM medium = new STGMEDIUM();            //using the Com IDataObject interface get the data using the defined FORMATETC            this.comUnderlyingDataObject.GetData(ref formatetc, out medium);            //retrieve the data depending on the returned store type            switch (medium.tymed)            {                case TYMED.TYMED_ISTORAGE:                    //to handle a IStorage it needs to be written into a second unmanaged                    //memory mapped storage and then the data can be read from memory into                    //a managed byte and returned as a MemoryStream                    NativeMethods.IStorage iStorage = null;                    NativeMethods.IStorage iStorage2 = null;                    NativeMethods.ILockBytes iLockBytes = null;                    System.Runtime.InteropServices.ComTypes.STATSTG iLockBytesStat;                    try                    {                        //marshal the returned pointer to a IStorage object                        iStorage = (NativeMethods.IStorage)Marshal.GetObjectForIUnknown(medium.unionmember);                        Marshal.Release(medium.unionmember);                        //create a ILockBytes (unmanaged byte array) and then create a IStorage using the byte array as a backing store                        iLockBytes = NativeMethods.CreateILockBytesOnHGlobal(IntPtr.Zero, true);                        iStorage2 = NativeMethods.StgCreateDocfileOnILockBytes(iLockBytes, 0x00001012, 0);                        //copy the returned IStorage into the new IStorage                        iStorage.CopyTo(0, null, IntPtr.Zero, iStorage2);                        iLockBytes.Flush();                        iStorage2.Commit(0);                        //get the STATSTG of the ILockBytes to determine how many bytes were written to it                        iLockBytesStat = new System.Runtime.InteropServices.ComTypes.STATSTG();                        iLockBytes.Stat(out iLockBytesStat, 1);                        int iLockBytesSize = (int)iLockBytesStat.cbSize;                        //read the data from the ILockBytes (unmanaged byte array) into a managed byte array                        byte[] iLockBytesContent = new byte[iLockBytesSize];                        iLockBytes.ReadAt(0, iLockBytesContent, iLockBytesContent.Length, null);                        //wrapped the managed byte array into a memory stream and return it                        return new MemoryStream(iLockBytesContent);                    }                    finally                    {                        //release all unmanaged objects                        Marshal.ReleaseComObject(iStorage2);                        Marshal.ReleaseComObject(iLockBytes);                        Marshal.ReleaseComObject(iStorage);                    }                case TYMED.TYMED_ISTREAM:                    //to handle a IStream it needs to be read into a managed byte and                    //returned as a MemoryStream                    IStream iStream = null;                    System.Runtime.InteropServices.ComTypes.STATSTG iStreamStat;                    try                    {                        //marshal the returned pointer to a IStream object                        iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember);                        Marshal.Release(medium.unionmember);                        //get the STATSTG of the IStream to determine how many bytes are in it                        iStreamStat = new System.Runtime.InteropServices.ComTypes.STATSTG();                        iStream.Stat(out iStreamStat, 0);                        int iStreamSize = (int)iStreamStat.cbSize;                        //read the data from the IStream into a managed byte array                        byte[] iStreamContent = new byte[iStreamSize];                        iStream.Read(iStreamContent, iStreamContent.Length, IntPtr.Zero);                        //wrapped the managed byte array into a memory stream and return it                        return new MemoryStream(iStreamContent);                    }                    finally                    {                        //release all unmanaged objects                        Marshal.ReleaseComObject(iStream);                    }                case TYMED.TYMED_HGLOBAL:                    //to handle a HGlobal the exisitng "GetDataFromHGLOBAL" method is invoked via                    //reflection                    return (MemoryStream)this.getDataFromHGLOBALMethod.Invoke(this.oleUnderlyingDataObject, new object[] { DataFormats.GetDataFormat((short)formatetc.cfFormat).Name, medium.unionmember });            }            return null;        }        /// <summary>        /// Determines whether data stored in this instance is associated with, or can be converted to, the specified format.        /// </summary>        /// <param name="format">A <see cref="T:System.Type"></see> representing the format for which to check. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <returns>        /// true if data stored in this instance is associated with, or can be converted to, the specified format; otherwise, false.        /// </returns>        public bool GetDataPresent(Type format)        {            return this.underlyingDataObject.GetDataPresent(format);        }        /// <summary>        /// Determines whether data stored in this instance is associated with, or can be converted to, the specified format.        /// </summary>        /// <param name="format">The format for which to check. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <returns>        /// true if data stored in this instance is associated with, or can be converted to, the specified format; otherwise false.        /// </returns>        public bool GetDataPresent(string format)        {            return this.underlyingDataObject.GetDataPresent(format);        }        /// <summary>        /// Determines whether data stored in this instance is associated with the specified format, using a Boolean value to determine whether to convert the data to the format.        /// </summary>        /// <param name="format">The format for which to check. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <param name="autoConvert">true to determine whether data stored in this instance can be converted to the specified format; false to check whether the data is in the specified format.</param>        /// <returns>        /// true if the data is in, or can be converted to, the specified format; otherwise, false.        /// </returns>        public bool GetDataPresent(string format, bool autoConvert)        {            return this.underlyingDataObject.GetDataPresent(format, autoConvert);        }        /// <summary>        /// Returns a list of all formats that data stored in this instance is associated with or can be converted to.        /// </summary>        /// <returns>        /// An array of the names that represents a list of all formats that are supported by the data stored in this object.        /// </returns>        public string[] GetFormats()        {            return this.underlyingDataObject.GetFormats();        }        /// <summary>        /// Gets a list of all formats that data stored in this instance is associated with or can be converted to, using a Boolean value to determine whether to retrieve all formats that the data can be converted to or only native data formats.        /// </summary>        /// <param name="autoConvert">true to retrieve all formats that data stored in this instance is associated with or can be converted to; false to retrieve only native data formats.</param>        /// <returns>        /// An array of the names that represents a list of all formats that are supported by the data stored in this object.        /// </returns>        public string[] GetFormats(bool autoConvert)        {            return this.underlyingDataObject.GetFormats(autoConvert);        }        /// <summary>        /// Stores the specified data in this instance, using the class of the data for the format.        /// </summary>        /// <param name="data">The data to store.</param>        public void SetData(object data)        {            this.underlyingDataObject.SetData(data);        }        /// <summary>        /// Stores the specified data and its associated class type in this instance.        /// </summary>        /// <param name="format">A <see cref="T:System.Type"></see> representing the format associated with the data. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <param name="data">The data to store.</param>        public void SetData(Type format, object data)        {            this.underlyingDataObject.SetData(format, data);        }        /// <summary>        /// Stores the specified data and its associated format in this instance.        /// </summary>        /// <param name="format">The format associated with the data. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <param name="data">The data to store.</param>        public void SetData(string format, object data)        {            this.underlyingDataObject.SetData(format, data);        }        /// <summary>        /// Stores the specified data and its associated format in this instance, using a Boolean value to specify whether the data can be converted to another format.        /// </summary>        /// <param name="format">The format associated with the data. See <see cref="T:System.Windows.DataFormats"></see> for predefined formats.</param>        /// <param name="autoConvert">true to allow the data to be converted to another format; otherwise, false.</param>        /// <param name="data">The data to store.</param>        public void SetData(string format, object data, bool autoConvert)        {            this.underlyingDataObject.SetData(format, data, autoConvert);        }        #endregion    }}
 |