123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 |
- 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)
- {
- return HandleFileDrop(e.Data);
- }
- public static IEnumerable<Tuple<string, Stream?>>? HandleFileDrop(System.Windows.IDataObject obj)
- {
- var dataObject = new OutlookDataObject(obj);
- 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
- }
- }
|