DataObject.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / DataObject.cs / 1458001 / DataObject.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Runtime.InteropServices.ComTypes;
    using System.Collections.Specialized; 
    using System.Diagnostics; 
    using System;
    using Microsoft.Win32; 
    using System.Collections;
    using System.ComponentModel;
    using System.IO;
    using System.Drawing; 
    using System.Windows.Forms;
    using System.Security; 
    using System.Security.Permissions; 
    using System.Reflection;
 
    using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
    using System.Globalization;

    ///  
    /// 
    ///    Implements a basic data transfer mechanism. 
    ///  
    [
        ClassInterface(ClassInterfaceType.None) 
    ]
    public class DataObject : IDataObject, IComDataObject {

        private static readonly string CF_DEPRECATED_FILENAME = "FileName"; 
        private static readonly string CF_DEPRECATED_FILENAMEW = "FileNameW";
 
        private const int DV_E_FORMATETC     = unchecked((int)0x80040064); 
        private const int DV_E_LINDEX        = unchecked((int)0x80040068);
        private const int DV_E_TYMED         = unchecked((int)0x80040069); 
        private const int DV_E_DVASPECT      = unchecked((int)0x8004006B);
        private const int OLE_E_NOTRUNNING   = unchecked((int)0x80040005);
        private const int OLE_E_ADVISENOTSUPPORTED = unchecked((int)0x80040003);
        private const int DATA_S_SAMEFORMATETC = 0x00040130; 

        private static readonly TYMED[] ALLOWED_TYMEDS = 
        new TYMED [] { 
            TYMED.TYMED_HGLOBAL,
            TYMED.TYMED_ISTREAM, 
            TYMED.TYMED_ENHMF,
            TYMED.TYMED_MFPICT,
            TYMED.TYMED_GDI};
 
        private IDataObject     innerData = null;
 
        // We use this to identify that a stream is actually a serialized object.  On read, 
        // we don't know if the contents of a stream were saved "raw" or if the stream is really
        // pointing to a serialized object.  If we saved an object, we prefix it with this 
        // guid.
        //
        private static readonly byte[] serializedObjectID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
 
        /// 
        ///  
        /// Initializes a new instance of the  class, with the specified . 
        /// 
        internal DataObject(IDataObject data) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject based on IDataObject");
            innerData = data;
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
        } 

        ///  
        ///  
        /// Initializes a new instance of the  class, with the specified .
        ///  
        internal DataObject(IComDataObject data) {
            if (data is DataObject) {
                innerData = data as IDataObject;
            } 
            else {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject based on IComDataObject"); 
                innerData = new OleConverter(data); 
            }
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
        }

        /// 
        ///  
        ///    
        ///       Initializes a new instance of the  
        ///       class, which can store arbitrary data. 
        ///    
        ///  
        public DataObject() {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject standalone");
            innerData = new DataStore();
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
        }
 
        ///  
        /// 
        /// Initializes a new instance of the  class, containing the specified data. 
        /// 
        public DataObject(object data) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject base on Object: " + data.ToString());
            if (data is IDataObject && !Marshal.IsComObject(data)) { 
                innerData = (IDataObject)data;
            } 
            else if (data is IComDataObject) { 
                innerData = new OleConverter((IComDataObject)data);
            } 
            else {
                innerData = new DataStore();
                SetData(data);
            } 
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
        } 
 
        /// 
        ///  
        /// Initializes a new instance of the  class, containing the specified data and its
        ///    associated format.
        /// 
        public DataObject(string format, object data) : this() { 
            SetData(format, data);
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
        } 

        private IntPtr GetCompatibleBitmap(Bitmap bm) { 
            // GDI+ returns a DIBSECTION based HBITMAP. The clipboard deals well
            // only with bitmaps created using CreateCompatibleBitmap(). So, we
            // convert the DIBSECTION into a compatible bitmap.
            // 
            IntPtr hBitmap = bm.GetHbitmap();
 
            // Get the screen DC. 
            //
            IntPtr hDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); 

            // Create a compatible DC to render the source bitmap.
            //
            IntPtr dcSrc = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hDC)); 
            IntPtr srcOld = SafeNativeMethods.SelectObject(new HandleRef(null, dcSrc), new HandleRef(bm, hBitmap));
 
            // Create a compatible DC and a new compatible bitmap. 
            //
            IntPtr dcDest = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hDC)); 
            IntPtr hBitmapNew = SafeNativeMethods.CreateCompatibleBitmap(new HandleRef(null, hDC), bm.Size.Width, bm.Size.Height);

            // Select the new bitmap into a compatible DC and render the blt the original bitmap.
            // 
            IntPtr destOld = SafeNativeMethods.SelectObject(new HandleRef(null, dcDest), new HandleRef(null, hBitmapNew));
            SafeNativeMethods.BitBlt(new HandleRef(null, dcDest), 0, 0, bm.Size.Width, bm.Size.Height, new HandleRef(null, dcSrc), 0, 0, 0x00CC0020); 
 
            // Clear the source and destination compatible DCs.
            // 
            SafeNativeMethods.SelectObject(new HandleRef(null, dcSrc), new HandleRef(null, srcOld));
            SafeNativeMethods.SelectObject(new HandleRef(null, dcDest), new HandleRef(null, destOld));

            UnsafeNativeMethods.DeleteCompatibleDC(new HandleRef(null, dcSrc)); 
            UnsafeNativeMethods.DeleteCompatibleDC(new HandleRef(null, dcDest));
            UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, hDC)); 
 
            SafeNativeMethods.DeleteObject(new HandleRef(bm, hBitmap));
 
            return hBitmapNew;
        }

        ///  
        /// 
        ///    Retrieves the data associated with the specified data 
        ///       format, using an automated conversion parameter to determine whether to convert 
        ///       the data to the format.
        ///  
        public virtual object GetData(string format, bool autoConvert) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format + ", " + autoConvert.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            return innerData.GetData(format, autoConvert); 
        }
 
        ///  
        /// 
        ///    Retrieves the data associated with the specified data 
        ///       format.
        /// 
        public virtual object GetData(string format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format); 
            return GetData(format, true);
        } 
 
        /// 
        ///  
        ///    Retrieves the data associated with the specified class
        ///       type format.
        /// 
        public virtual object GetData(Type format) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format.FullName);
            Debug.Assert(format != null, "Must specify a format type"); 
            if (format == null) { 
                return null;
            } 
            return GetData(format.FullName);
        }

        ///  
        /// 
        ///    Determines whether data stored in this instance is 
        ///       associated with, or can be converted to, the specified 
        ///       format.
        ///  
        public virtual bool GetDataPresent(Type format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check data: " + format.FullName);
            Debug.Assert(format != null, "Must specify a format type");
            if (format == null) { 
                return false;
            } 
            bool b = GetDataPresent(format.FullName); 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "  ret: " + b.ToString());
            return b; 
        }

        /// 
        ///  
        ///    Determines whether data stored in this instance is
        ///       associated with the specified format, using an automatic conversion 
        ///       parameter to determine whether to convert the data to the format. 
        /// 
        public virtual bool GetDataPresent(string format, bool autoConvert) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check data: " + format + ", " + autoConvert.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            bool b = innerData.GetDataPresent(format, autoConvert);
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "  ret: " + b.ToString()); 
            return b;
        } 
 
        /// 
        ///  
        ///    Determines whether data stored in this instance is
        ///       associated with, or can be converted to, the specified
        ///       format.
        ///  
        public virtual bool GetDataPresent(string format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check data: " + format); 
            bool b = GetDataPresent(format, true); 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "  ret: " + b.ToString());
            return b; 
        }


        ///  
        /// 
        ///    Gets a list of all formats that data stored in this 
        ///       instance is associated with or can be converted to, using an automatic 
        ///       conversion parameterto
        ///       determine whether to retrieve all formats that the data can be converted to or 
        ///       only native data formats.
        /// 
        public virtual string[] GetFormats(bool autoConvert) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check formats: " + autoConvert.ToString()); 
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            return innerData.GetFormats(autoConvert); 
        } 

        ///  
        /// 
        ///    Gets a list of all formats that data stored in this instance is associated
        ///       with or can be converted to.
        ///  
        public virtual string[] GetFormats() {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check formats:"); 
            return GetFormats(true); 
        }
 
        // <-- WHIDBEY ADDITIONS

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public virtual bool ContainsAudio() { 
            return GetDataPresent(DataFormats.WaveAudio, false);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public virtual bool ContainsFileDropList() { 
            return GetDataPresent(DataFormats.FileDrop, true); 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public virtual bool ContainsImage() {
            return GetDataPresent(DataFormats.Bitmap, true); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        public virtual bool ContainsText() { 
            return ContainsText(TextDataFormat.UnicodeText);
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        public virtual bool ContainsText(TextDataFormat format) {
            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue)){
                throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat)); 
            } 

            return GetDataPresent(ConvertToDataFormats(format), false); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public virtual Stream GetAudioStream() { 
            return GetData(DataFormats.WaveAudio, false) as Stream;
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public virtual StringCollection GetFileDropList() { 
            StringCollection retVal = new StringCollection(); 
            string[] strings = GetData(DataFormats.FileDrop, true) as string[];
            if (strings != null) { 
                retVal.AddRange(strings);
            }
            return retVal;
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public virtual Image GetImage() {
            return GetData(DataFormats.Bitmap, true) as Image;
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        public virtual string GetText() { 
            return GetText(TextDataFormat.UnicodeText);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        public virtual string GetText(TextDataFormat format) {
            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue)){
                throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat));
            }
 
            string text = GetData(ConvertToDataFormats(format), false) as string;
            if (text != null) { 
                return text; 
            }
 
            return String.Empty;
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        public virtual void SetAudio(byte[] audioBytes) {
            if (audioBytes == null) { 
                throw new ArgumentNullException("audioBytes");
            }
            SetAudio(new MemoryStream(audioBytes));
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public virtual void SetAudio(Stream audioStream) {
            if (audioStream == null) {
                throw new ArgumentNullException("audioStream");
            } 
            SetData(DataFormats.WaveAudio, false, audioStream);
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        public virtual void SetFileDropList(StringCollection filePaths) {
            if (filePaths == null) { 
                throw new ArgumentNullException("filePaths");
            } 
            string[] strings = new string[filePaths.Count]; 
            filePaths.CopyTo(strings, 0);
            SetData(DataFormats.FileDrop, true, strings); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public virtual void SetImage(Image image) { 
            if (image == null) {
                throw new ArgumentNullException("image"); 
            }
            SetData(DataFormats.Bitmap, true, image);
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        public virtual void SetText(string textData) { 
            SetText(textData, TextDataFormat.UnicodeText);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        public virtual void SetText(string textData, TextDataFormat format) {
            if (String.IsNullOrEmpty(textData)) { 
                throw new ArgumentNullException("textData");
            }

            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue))
            { 
                throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat)); 
            }
 
            SetData(ConvertToDataFormats(format), false, textData);
        }

        private static string ConvertToDataFormats(TextDataFormat format) { 
            switch (format) {
            case TextDataFormat.UnicodeText: 
                return DataFormats.UnicodeText; 

            case TextDataFormat.Rtf: 
                return DataFormats.Rtf;

            case TextDataFormat.Html:
                return DataFormats.Html; 

            case TextDataFormat.CommaSeparatedValue: 
                return DataFormats.CommaSeparatedValue; 
            }
 
            return DataFormats.UnicodeText;
        }

        // END - WHIDBEY ADDITIONS --> 

        ///  
        ///  
        ///     Retrieves a list of distinct strings from the array.
        ///  
        private static string[] GetDistinctStrings(string[] formats) {
            ArrayList distinct = new ArrayList();
            for (int i=0; i 
        ///  
        ///     Returns all the "synonyms" for the specified format.
        ///  
        private static string[] GetMappedFormats(string format) {
            if (format == null) {
                return null;
            } 

            if (format.Equals(DataFormats.Text) 
                || format.Equals(DataFormats.UnicodeText) 
                || format.Equals(DataFormats.StringFormat)) {
 
                return new string[] {
                    DataFormats.StringFormat,
                    DataFormats.UnicodeText,
                    DataFormats.Text, 
                };
            } 
 
            if (format.Equals(DataFormats.FileDrop)
                || format.Equals(CF_DEPRECATED_FILENAME) 
                || format.Equals(CF_DEPRECATED_FILENAMEW)) {

                return new string[] {
                    DataFormats.FileDrop, 
                    CF_DEPRECATED_FILENAMEW,
                    CF_DEPRECATED_FILENAME, 
                }; 
            }
 
            if (format.Equals(DataFormats.Bitmap)
                || format.Equals((typeof(Bitmap)).FullName)) {

                return new string[] { 
                    (typeof(Bitmap)).FullName,
                    DataFormats.Bitmap, 
                }; 
            }
 
/*gpr
            if (format.Equals(DataFormats.EnhancedMetafile)
                || format.Equals((typeof(Metafile)).FullName)) {
 
                return new string[] {DataFormats.EnhancedMetafile,
                    (typeof(Metafile)).FullName}; 
            } 
*/
            return new String[] {format}; 
        }

        /*
        ///  
        /// 
        ///     Returns all distinct "synonyms" for the each of the formats. 
        ///  
        private static string[] GetMappedFormats(string[] formats) {
            ArrayList allChoices = new ArrayList(); 

            for (int i=0; i
        ///  
        ///     Returns true if the tymed is useable. 
        /// 
        ///  
        private bool GetTymedUseable(TYMED tymed) {
            for (int i=0; i
        /// 
        ///     Populates Ole datastructes from a [....] dataObject. This is the core
        ///     of [....] to OLE conversion. 
        /// 
        ///  
        private void GetDataIntoOleStructs(ref FORMATETC formatetc, 
                                           ref STGMEDIUM medium) {
 
            if (GetTymedUseable(formatetc.tymed) && GetTymedUseable(medium.tymed)) {
                string format = DataFormats.GetFormat(formatetc.cfFormat).Name;

                if (GetDataPresent(format)) { 
                    Object data = GetData(format);
 
                    if ((formatetc.tymed & TYMED.TYMED_HGLOBAL) != 0) { 
                        int hr = SaveDataToHandle(data, format, ref medium);
                        if (NativeMethods.Failed(hr)) { 
                            Marshal.ThrowExceptionForHR(hr);
                        }
                    }
                    else if ((formatetc.tymed & TYMED.TYMED_GDI) != 0) { 
                        if (format.Equals(DataFormats.Bitmap) && data is Bitmap) {
                            // save bitmap 
                            // 
                            Bitmap bm = (Bitmap)data;
                            if (bm != null) { 
                                medium.unionmember = GetCompatibleBitmap(bm); // gpr: Does this get properly disposed?
                            }
                        }
                    } 
/* gpr
                    else if ((formatetc.tymed & TYMED.TYMED_ENHMF) != 0) { 
                        if (format.Equals(DataFormats.EnhancedMetafile) 
                            && data is Metafile) {
                            // save metafile 

                            Metafile mf = (Metafile)data;
                            if (mf != null) {
                                medium.unionmember = mf.Handle; 
                            }
                        } 
                    } 
                    */
                    else { 
                        Marshal.ThrowExceptionForHR (DV_E_TYMED);
                    }
                }
                else { 
                    Marshal.ThrowExceptionForHR (DV_E_FORMATETC);
                } 
            } 
            else {
                Marshal.ThrowExceptionForHR (DV_E_TYMED); 
            }
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        int IComDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink pAdvSink, out int pdwConnection) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DAdvise");
            if (innerData is OleConverter) { 
                return ((OleConverter)innerData).OleDataObject.DAdvise(ref pFormatetc, advf, pAdvSink, out pdwConnection); 
            }
            pdwConnection = 0; 
            return (NativeMethods.E_NOTIMPL);
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        void IComDataObject.DUnadvise(int dwConnection) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DUnadvise");
            if (innerData is OleConverter) { 
                ((OleConverter)innerData).OleDataObject.DUnadvise(dwConnection); 
                return;
            } 
            Marshal.ThrowExceptionForHR(NativeMethods.E_NOTIMPL);
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        int IComDataObject.EnumDAdvise(out IEnumSTATDATA enumAdvise) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "EnumDAdvise");
            if (innerData is OleConverter) { 
                return ((OleConverter)innerData).OleDataObject.EnumDAdvise(out enumAdvise); 
            }
            enumAdvise = null; 
            return (OLE_E_ADVISENOTSUPPORTED);
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        IEnumFORMATETC IComDataObject.EnumFormatEtc(DATADIR dwDirection) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "EnumFormatEtc: " + dwDirection.ToString());
            if (innerData is OleConverter) { 
                return ((OleConverter)innerData).OleDataObject.EnumFormatEtc(dwDirection); 
            }
            if (dwDirection == DATADIR.DATADIR_GET) { 
                return new FormatEnumerator(this);
            }
            else {
                throw new ExternalException(SR.GetString(SR.ExternalException), NativeMethods.E_NOTIMPL); 
            }
        } 
 
        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        // 
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        int IComDataObject.GetCanonicalFormatEtc(ref FORMATETC pformatetcIn, out FORMATETC pformatetcOut) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "GetCanonicalFormatEtc"); 
            if (innerData is OleConverter) {
                return ((OleConverter)innerData).OleDataObject.GetCanonicalFormatEtc(ref pformatetcIn, out pformatetcOut);
            }
            pformatetcOut = new FORMATETC(); 
            return (DATA_S_SAMEFORMATETC);
        } 
 
        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        // 
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        void IComDataObject.GetData(ref FORMATETC formatetc, out STGMEDIUM medium) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "GetData"); 
            if (innerData is OleConverter) {
                ((OleConverter)innerData).OleDataObject.GetData(ref formatetc, out medium);
                return;
            } 

            medium = new STGMEDIUM(); 
 
            if (GetTymedUseable(formatetc.tymed)) {
                if ((formatetc.tymed & TYMED.TYMED_HGLOBAL) != 0) { 
                    medium.tymed = TYMED.TYMED_HGLOBAL;
                    medium.unionmember = UnsafeNativeMethods.GlobalAlloc(NativeMethods.GMEM_MOVEABLE
                                                             | NativeMethods.GMEM_DDESHARE
                                                             | NativeMethods.GMEM_ZEROINIT, 
                                                             1);
                    if (medium.unionmember == IntPtr.Zero) { 
                        throw new OutOfMemoryException(); 
                    }
 
                    try {
                        ((IComDataObject)this).GetDataHere(ref formatetc, ref medium);
                    }
                    catch { 
                        UnsafeNativeMethods.GlobalFree(new HandleRef(medium, medium.unionmember));
                        medium.unionmember = IntPtr.Zero; 
                        throw; 
                    }
                } 
                else {
                    medium.tymed  = formatetc.tymed;
                    ((IComDataObject)this).GetDataHere(ref formatetc, ref medium);
                } 
            }
            else { 
                Marshal.ThrowExceptionForHR(DV_E_TYMED); 
            }
        } 

        // 
        //     Part of IComDataObject, used to interop with OLE.
        //  
        // 
        ///  
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        void IComDataObject.GetDataHere(ref FORMATETC formatetc, ref STGMEDIUM medium) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "GetDataHere");
            if (innerData is OleConverter) { 
                ((OleConverter)innerData).OleDataObject.GetDataHere(ref formatetc, ref medium);
            } 
            else { 
                GetDataIntoOleStructs(ref formatetc, ref medium);
            } 
        }

        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        //  
        ///  
        /// 
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface. 
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        int IComDataObject.QueryGetData(ref FORMATETC formatetc) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData"); 
            if (innerData is OleConverter) {
                return ((OleConverter)innerData).OleDataObject.QueryGetData(ref formatetc); 
            } 
            if (formatetc.dwAspect == DVASPECT.DVASPECT_CONTENT) {
                if (GetTymedUseable(formatetc.tymed)) { 

                    if (formatetc.cfFormat == 0) {
                        Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData::returning S_FALSE because cfFormat == 0");
                        return NativeMethods.S_FALSE; 
                    }
                    else { 
                        if (!GetDataPresent(DataFormats.GetFormat(formatetc.cfFormat).Name)) { 
                            return (DV_E_FORMATETC);
                        } 
                    }
                }
                else {
                    return (DV_E_TYMED); 
                }
            } 
            else { 
                return (DV_E_DVASPECT);
            } 
            #if DEBUG
            int format = formatetc.cfFormat;
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData::cfFormat " + format.ToString(CultureInfo.InvariantCulture) + " found");
            #endif 
            return NativeMethods.S_OK;
        } 
 
        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        // 
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        void IComDataObject.SetData(ref FORMATETC pFormatetcIn, ref STGMEDIUM pmedium, bool fRelease) {
 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "SetData");
            if (innerData is OleConverter) {
                ((OleConverter)innerData).OleDataObject.SetData(ref pFormatetcIn, ref pmedium, fRelease);
                return; 
            }
            // 
 
            throw new NotImplementedException();
        } 

        private int SaveDataToHandle(object data, string format, ref STGMEDIUM medium) {
            int hr = NativeMethods.E_FAIL;
            if (data is Stream) { 
                hr = SaveStreamToHandle(ref medium.unionmember, (Stream)data);
            } 
            else if (format.Equals(DataFormats.Text) 
                     || format.Equals(DataFormats.Rtf)
                     || format.Equals(DataFormats.Html) 
                     || format.Equals(DataFormats.OemText)) {
                hr = SaveStringToHandle(medium.unionmember, data.ToString(), false);
            }
            else if (format.Equals(DataFormats.UnicodeText)) { 
                hr = SaveStringToHandle(medium.unionmember, data.ToString(), true);
            } 
            else if (format.Equals(DataFormats.FileDrop)) { 
                hr = SaveFileListToHandle(medium.unionmember, (string[])data);
            } 
            else if (format.Equals(CF_DEPRECATED_FILENAME)) {
                string[] filelist = (string[])data;
                hr = SaveStringToHandle(medium.unionmember, filelist[0], false);
            } 
            else if (format.Equals(CF_DEPRECATED_FILENAMEW)) {
                string[] filelist = (string[])data; 
                hr = SaveStringToHandle(medium.unionmember, filelist[0], true); 
            }
            else if (format.Equals(DataFormats.Dib) 
                     && data is Image) {
                // GDI+ does not properly handle saving to DIB images.  Since the
                // clipboard will take an HBITMAP and publish a Dib, we don't need
                // to support this. 
                //
                hr = DV_E_TYMED; // SaveImageToHandle(ref medium.unionmember, (Image)data); 
            } 
            else if (format.Equals(DataFormats.Serializable)
                     || data is ISerializable 
                     || (data != null && data.GetType().IsSerializable)) {
                hr = SaveObjectToHandle(ref medium.unionmember, data);
            }
            return hr; 
        }
 
        /* 
        private int SaveImageToHandle(ref IntPtr handle, Image data) {
            MemoryStream stream = new MemoryStream(); 
            data.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
            return SaveStreamToHandle(ref handle, stream);
        }
        */ 

        private int SaveObjectToHandle(ref IntPtr handle, Object data) { 
            Stream stream = new MemoryStream(); 
            BinaryWriter bw = new BinaryWriter(stream);
            bw.Write(serializedObjectID); 
            SaveObjectToHandleSerializer(stream, data);
            return SaveStreamToHandle(ref handle, stream);
        }
 
        [
            SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.SerializationFormatter) 
        ] 
        private static void SaveObjectToHandleSerializer(Stream stream, Object data) {
            BinaryFormatter formatter = new BinaryFormatter(); 
            formatter.Serialize(stream, data);
        }

        ///  
        /// 
        ///     Saves stream out to handle. 
        ///  
        /// 
        private int SaveStreamToHandle(ref IntPtr handle, Stream stream) { 
            if (handle != IntPtr.Zero) {
                UnsafeNativeMethods.GlobalFree(new HandleRef(null, handle));
            }
            int size = (int)stream.Length; 
            handle = UnsafeNativeMethods.GlobalAlloc(NativeMethods.GMEM_MOVEABLE | NativeMethods.GMEM_DDESHARE, size);
            if (handle == IntPtr.Zero) { 
                return (NativeMethods.E_OUTOFMEMORY); 
            }
            IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle)); 
            if (ptr == IntPtr.Zero) {
                return (NativeMethods.E_OUTOFMEMORY);
            }
            try { 
                byte[] bytes = new byte[size];
                stream.Position = 0; 
                stream.Read(bytes, 0, size); 
                Marshal.Copy(bytes, 0, ptr, size);
            } 
            finally {
                UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
            }
            return NativeMethods.S_OK; 
        }
 
        ///  
        /// 
        ///     Saves a list of files out to the handle in HDROP format. 
        /// 
        /// 
        private int SaveFileListToHandle(IntPtr handle, string[] files) {
            if (files == null) { 
                return NativeMethods.S_OK;
            } 
            else if (files.Length < 1) { 
                return NativeMethods.S_OK;
            } 
            if (handle == IntPtr.Zero) {
                return (NativeMethods.E_INVALIDARG);
            }
 

            bool unicode = (Marshal.SystemDefaultCharSize != 1); 
 
            IntPtr currentPtr = IntPtr.Zero;
            int baseStructSize =  4 + 8 + 4 + 4; 
            int sizeInBytes = baseStructSize;

            // First determine the size of the array
            // 
            if (unicode) {
                for (int i=0; i
        ///  
        ///     Save string to handle. If unicode is set to true
        ///     then the string is saved as Unicode, else it is saves as DBCS. 
        ///  
        /// 
        private int SaveStringToHandle(IntPtr handle, string str, bool unicode) { 
            if (handle == IntPtr.Zero) {
                return (NativeMethods.E_INVALIDARG);
            }
            IntPtr newHandle = IntPtr.Zero; 
            if (unicode) {
                int byteSize = (str.Length*2 + 2); 
                newHandle = UnsafeNativeMethods.GlobalReAlloc(new HandleRef(null, handle), 
                                                  byteSize,
                                                  NativeMethods.GMEM_MOVEABLE 
                                                  | NativeMethods.GMEM_DDESHARE
                                                  | NativeMethods.GMEM_ZEROINIT);
                if (newHandle == IntPtr.Zero) {
                    return (NativeMethods.E_OUTOFMEMORY); 
                }
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, newHandle)); 
                if (ptr == IntPtr.Zero) { 
                    return (NativeMethods.E_OUTOFMEMORY);
                } 
                // NOTE: DllLib.copy(char[]...) converts to ANSI on Windows 95...
                char[] chars = str.ToCharArray(0, str.Length);
                UnsafeNativeMethods.CopyMemoryW(ptr, chars, chars.Length*2);
                //NativeMethods.CopyMemoryW(ptr, string, string.Length()*2); 

            } 
            else { 

 
                int pinvokeSize = UnsafeNativeMethods.WideCharToMultiByte(0 /*CP_ACP*/, 0, str, str.Length, null, 0, IntPtr.Zero, IntPtr.Zero);

                byte[] strBytes = new byte[pinvokeSize];
                UnsafeNativeMethods.WideCharToMultiByte(0 /*CP_ACP*/, 0, str, str.Length, strBytes, strBytes.Length, IntPtr.Zero, IntPtr.Zero); 

                newHandle = UnsafeNativeMethods.GlobalReAlloc(new HandleRef(null, handle), 
                                                  pinvokeSize + 1, 
                                                  NativeMethods.GMEM_MOVEABLE
                                                  | NativeMethods.GMEM_DDESHARE 
                                                  | NativeMethods.GMEM_ZEROINIT);
                if (newHandle == IntPtr.Zero) {
                    return (NativeMethods.E_OUTOFMEMORY);
                } 
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, newHandle));
                if (ptr == IntPtr.Zero) { 
                    return (NativeMethods.E_OUTOFMEMORY); 
                }
                UnsafeNativeMethods.CopyMemory(ptr, strBytes, pinvokeSize); 
                Marshal.Copy(new byte[] {0}, 0, (IntPtr)((long)ptr+pinvokeSize), 1);
            }

            if (newHandle != IntPtr.Zero) { 
                UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, newHandle));
            } 
            return NativeMethods.S_OK; 
        }
 

        /// 
        /// 
        ///    Stores the specified data and its associated format in 
        ///       this instance, using the automatic conversion parameter
        ///       to specify whether the 
        ///       data can be converted to another format. 
        /// 
        public virtual void SetData(string format, bool autoConvert, Object data) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + format + ", " + autoConvert.ToString() + ", " + data.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            innerData.SetData(format, autoConvert, data);
        } 

        ///  
        ///  
        ///    Stores the specified data and its associated format in this
        ///       instance. 
        /// 
        public virtual void SetData(string format, object data) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + format + ", " + data.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
            innerData.SetData(format, data);
        } 
 
        /// 
        ///  
        ///    Stores the specified data and
        ///       its
        ///       associated class type in this instance.
        ///  
        public virtual void SetData(Type format, object data) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + format.FullName + ", " + data.ToString()); 
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
            innerData.SetData(format, data);
        } 

        /// 
        /// 
        ///    Stores the specified data in 
        ///       this instance, using the class of the data for the format.
        ///  
        public virtual void SetData(object data) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + data.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
            innerData.SetData(data);
        }

        ///  
        /// 
        ///     Part of IComDataObject, used to interop with OLE. 
        ///  
        /// 
        private class FormatEnumerator : IEnumFORMATETC { 

            internal IDataObject parent = null;
            internal ArrayList formats = new ArrayList();
            internal int current = 0; 

            public FormatEnumerator(IDataObject parent) : this(parent, parent.GetFormats()) { 
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Constructed: " + parent.ToString()); 
            }
 
            public FormatEnumerator(IDataObject parent, FORMATETC[] formats) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Constructed: " + parent.ToString() + ", FORMATETC[]" + formats.Length.ToString(CultureInfo.InvariantCulture));
                this.formats.Clear();
                this.parent = parent; 
                current = 0;
 
                if (formats != null) { 
                    for (int i=0; i 0) {
 
                    FORMATETC current = (FORMATETC)formats[this.current];
                    rgelt[0].cfFormat = current.cfFormat; 
                    rgelt[0].tymed = current.tymed; 
                    rgelt[0].dwAspect = DVASPECT.DVASPECT_CONTENT;
                    rgelt[0].ptd = IntPtr.Zero; 
                    rgelt[0].lindex = -1;

                    if (pceltFetched != null) {
                        pceltFetched[0] = 1; 
                    }
                    this.current++; 
                } 
                else {
                    if (pceltFetched != null) { 
                        pceltFetched[0] = 0;
                    }
                    return NativeMethods.S_FALSE;
                } 
                return NativeMethods.S_OK;
            } 
 
            public int Skip(int celt) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Skip"); 
                if (current + celt >= this.formats.Count) {
                    return NativeMethods.S_FALSE;
                }
                current += celt; 
                return NativeMethods.S_OK;
            } 
 
            public int Reset() {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Reset"); 
                current = 0;
                return NativeMethods.S_OK;
            }
 
            public void Clone(out IEnumFORMATETC ppenum) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Clone"); 
                FORMATETC[] temp = new FORMATETC[formats.Count]; 
                formats.CopyTo(temp, 0);
                ppenum = new FormatEnumerator(parent, temp); 
            }
        }

        ///  
        /// 
        ///     OLE Converter.  This class embodies the nastiness required to convert from our 
        ///     managed types to standard OLE clipboard formats. 
        /// 
        private class OleConverter : IDataObject { 
            internal IComDataObject innerData;

            public OleConverter(IComDataObject data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "OleConverter: Constructed OleConverter"); 
                innerData = data;
            } 
 
            /// 
            ///  
            ///     Returns the data Object we are wrapping
            /// 
            /// 
            public IComDataObject OleDataObject { 
                get {
                    return innerData; 
                } 
            }
 
            /// 
            /// 
            ///     Uses IStream and retrieves the specified format from the bound IComDataObject.
            ///  
            /// 
            private Object GetDataFromOleIStream(string format) { 
 
                FORMATETC formatetc = new FORMATETC();
                STGMEDIUM medium = new STGMEDIUM(); 

                formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id;
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1; 
                formatetc.tymed = TYMED.TYMED_ISTREAM;
 
                medium.tymed = TYMED.TYMED_ISTREAM; 

                // Limit the # of exceptions we may throw below. 
                if (NativeMethods.S_OK != QueryGetData(ref formatetc)){
                    return null;
                }
 
                try {
                    IntSecurity.UnmanagedCode.Assert(); 
                    try { 
                         innerData.GetData(ref formatetc, out medium);
                    } 
                    finally {
                        CodeAccessPermission.RevertAssert();
                    }
                } 
                catch {
                    return null; 
                } 

                if (medium.unionmember != IntPtr.Zero) { 
                    UnsafeNativeMethods.IStream pStream = (UnsafeNativeMethods.IStream)Marshal.GetObjectForIUnknown(medium.unionmember);
                    Marshal.Release(medium.unionmember);
                    NativeMethods.STATSTG sstg = new NativeMethods.STATSTG();
                    pStream.Stat(sstg, NativeMethods.STATFLAG_DEFAULT ); 
                    int size = (int)sstg.cbSize;
 
                    IntPtr hglobal = UnsafeNativeMethods.GlobalAlloc(NativeMethods.GMEM_MOVEABLE 
                                                      | NativeMethods.GMEM_DDESHARE
                                                      | NativeMethods.GMEM_ZEROINIT, 
                                                      size);
                    IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(innerData, hglobal));
                    pStream.Read(ptr, size);
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(innerData, hglobal)); 

                    return GetDataFromHGLOBLAL(format, hglobal); 
                } 

                return null; 
            }


            ///  
            /// 
            ///     Retrieves the specified form from the specified hglobal. 
            ///  
            /// 
            private Object GetDataFromHGLOBLAL(string format, IntPtr hglobal) { 
                Object data = null;

                if (hglobal != IntPtr.Zero) {
                    //=---------------------------------------------------------------= 
                    // Convert from OLE to IW objects
                    //=---------------------------------------------------------------= 
                    // Add any new formats here... 

                    if (format.Equals(DataFormats.Text) 
                        || format.Equals(DataFormats.Rtf)
                        || format.Equals(DataFormats.Html)
                        || format.Equals(DataFormats.OemText)) {
                        data = ReadStringFromHandle(hglobal, false); 
                    }
                    else if (format.Equals(DataFormats.UnicodeText)) { 
                        data = ReadStringFromHandle(hglobal, true); 
                    }
                    else if (format.Equals(DataFormats.FileDrop)) { 
                        data = (Object)ReadFileListFromHandle(hglobal);
                    }
                    else if (format.Equals(CF_DEPRECATED_FILENAME)) {
                        data = new string[] {ReadStringFromHandle(hglobal, false)}; 
                    }
                    else if (format.Equals(CF_DEPRECATED_FILENAMEW)) { 
                        data = new string[] {ReadStringFromHandle(hglobal, true)}; 
                    }
                    else { 
                        data = ReadObjectFromHandle(hglobal);
                        /*
                        spb - 93835 dib support is a mess
                        if (format.Equals(DataFormats.Dib) 
                            && data is Stream) {
                            data = new Bitmap((Stream)data); 
                        } 
                        */
                    } 

                    UnsafeNativeMethods.GlobalFree(new HandleRef(null, hglobal));
                }
 
                return data;
            } 
 
            /// 
            ///  
            ///     Uses HGLOBALs and retrieves the specified format from the bound IComDatabject.
            /// 
            /// 
            private Object GetDataFromOleHGLOBAL(string format) { 
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
 
                FORMATETC formatetc = new FORMATETC(); 
                STGMEDIUM medium = new STGMEDIUM();
 
                formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id;
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1;
                formatetc.tymed = TYMED.TYMED_HGLOBAL; 

                medium.tymed = TYMED.TYMED_HGLOBAL; 
 
                object data = null;
 
                if (NativeMethods.S_OK == QueryGetData(ref formatetc)) {
                    try {
                        IntSecurity.UnmanagedCode.Assert();
                        try { 
                             innerData.GetData(ref formatetc, out medium);
                        } 
                        finally { 
                            CodeAccessPermission.RevertAssert();
                        } 

                        if (medium.unionmember != IntPtr.Zero) {
                            data = GetDataFromHGLOBLAL(format, medium.unionmember);
                        } 
                    }
                    catch { 
                    } 
                }
                return data; 
            }

            /// 
            ///  
            ///     Retrieves the specified format data from the bound IComDataObject, from
            ///     other sources that IStream and HGLOBAL... this is really just a place 
            ///     to put the "special" formats like BITMAP, ENHMF, etc. 
            /// 
            ///  
            private Object GetDataFromOleOther(string format) {
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");

                FORMATETC formatetc = new FORMATETC(); 
                STGMEDIUM medium = new STGMEDIUM();
 
                TYMED tymed = (TYMED)0; 

                if (format.Equals(DataFormats.Bitmap)) { 
                    tymed = TYMED.TYMED_GDI;
                }
                else if (format.Equals(DataFormats.EnhancedMetafile)) {
                    tymed = TYMED.TYMED_ENHMF; 
                }
 
                if (tymed == (TYMED)0) { 
                    return null;
                } 

                formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id;
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1; 
                formatetc.tymed = tymed;
                medium.tymed = tymed; 
 
                Object data = null;
                if (NativeMethods.S_OK == QueryGetData(ref formatetc)) { 
                    try {
                        IntSecurity.UnmanagedCode.Assert();
                        try {
                             innerData.GetData(ref formatetc, out medium); 
                        }
                        finally { 
                            CodeAccessPermission.RevertAssert(); 
                        }
                    } 
                    catch {
                    }
                }
 
                if (medium.unionmember != IntPtr.Zero) {
 
                    if (format.Equals(DataFormats.Bitmap) 
                        //||format.Equals(DataFormats.Dib))
                    ) { 
                        // as/urt 140870 -- GDI+ doesn't own this HBITMAP, but we can't
                        // delete it while the object is still around.  So we have to do the really expensive
                        // thing of cloning the image so we can release the HBITMAP.
                        // 

                        //This bitmap is created by the com object which originally copied the bitmap to tbe 
                        //clipboard. We call Add here, since DeleteObject calls Remove. 
                        System.Internal.HandleCollector.Add(medium.unionmember, NativeMethods.CommonHandles.GDI);
                        Image clipboardImage = null; 
                        IntSecurity.ObjectFromWin32Handle.Assert();
                        try
                        {
                            clipboardImage = Image.FromHbitmap(medium.unionmember); 
                        }
                        finally 
                        { 
                            CodeAccessPermission.RevertAssert();
                        } 
                        if (clipboardImage != null) {
                            Image firstImage = clipboardImage;
                            clipboardImage = (Image)clipboardImage.Clone();
                            SafeNativeMethods.DeleteObject(new HandleRef(null, medium.unionmember)); 
                            firstImage.Dispose();
                        } 
                        data = clipboardImage; 
                    }
/* gpr: 
                    else if (format.Equals(DataFormats.EnhancedMetafile)) {
                        data = new Metafile(medium.unionmember);
                    }
*/ 
                }
 
                return data; 
            }
 
            /// 
            /// 
            ///     Extracts a managed Object from the innerData of the specified
            ///     format. This is the base of the OLE to managed conversion. 
            /// 
            ///  
            private Object GetDataFromBoundOleDataObject(string format) { 

                Object data = null; 
                try
                {
                    data = GetDataFromOleOther(format);
                    if (data == null) 
                    {
                        data = GetDataFromOleHGLOBAL(format); 
                    } 
                    if (data == null)
                    { 
                        data = GetDataFromOleIStream(format);
                    }
                }
                catch (Exception e) 
                {
                    Debug.Fail(e.ToString()); 
                } 
                return data;
            } 

            /// 
            /// 
            ///     Creates an Stream from the data stored in handle. 
            /// 
            ///  
            private Stream ReadByteStreamFromHandle(IntPtr handle, out bool isSerializedObject) { 
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle));
                if (ptr == IntPtr.Zero){ 
                    throw new ExternalException(SR.GetString(SR.ExternalException), NativeMethods.E_OUTOFMEMORY);
                }
                try {
                    int size = UnsafeNativeMethods.GlobalSize(new HandleRef(null, handle)); 
                    byte[] bytes = new byte[size];
                    Marshal.Copy(ptr, bytes, 0, size); 
                    int index = 0; 

                    // The object here can either be a stream or a serialized 
                    // object.  We identify a serialized object by writing the
                    // bytes for the guid serializedObjectID at the front
                    // of the stream.  Check for that here.
                    // 
                    if (size > serializedObjectID.Length) {
                        isSerializedObject = true; 
                        for(int i = 0; i < serializedObjectID.Length; i++) { 
                            if (serializedObjectID[i] != bytes[i]) {
                                isSerializedObject = false; 
                                break;
                            }
                        }
 
                        // Advance the byte pointer.
                        // 
                        if (isSerializedObject) { 
                            index = serializedObjectID.Length;
                        } 
                    }
                    else {
                        isSerializedObject = false;
                    } 

                    return new MemoryStream(bytes, index, bytes.Length - index); 
                } 
                finally {
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle)); 
                }
            }

            ///  
            /// 
            ///     Creates a new instance of the Object that has been persisted into the 
            ///     handle. 
            /// 
            ///  
            private Object ReadObjectFromHandle(IntPtr handle)
            {
                object value = null;
 
                bool isSerializedObject;
                Stream stream = ReadByteStreamFromHandle(handle, out isSerializedObject); 
 
                if (isSerializedObject) {
                    value = ReadObjectFromHandleDeserializer(stream); 
                }
                else {
                    value = stream;
                } 

                return value; 
            } 

            [ 
                SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.SerializationFormatter)
            ]
            private static Object ReadObjectFromHandleDeserializer(Stream stream) {
                BinaryFormatter formatter = new BinaryFormatter(); 
                formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
                return formatter.Deserialize(stream); 
            } 

            ///  
            /// 
            ///     Parses the HDROP format and returns a list of strings using
            ///     the DragQueryFile function.
            ///  
            /// 
            private string[] ReadFileListFromHandle(IntPtr hdrop) { 
 
                string[] files = null;
                StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); 

                int count = UnsafeNativeMethods.DragQueryFile(new HandleRef(null, hdrop), unchecked((int)0xFFFFFFFF), null, 0);
                if (count > 0) {
                    files = new string[count]; 

 
                    for (int i=0; i charlen) {
                            s = s.Substring(0, charlen);
                        }
 
                        // SECREVIEW : do we really need to do this?
                        // 
                        string fullPath = Path.GetFullPath(s); 
                        Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + fullPath + ") Demanded");
                        new FileIOPermission(FileIOPermissionAccess.PathDiscovery, fullPath).Demand(); 
                        files[i] = s;
                    }
                }
 
                return files;
            } 
 
            /// 
            ///  
            ///     Creates a string from the data stored in handle. If
            ///     unicode is set to true, then the string is assume to be Unicode,
            ///     else DBCS (ASCI) is assumed.
            ///  
            /// 
            private unsafe string ReadStringFromHandle(IntPtr handle, bool unicode) { 
                string stringData = null; 

                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle)); 
                try {
                    if (unicode) {
                        stringData = new string((char*)ptr);
                    } 
                    else {
                        stringData = new string((sbyte*)ptr); 
                    } 
                }
                finally { 
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
                }

                return stringData; 
            }
 
            //=------------------------------------------------------------------------= 
            // IDataObject
            //=-----------------------------------------------------------------------= 
            public virtual Object GetData(string format, bool autoConvert) {
                Object baseVar = GetDataFromBoundOleDataObject(format);
                Object original = baseVar;
 
                if (autoConvert && (baseVar == null || baseVar is MemoryStream)) {
                    string[] mappedFormats = GetMappedFormats(format); 
                    if (mappedFormats != null) { 
                        for (int i=0; i 0) { 
                        retrieved[0] = 0;
                        try { 
                            enumFORMATETC.Next(1, formatetc, retrieved); 
                        }
                        catch { 
                        }

                        if (retrieved[0] > 0) {
                            string name = DataFormats.GetFormat(formatetc[0].cfFormat).Name; 
                            if (autoConvert) {
                                string[] mappedFormats = GetMappedFormats(name); 
                                for (int i=0; i
        ///  
        /// 
        private class DataStore : IDataObject {
            private class DataStoreEntry {
                public Object data; 
                public bool autoConvert;
 
                public DataStoreEntry(Object data, bool autoConvert) { 
                    this.data = data;
                    this.autoConvert = autoConvert; 
                }
            }

            private Hashtable data = new Hashtable(BackCompatibleStringComparer.Default); 

            public DataStore() { 
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: Constructed DataStore"); 
            }
 
            public virtual Object GetData(string format, bool autoConvert) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetData: " + format + ", " + autoConvert.ToString());
                DataStoreEntry dse = (DataStoreEntry)data[format];
                Object baseVar = null; 
                if (dse != null) {
                    baseVar = dse.data; 
                } 
                Object original = baseVar;
 
                if (autoConvert
                    && (dse == null || dse.autoConvert)
                    && (baseVar == null || baseVar is MemoryStream)) {
 
                    string[] mappedFormats = GetMappedFormats(format);
                    if (mappedFormats != null) { 
                        for (int i=0; i
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Runtime.InteropServices.ComTypes;
    using System.Collections.Specialized; 
    using System.Diagnostics; 
    using System;
    using Microsoft.Win32; 
    using System.Collections;
    using System.ComponentModel;
    using System.IO;
    using System.Drawing; 
    using System.Windows.Forms;
    using System.Security; 
    using System.Security.Permissions; 
    using System.Reflection;
 
    using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
    using System.Globalization;

    ///  
    /// 
    ///    Implements a basic data transfer mechanism. 
    ///  
    [
        ClassInterface(ClassInterfaceType.None) 
    ]
    public class DataObject : IDataObject, IComDataObject {

        private static readonly string CF_DEPRECATED_FILENAME = "FileName"; 
        private static readonly string CF_DEPRECATED_FILENAMEW = "FileNameW";
 
        private const int DV_E_FORMATETC     = unchecked((int)0x80040064); 
        private const int DV_E_LINDEX        = unchecked((int)0x80040068);
        private const int DV_E_TYMED         = unchecked((int)0x80040069); 
        private const int DV_E_DVASPECT      = unchecked((int)0x8004006B);
        private const int OLE_E_NOTRUNNING   = unchecked((int)0x80040005);
        private const int OLE_E_ADVISENOTSUPPORTED = unchecked((int)0x80040003);
        private const int DATA_S_SAMEFORMATETC = 0x00040130; 

        private static readonly TYMED[] ALLOWED_TYMEDS = 
        new TYMED [] { 
            TYMED.TYMED_HGLOBAL,
            TYMED.TYMED_ISTREAM, 
            TYMED.TYMED_ENHMF,
            TYMED.TYMED_MFPICT,
            TYMED.TYMED_GDI};
 
        private IDataObject     innerData = null;
 
        // We use this to identify that a stream is actually a serialized object.  On read, 
        // we don't know if the contents of a stream were saved "raw" or if the stream is really
        // pointing to a serialized object.  If we saved an object, we prefix it with this 
        // guid.
        //
        private static readonly byte[] serializedObjectID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
 
        /// 
        ///  
        /// Initializes a new instance of the  class, with the specified . 
        /// 
        internal DataObject(IDataObject data) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject based on IDataObject");
            innerData = data;
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
        } 

        ///  
        ///  
        /// Initializes a new instance of the  class, with the specified .
        ///  
        internal DataObject(IComDataObject data) {
            if (data is DataObject) {
                innerData = data as IDataObject;
            } 
            else {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject based on IComDataObject"); 
                innerData = new OleConverter(data); 
            }
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
        }

        /// 
        ///  
        ///    
        ///       Initializes a new instance of the  
        ///       class, which can store arbitrary data. 
        ///    
        ///  
        public DataObject() {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject standalone");
            innerData = new DataStore();
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
        }
 
        ///  
        /// 
        /// Initializes a new instance of the  class, containing the specified data. 
        /// 
        public DataObject(object data) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Constructed DataObject base on Object: " + data.ToString());
            if (data is IDataObject && !Marshal.IsComObject(data)) { 
                innerData = (IDataObject)data;
            } 
            else if (data is IComDataObject) { 
                innerData = new OleConverter((IComDataObject)data);
            } 
            else {
                innerData = new DataStore();
                SetData(data);
            } 
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
        } 
 
        /// 
        ///  
        /// Initializes a new instance of the  class, containing the specified data and its
        ///    associated format.
        /// 
        public DataObject(string format, object data) : this() { 
            SetData(format, data);
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
        } 

        private IntPtr GetCompatibleBitmap(Bitmap bm) { 
            // GDI+ returns a DIBSECTION based HBITMAP. The clipboard deals well
            // only with bitmaps created using CreateCompatibleBitmap(). So, we
            // convert the DIBSECTION into a compatible bitmap.
            // 
            IntPtr hBitmap = bm.GetHbitmap();
 
            // Get the screen DC. 
            //
            IntPtr hDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); 

            // Create a compatible DC to render the source bitmap.
            //
            IntPtr dcSrc = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hDC)); 
            IntPtr srcOld = SafeNativeMethods.SelectObject(new HandleRef(null, dcSrc), new HandleRef(bm, hBitmap));
 
            // Create a compatible DC and a new compatible bitmap. 
            //
            IntPtr dcDest = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hDC)); 
            IntPtr hBitmapNew = SafeNativeMethods.CreateCompatibleBitmap(new HandleRef(null, hDC), bm.Size.Width, bm.Size.Height);

            // Select the new bitmap into a compatible DC and render the blt the original bitmap.
            // 
            IntPtr destOld = SafeNativeMethods.SelectObject(new HandleRef(null, dcDest), new HandleRef(null, hBitmapNew));
            SafeNativeMethods.BitBlt(new HandleRef(null, dcDest), 0, 0, bm.Size.Width, bm.Size.Height, new HandleRef(null, dcSrc), 0, 0, 0x00CC0020); 
 
            // Clear the source and destination compatible DCs.
            // 
            SafeNativeMethods.SelectObject(new HandleRef(null, dcSrc), new HandleRef(null, srcOld));
            SafeNativeMethods.SelectObject(new HandleRef(null, dcDest), new HandleRef(null, destOld));

            UnsafeNativeMethods.DeleteCompatibleDC(new HandleRef(null, dcSrc)); 
            UnsafeNativeMethods.DeleteCompatibleDC(new HandleRef(null, dcDest));
            UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, hDC)); 
 
            SafeNativeMethods.DeleteObject(new HandleRef(bm, hBitmap));
 
            return hBitmapNew;
        }

        ///  
        /// 
        ///    Retrieves the data associated with the specified data 
        ///       format, using an automated conversion parameter to determine whether to convert 
        ///       the data to the format.
        ///  
        public virtual object GetData(string format, bool autoConvert) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format + ", " + autoConvert.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            return innerData.GetData(format, autoConvert); 
        }
 
        ///  
        /// 
        ///    Retrieves the data associated with the specified data 
        ///       format.
        /// 
        public virtual object GetData(string format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format); 
            return GetData(format, true);
        } 
 
        /// 
        ///  
        ///    Retrieves the data associated with the specified class
        ///       type format.
        /// 
        public virtual object GetData(Type format) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format.FullName);
            Debug.Assert(format != null, "Must specify a format type"); 
            if (format == null) { 
                return null;
            } 
            return GetData(format.FullName);
        }

        ///  
        /// 
        ///    Determines whether data stored in this instance is 
        ///       associated with, or can be converted to, the specified 
        ///       format.
        ///  
        public virtual bool GetDataPresent(Type format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check data: " + format.FullName);
            Debug.Assert(format != null, "Must specify a format type");
            if (format == null) { 
                return false;
            } 
            bool b = GetDataPresent(format.FullName); 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "  ret: " + b.ToString());
            return b; 
        }

        /// 
        ///  
        ///    Determines whether data stored in this instance is
        ///       associated with the specified format, using an automatic conversion 
        ///       parameter to determine whether to convert the data to the format. 
        /// 
        public virtual bool GetDataPresent(string format, bool autoConvert) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check data: " + format + ", " + autoConvert.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            bool b = innerData.GetDataPresent(format, autoConvert);
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "  ret: " + b.ToString()); 
            return b;
        } 
 
        /// 
        ///  
        ///    Determines whether data stored in this instance is
        ///       associated with, or can be converted to, the specified
        ///       format.
        ///  
        public virtual bool GetDataPresent(string format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check data: " + format); 
            bool b = GetDataPresent(format, true); 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "  ret: " + b.ToString());
            return b; 
        }


        ///  
        /// 
        ///    Gets a list of all formats that data stored in this 
        ///       instance is associated with or can be converted to, using an automatic 
        ///       conversion parameterto
        ///       determine whether to retrieve all formats that the data can be converted to or 
        ///       only native data formats.
        /// 
        public virtual string[] GetFormats(bool autoConvert) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check formats: " + autoConvert.ToString()); 
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            return innerData.GetFormats(autoConvert); 
        } 

        ///  
        /// 
        ///    Gets a list of all formats that data stored in this instance is associated
        ///       with or can be converted to.
        ///  
        public virtual string[] GetFormats() {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check formats:"); 
            return GetFormats(true); 
        }
 
        // <-- WHIDBEY ADDITIONS

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public virtual bool ContainsAudio() { 
            return GetDataPresent(DataFormats.WaveAudio, false);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public virtual bool ContainsFileDropList() { 
            return GetDataPresent(DataFormats.FileDrop, true); 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public virtual bool ContainsImage() {
            return GetDataPresent(DataFormats.Bitmap, true); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        public virtual bool ContainsText() { 
            return ContainsText(TextDataFormat.UnicodeText);
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        public virtual bool ContainsText(TextDataFormat format) {
            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue)){
                throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat)); 
            } 

            return GetDataPresent(ConvertToDataFormats(format), false); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public virtual Stream GetAudioStream() { 
            return GetData(DataFormats.WaveAudio, false) as Stream;
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public virtual StringCollection GetFileDropList() { 
            StringCollection retVal = new StringCollection(); 
            string[] strings = GetData(DataFormats.FileDrop, true) as string[];
            if (strings != null) { 
                retVal.AddRange(strings);
            }
            return retVal;
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public virtual Image GetImage() {
            return GetData(DataFormats.Bitmap, true) as Image;
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        public virtual string GetText() { 
            return GetText(TextDataFormat.UnicodeText);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        public virtual string GetText(TextDataFormat format) {
            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue)){
                throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat));
            }
 
            string text = GetData(ConvertToDataFormats(format), false) as string;
            if (text != null) { 
                return text; 
            }
 
            return String.Empty;
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        public virtual void SetAudio(byte[] audioBytes) {
            if (audioBytes == null) { 
                throw new ArgumentNullException("audioBytes");
            }
            SetAudio(new MemoryStream(audioBytes));
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public virtual void SetAudio(Stream audioStream) {
            if (audioStream == null) {
                throw new ArgumentNullException("audioStream");
            } 
            SetData(DataFormats.WaveAudio, false, audioStream);
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        public virtual void SetFileDropList(StringCollection filePaths) {
            if (filePaths == null) { 
                throw new ArgumentNullException("filePaths");
            } 
            string[] strings = new string[filePaths.Count]; 
            filePaths.CopyTo(strings, 0);
            SetData(DataFormats.FileDrop, true, strings); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public virtual void SetImage(Image image) { 
            if (image == null) {
                throw new ArgumentNullException("image"); 
            }
            SetData(DataFormats.Bitmap, true, image);
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        public virtual void SetText(string textData) { 
            SetText(textData, TextDataFormat.UnicodeText);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        public virtual void SetText(string textData, TextDataFormat format) {
            if (String.IsNullOrEmpty(textData)) { 
                throw new ArgumentNullException("textData");
            }

            //valid values are 0x0 to 0x4 
            if (!ClientUtils.IsEnumValid(format, (int)format, (int)TextDataFormat.Text, (int)TextDataFormat.CommaSeparatedValue))
            { 
                throw new InvalidEnumArgumentException("format", (int)format, typeof(TextDataFormat)); 
            }
 
            SetData(ConvertToDataFormats(format), false, textData);
        }

        private static string ConvertToDataFormats(TextDataFormat format) { 
            switch (format) {
            case TextDataFormat.UnicodeText: 
                return DataFormats.UnicodeText; 

            case TextDataFormat.Rtf: 
                return DataFormats.Rtf;

            case TextDataFormat.Html:
                return DataFormats.Html; 

            case TextDataFormat.CommaSeparatedValue: 
                return DataFormats.CommaSeparatedValue; 
            }
 
            return DataFormats.UnicodeText;
        }

        // END - WHIDBEY ADDITIONS --> 

        ///  
        ///  
        ///     Retrieves a list of distinct strings from the array.
        ///  
        private static string[] GetDistinctStrings(string[] formats) {
            ArrayList distinct = new ArrayList();
            for (int i=0; i 
        ///  
        ///     Returns all the "synonyms" for the specified format.
        ///  
        private static string[] GetMappedFormats(string format) {
            if (format == null) {
                return null;
            } 

            if (format.Equals(DataFormats.Text) 
                || format.Equals(DataFormats.UnicodeText) 
                || format.Equals(DataFormats.StringFormat)) {
 
                return new string[] {
                    DataFormats.StringFormat,
                    DataFormats.UnicodeText,
                    DataFormats.Text, 
                };
            } 
 
            if (format.Equals(DataFormats.FileDrop)
                || format.Equals(CF_DEPRECATED_FILENAME) 
                || format.Equals(CF_DEPRECATED_FILENAMEW)) {

                return new string[] {
                    DataFormats.FileDrop, 
                    CF_DEPRECATED_FILENAMEW,
                    CF_DEPRECATED_FILENAME, 
                }; 
            }
 
            if (format.Equals(DataFormats.Bitmap)
                || format.Equals((typeof(Bitmap)).FullName)) {

                return new string[] { 
                    (typeof(Bitmap)).FullName,
                    DataFormats.Bitmap, 
                }; 
            }
 
/*gpr
            if (format.Equals(DataFormats.EnhancedMetafile)
                || format.Equals((typeof(Metafile)).FullName)) {
 
                return new string[] {DataFormats.EnhancedMetafile,
                    (typeof(Metafile)).FullName}; 
            } 
*/
            return new String[] {format}; 
        }

        /*
        ///  
        /// 
        ///     Returns all distinct "synonyms" for the each of the formats. 
        ///  
        private static string[] GetMappedFormats(string[] formats) {
            ArrayList allChoices = new ArrayList(); 

            for (int i=0; i
        ///  
        ///     Returns true if the tymed is useable. 
        /// 
        ///  
        private bool GetTymedUseable(TYMED tymed) {
            for (int i=0; i
        /// 
        ///     Populates Ole datastructes from a [....] dataObject. This is the core
        ///     of [....] to OLE conversion. 
        /// 
        ///  
        private void GetDataIntoOleStructs(ref FORMATETC formatetc, 
                                           ref STGMEDIUM medium) {
 
            if (GetTymedUseable(formatetc.tymed) && GetTymedUseable(medium.tymed)) {
                string format = DataFormats.GetFormat(formatetc.cfFormat).Name;

                if (GetDataPresent(format)) { 
                    Object data = GetData(format);
 
                    if ((formatetc.tymed & TYMED.TYMED_HGLOBAL) != 0) { 
                        int hr = SaveDataToHandle(data, format, ref medium);
                        if (NativeMethods.Failed(hr)) { 
                            Marshal.ThrowExceptionForHR(hr);
                        }
                    }
                    else if ((formatetc.tymed & TYMED.TYMED_GDI) != 0) { 
                        if (format.Equals(DataFormats.Bitmap) && data is Bitmap) {
                            // save bitmap 
                            // 
                            Bitmap bm = (Bitmap)data;
                            if (bm != null) { 
                                medium.unionmember = GetCompatibleBitmap(bm); // gpr: Does this get properly disposed?
                            }
                        }
                    } 
/* gpr
                    else if ((formatetc.tymed & TYMED.TYMED_ENHMF) != 0) { 
                        if (format.Equals(DataFormats.EnhancedMetafile) 
                            && data is Metafile) {
                            // save metafile 

                            Metafile mf = (Metafile)data;
                            if (mf != null) {
                                medium.unionmember = mf.Handle; 
                            }
                        } 
                    } 
                    */
                    else { 
                        Marshal.ThrowExceptionForHR (DV_E_TYMED);
                    }
                }
                else { 
                    Marshal.ThrowExceptionForHR (DV_E_FORMATETC);
                } 
            } 
            else {
                Marshal.ThrowExceptionForHR (DV_E_TYMED); 
            }
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        int IComDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink pAdvSink, out int pdwConnection) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DAdvise");
            if (innerData is OleConverter) { 
                return ((OleConverter)innerData).OleDataObject.DAdvise(ref pFormatetc, advf, pAdvSink, out pdwConnection); 
            }
            pdwConnection = 0; 
            return (NativeMethods.E_NOTIMPL);
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        void IComDataObject.DUnadvise(int dwConnection) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DUnadvise");
            if (innerData is OleConverter) { 
                ((OleConverter)innerData).OleDataObject.DUnadvise(dwConnection); 
                return;
            } 
            Marshal.ThrowExceptionForHR(NativeMethods.E_NOTIMPL);
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        int IComDataObject.EnumDAdvise(out IEnumSTATDATA enumAdvise) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "EnumDAdvise");
            if (innerData is OleConverter) { 
                return ((OleConverter)innerData).OleDataObject.EnumDAdvise(out enumAdvise); 
            }
            enumAdvise = null; 
            return (OLE_E_ADVISENOTSUPPORTED);
        }

        //  
        //     Part of IComDataObject, used to interop with OLE.
        //  
        //  
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        IEnumFORMATETC IComDataObject.EnumFormatEtc(DATADIR dwDirection) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "EnumFormatEtc: " + dwDirection.ToString());
            if (innerData is OleConverter) { 
                return ((OleConverter)innerData).OleDataObject.EnumFormatEtc(dwDirection); 
            }
            if (dwDirection == DATADIR.DATADIR_GET) { 
                return new FormatEnumerator(this);
            }
            else {
                throw new ExternalException(SR.GetString(SR.ExternalException), NativeMethods.E_NOTIMPL); 
            }
        } 
 
        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        // 
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        int IComDataObject.GetCanonicalFormatEtc(ref FORMATETC pformatetcIn, out FORMATETC pformatetcOut) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "GetCanonicalFormatEtc"); 
            if (innerData is OleConverter) {
                return ((OleConverter)innerData).OleDataObject.GetCanonicalFormatEtc(ref pformatetcIn, out pformatetcOut);
            }
            pformatetcOut = new FORMATETC(); 
            return (DATA_S_SAMEFORMATETC);
        } 
 
        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        // 
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        void IComDataObject.GetData(ref FORMATETC formatetc, out STGMEDIUM medium) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "GetData"); 
            if (innerData is OleConverter) {
                ((OleConverter)innerData).OleDataObject.GetData(ref formatetc, out medium);
                return;
            } 

            medium = new STGMEDIUM(); 
 
            if (GetTymedUseable(formatetc.tymed)) {
                if ((formatetc.tymed & TYMED.TYMED_HGLOBAL) != 0) { 
                    medium.tymed = TYMED.TYMED_HGLOBAL;
                    medium.unionmember = UnsafeNativeMethods.GlobalAlloc(NativeMethods.GMEM_MOVEABLE
                                                             | NativeMethods.GMEM_DDESHARE
                                                             | NativeMethods.GMEM_ZEROINIT, 
                                                             1);
                    if (medium.unionmember == IntPtr.Zero) { 
                        throw new OutOfMemoryException(); 
                    }
 
                    try {
                        ((IComDataObject)this).GetDataHere(ref formatetc, ref medium);
                    }
                    catch { 
                        UnsafeNativeMethods.GlobalFree(new HandleRef(medium, medium.unionmember));
                        medium.unionmember = IntPtr.Zero; 
                        throw; 
                    }
                } 
                else {
                    medium.tymed  = formatetc.tymed;
                    ((IComDataObject)this).GetDataHere(ref formatetc, ref medium);
                } 
            }
            else { 
                Marshal.ThrowExceptionForHR(DV_E_TYMED); 
            }
        } 

        // 
        //     Part of IComDataObject, used to interop with OLE.
        //  
        // 
        ///  
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        void IComDataObject.GetDataHere(ref FORMATETC formatetc, ref STGMEDIUM medium) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "GetDataHere");
            if (innerData is OleConverter) { 
                ((OleConverter)innerData).OleDataObject.GetDataHere(ref formatetc, ref medium);
            } 
            else { 
                GetDataIntoOleStructs(ref formatetc, ref medium);
            } 
        }

        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        //  
        ///  
        /// 
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface. 
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions.
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        int IComDataObject.QueryGetData(ref FORMATETC formatetc) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData"); 
            if (innerData is OleConverter) {
                return ((OleConverter)innerData).OleDataObject.QueryGetData(ref formatetc); 
            } 
            if (formatetc.dwAspect == DVASPECT.DVASPECT_CONTENT) {
                if (GetTymedUseable(formatetc.tymed)) { 

                    if (formatetc.cfFormat == 0) {
                        Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData::returning S_FALSE because cfFormat == 0");
                        return NativeMethods.S_FALSE; 
                    }
                    else { 
                        if (!GetDataPresent(DataFormats.GetFormat(formatetc.cfFormat).Name)) { 
                            return (DV_E_FORMATETC);
                        } 
                    }
                }
                else {
                    return (DV_E_TYMED); 
                }
            } 
            else { 
                return (DV_E_DVASPECT);
            } 
            #if DEBUG
            int format = formatetc.cfFormat;
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData::cfFormat " + format.ToString(CultureInfo.InvariantCulture) + " found");
            #endif 
            return NativeMethods.S_OK;
        } 
 
        // 
        //     Part of IComDataObject, used to interop with OLE. 
        // 
        // 
        /// 
        ///  
        // SecReview : Vs# 416823 : Need to Demand UMC as IComDataObject is now public interface.
        // This exposes security hole where the IComDataObject implementation can be used to bypass UMC security to call Win32 functions. 
        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        void IComDataObject.SetData(ref FORMATETC pFormatetcIn, ref STGMEDIUM pmedium, bool fRelease) {
 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "SetData");
            if (innerData is OleConverter) {
                ((OleConverter)innerData).OleDataObject.SetData(ref pFormatetcIn, ref pmedium, fRelease);
                return; 
            }
            // 
 
            throw new NotImplementedException();
        } 

        private int SaveDataToHandle(object data, string format, ref STGMEDIUM medium) {
            int hr = NativeMethods.E_FAIL;
            if (data is Stream) { 
                hr = SaveStreamToHandle(ref medium.unionmember, (Stream)data);
            } 
            else if (format.Equals(DataFormats.Text) 
                     || format.Equals(DataFormats.Rtf)
                     || format.Equals(DataFormats.Html) 
                     || format.Equals(DataFormats.OemText)) {
                hr = SaveStringToHandle(medium.unionmember, data.ToString(), false);
            }
            else if (format.Equals(DataFormats.UnicodeText)) { 
                hr = SaveStringToHandle(medium.unionmember, data.ToString(), true);
            } 
            else if (format.Equals(DataFormats.FileDrop)) { 
                hr = SaveFileListToHandle(medium.unionmember, (string[])data);
            } 
            else if (format.Equals(CF_DEPRECATED_FILENAME)) {
                string[] filelist = (string[])data;
                hr = SaveStringToHandle(medium.unionmember, filelist[0], false);
            } 
            else if (format.Equals(CF_DEPRECATED_FILENAMEW)) {
                string[] filelist = (string[])data; 
                hr = SaveStringToHandle(medium.unionmember, filelist[0], true); 
            }
            else if (format.Equals(DataFormats.Dib) 
                     && data is Image) {
                // GDI+ does not properly handle saving to DIB images.  Since the
                // clipboard will take an HBITMAP and publish a Dib, we don't need
                // to support this. 
                //
                hr = DV_E_TYMED; // SaveImageToHandle(ref medium.unionmember, (Image)data); 
            } 
            else if (format.Equals(DataFormats.Serializable)
                     || data is ISerializable 
                     || (data != null && data.GetType().IsSerializable)) {
                hr = SaveObjectToHandle(ref medium.unionmember, data);
            }
            return hr; 
        }
 
        /* 
        private int SaveImageToHandle(ref IntPtr handle, Image data) {
            MemoryStream stream = new MemoryStream(); 
            data.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
            return SaveStreamToHandle(ref handle, stream);
        }
        */ 

        private int SaveObjectToHandle(ref IntPtr handle, Object data) { 
            Stream stream = new MemoryStream(); 
            BinaryWriter bw = new BinaryWriter(stream);
            bw.Write(serializedObjectID); 
            SaveObjectToHandleSerializer(stream, data);
            return SaveStreamToHandle(ref handle, stream);
        }
 
        [
            SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.SerializationFormatter) 
        ] 
        private static void SaveObjectToHandleSerializer(Stream stream, Object data) {
            BinaryFormatter formatter = new BinaryFormatter(); 
            formatter.Serialize(stream, data);
        }

        ///  
        /// 
        ///     Saves stream out to handle. 
        ///  
        /// 
        private int SaveStreamToHandle(ref IntPtr handle, Stream stream) { 
            if (handle != IntPtr.Zero) {
                UnsafeNativeMethods.GlobalFree(new HandleRef(null, handle));
            }
            int size = (int)stream.Length; 
            handle = UnsafeNativeMethods.GlobalAlloc(NativeMethods.GMEM_MOVEABLE | NativeMethods.GMEM_DDESHARE, size);
            if (handle == IntPtr.Zero) { 
                return (NativeMethods.E_OUTOFMEMORY); 
            }
            IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle)); 
            if (ptr == IntPtr.Zero) {
                return (NativeMethods.E_OUTOFMEMORY);
            }
            try { 
                byte[] bytes = new byte[size];
                stream.Position = 0; 
                stream.Read(bytes, 0, size); 
                Marshal.Copy(bytes, 0, ptr, size);
            } 
            finally {
                UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
            }
            return NativeMethods.S_OK; 
        }
 
        ///  
        /// 
        ///     Saves a list of files out to the handle in HDROP format. 
        /// 
        /// 
        private int SaveFileListToHandle(IntPtr handle, string[] files) {
            if (files == null) { 
                return NativeMethods.S_OK;
            } 
            else if (files.Length < 1) { 
                return NativeMethods.S_OK;
            } 
            if (handle == IntPtr.Zero) {
                return (NativeMethods.E_INVALIDARG);
            }
 

            bool unicode = (Marshal.SystemDefaultCharSize != 1); 
 
            IntPtr currentPtr = IntPtr.Zero;
            int baseStructSize =  4 + 8 + 4 + 4; 
            int sizeInBytes = baseStructSize;

            // First determine the size of the array
            // 
            if (unicode) {
                for (int i=0; i
        ///  
        ///     Save string to handle. If unicode is set to true
        ///     then the string is saved as Unicode, else it is saves as DBCS. 
        ///  
        /// 
        private int SaveStringToHandle(IntPtr handle, string str, bool unicode) { 
            if (handle == IntPtr.Zero) {
                return (NativeMethods.E_INVALIDARG);
            }
            IntPtr newHandle = IntPtr.Zero; 
            if (unicode) {
                int byteSize = (str.Length*2 + 2); 
                newHandle = UnsafeNativeMethods.GlobalReAlloc(new HandleRef(null, handle), 
                                                  byteSize,
                                                  NativeMethods.GMEM_MOVEABLE 
                                                  | NativeMethods.GMEM_DDESHARE
                                                  | NativeMethods.GMEM_ZEROINIT);
                if (newHandle == IntPtr.Zero) {
                    return (NativeMethods.E_OUTOFMEMORY); 
                }
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, newHandle)); 
                if (ptr == IntPtr.Zero) { 
                    return (NativeMethods.E_OUTOFMEMORY);
                } 
                // NOTE: DllLib.copy(char[]...) converts to ANSI on Windows 95...
                char[] chars = str.ToCharArray(0, str.Length);
                UnsafeNativeMethods.CopyMemoryW(ptr, chars, chars.Length*2);
                //NativeMethods.CopyMemoryW(ptr, string, string.Length()*2); 

            } 
            else { 

 
                int pinvokeSize = UnsafeNativeMethods.WideCharToMultiByte(0 /*CP_ACP*/, 0, str, str.Length, null, 0, IntPtr.Zero, IntPtr.Zero);

                byte[] strBytes = new byte[pinvokeSize];
                UnsafeNativeMethods.WideCharToMultiByte(0 /*CP_ACP*/, 0, str, str.Length, strBytes, strBytes.Length, IntPtr.Zero, IntPtr.Zero); 

                newHandle = UnsafeNativeMethods.GlobalReAlloc(new HandleRef(null, handle), 
                                                  pinvokeSize + 1, 
                                                  NativeMethods.GMEM_MOVEABLE
                                                  | NativeMethods.GMEM_DDESHARE 
                                                  | NativeMethods.GMEM_ZEROINIT);
                if (newHandle == IntPtr.Zero) {
                    return (NativeMethods.E_OUTOFMEMORY);
                } 
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, newHandle));
                if (ptr == IntPtr.Zero) { 
                    return (NativeMethods.E_OUTOFMEMORY); 
                }
                UnsafeNativeMethods.CopyMemory(ptr, strBytes, pinvokeSize); 
                Marshal.Copy(new byte[] {0}, 0, (IntPtr)((long)ptr+pinvokeSize), 1);
            }

            if (newHandle != IntPtr.Zero) { 
                UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, newHandle));
            } 
            return NativeMethods.S_OK; 
        }
 

        /// 
        /// 
        ///    Stores the specified data and its associated format in 
        ///       this instance, using the automatic conversion parameter
        ///       to specify whether the 
        ///       data can be converted to another format. 
        /// 
        public virtual void SetData(string format, bool autoConvert, Object data) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + format + ", " + autoConvert.ToString() + ", " + data.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
            innerData.SetData(format, autoConvert, data);
        } 

        ///  
        ///  
        ///    Stores the specified data and its associated format in this
        ///       instance. 
        /// 
        public virtual void SetData(string format, object data) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + format + ", " + data.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
            innerData.SetData(format, data);
        } 
 
        /// 
        ///  
        ///    Stores the specified data and
        ///       its
        ///       associated class type in this instance.
        ///  
        public virtual void SetData(Type format, object data) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + format.FullName + ", " + data.ToString()); 
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
            innerData.SetData(format, data);
        } 

        /// 
        /// 
        ///    Stores the specified data in 
        ///       this instance, using the class of the data for the format.
        ///  
        public virtual void SetData(object data) { 
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Set data: " + data.ToString());
            Debug.Assert(innerData != null, "You must have an innerData on all DataObjects"); 
            innerData.SetData(data);
        }

        ///  
        /// 
        ///     Part of IComDataObject, used to interop with OLE. 
        ///  
        /// 
        private class FormatEnumerator : IEnumFORMATETC { 

            internal IDataObject parent = null;
            internal ArrayList formats = new ArrayList();
            internal int current = 0; 

            public FormatEnumerator(IDataObject parent) : this(parent, parent.GetFormats()) { 
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Constructed: " + parent.ToString()); 
            }
 
            public FormatEnumerator(IDataObject parent, FORMATETC[] formats) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Constructed: " + parent.ToString() + ", FORMATETC[]" + formats.Length.ToString(CultureInfo.InvariantCulture));
                this.formats.Clear();
                this.parent = parent; 
                current = 0;
 
                if (formats != null) { 
                    for (int i=0; i 0) {
 
                    FORMATETC current = (FORMATETC)formats[this.current];
                    rgelt[0].cfFormat = current.cfFormat; 
                    rgelt[0].tymed = current.tymed; 
                    rgelt[0].dwAspect = DVASPECT.DVASPECT_CONTENT;
                    rgelt[0].ptd = IntPtr.Zero; 
                    rgelt[0].lindex = -1;

                    if (pceltFetched != null) {
                        pceltFetched[0] = 1; 
                    }
                    this.current++; 
                } 
                else {
                    if (pceltFetched != null) { 
                        pceltFetched[0] = 0;
                    }
                    return NativeMethods.S_FALSE;
                } 
                return NativeMethods.S_OK;
            } 
 
            public int Skip(int celt) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Skip"); 
                if (current + celt >= this.formats.Count) {
                    return NativeMethods.S_FALSE;
                }
                current += celt; 
                return NativeMethods.S_OK;
            } 
 
            public int Reset() {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Reset"); 
                current = 0;
                return NativeMethods.S_OK;
            }
 
            public void Clone(out IEnumFORMATETC ppenum) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Clone"); 
                FORMATETC[] temp = new FORMATETC[formats.Count]; 
                formats.CopyTo(temp, 0);
                ppenum = new FormatEnumerator(parent, temp); 
            }
        }

        ///  
        /// 
        ///     OLE Converter.  This class embodies the nastiness required to convert from our 
        ///     managed types to standard OLE clipboard formats. 
        /// 
        private class OleConverter : IDataObject { 
            internal IComDataObject innerData;

            public OleConverter(IComDataObject data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "OleConverter: Constructed OleConverter"); 
                innerData = data;
            } 
 
            /// 
            ///  
            ///     Returns the data Object we are wrapping
            /// 
            /// 
            public IComDataObject OleDataObject { 
                get {
                    return innerData; 
                } 
            }
 
            /// 
            /// 
            ///     Uses IStream and retrieves the specified format from the bound IComDataObject.
            ///  
            /// 
            private Object GetDataFromOleIStream(string format) { 
 
                FORMATETC formatetc = new FORMATETC();
                STGMEDIUM medium = new STGMEDIUM(); 

                formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id;
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1; 
                formatetc.tymed = TYMED.TYMED_ISTREAM;
 
                medium.tymed = TYMED.TYMED_ISTREAM; 

                // Limit the # of exceptions we may throw below. 
                if (NativeMethods.S_OK != QueryGetData(ref formatetc)){
                    return null;
                }
 
                try {
                    IntSecurity.UnmanagedCode.Assert(); 
                    try { 
                         innerData.GetData(ref formatetc, out medium);
                    } 
                    finally {
                        CodeAccessPermission.RevertAssert();
                    }
                } 
                catch {
                    return null; 
                } 

                if (medium.unionmember != IntPtr.Zero) { 
                    UnsafeNativeMethods.IStream pStream = (UnsafeNativeMethods.IStream)Marshal.GetObjectForIUnknown(medium.unionmember);
                    Marshal.Release(medium.unionmember);
                    NativeMethods.STATSTG sstg = new NativeMethods.STATSTG();
                    pStream.Stat(sstg, NativeMethods.STATFLAG_DEFAULT ); 
                    int size = (int)sstg.cbSize;
 
                    IntPtr hglobal = UnsafeNativeMethods.GlobalAlloc(NativeMethods.GMEM_MOVEABLE 
                                                      | NativeMethods.GMEM_DDESHARE
                                                      | NativeMethods.GMEM_ZEROINIT, 
                                                      size);
                    IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(innerData, hglobal));
                    pStream.Read(ptr, size);
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(innerData, hglobal)); 

                    return GetDataFromHGLOBLAL(format, hglobal); 
                } 

                return null; 
            }


            ///  
            /// 
            ///     Retrieves the specified form from the specified hglobal. 
            ///  
            /// 
            private Object GetDataFromHGLOBLAL(string format, IntPtr hglobal) { 
                Object data = null;

                if (hglobal != IntPtr.Zero) {
                    //=---------------------------------------------------------------= 
                    // Convert from OLE to IW objects
                    //=---------------------------------------------------------------= 
                    // Add any new formats here... 

                    if (format.Equals(DataFormats.Text) 
                        || format.Equals(DataFormats.Rtf)
                        || format.Equals(DataFormats.Html)
                        || format.Equals(DataFormats.OemText)) {
                        data = ReadStringFromHandle(hglobal, false); 
                    }
                    else if (format.Equals(DataFormats.UnicodeText)) { 
                        data = ReadStringFromHandle(hglobal, true); 
                    }
                    else if (format.Equals(DataFormats.FileDrop)) { 
                        data = (Object)ReadFileListFromHandle(hglobal);
                    }
                    else if (format.Equals(CF_DEPRECATED_FILENAME)) {
                        data = new string[] {ReadStringFromHandle(hglobal, false)}; 
                    }
                    else if (format.Equals(CF_DEPRECATED_FILENAMEW)) { 
                        data = new string[] {ReadStringFromHandle(hglobal, true)}; 
                    }
                    else { 
                        data = ReadObjectFromHandle(hglobal);
                        /*
                        spb - 93835 dib support is a mess
                        if (format.Equals(DataFormats.Dib) 
                            && data is Stream) {
                            data = new Bitmap((Stream)data); 
                        } 
                        */
                    } 

                    UnsafeNativeMethods.GlobalFree(new HandleRef(null, hglobal));
                }
 
                return data;
            } 
 
            /// 
            ///  
            ///     Uses HGLOBALs and retrieves the specified format from the bound IComDatabject.
            /// 
            /// 
            private Object GetDataFromOleHGLOBAL(string format) { 
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
 
                FORMATETC formatetc = new FORMATETC(); 
                STGMEDIUM medium = new STGMEDIUM();
 
                formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id;
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1;
                formatetc.tymed = TYMED.TYMED_HGLOBAL; 

                medium.tymed = TYMED.TYMED_HGLOBAL; 
 
                object data = null;
 
                if (NativeMethods.S_OK == QueryGetData(ref formatetc)) {
                    try {
                        IntSecurity.UnmanagedCode.Assert();
                        try { 
                             innerData.GetData(ref formatetc, out medium);
                        } 
                        finally { 
                            CodeAccessPermission.RevertAssert();
                        } 

                        if (medium.unionmember != IntPtr.Zero) {
                            data = GetDataFromHGLOBLAL(format, medium.unionmember);
                        } 
                    }
                    catch { 
                    } 
                }
                return data; 
            }

            /// 
            ///  
            ///     Retrieves the specified format data from the bound IComDataObject, from
            ///     other sources that IStream and HGLOBAL... this is really just a place 
            ///     to put the "special" formats like BITMAP, ENHMF, etc. 
            /// 
            ///  
            private Object GetDataFromOleOther(string format) {
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");

                FORMATETC formatetc = new FORMATETC(); 
                STGMEDIUM medium = new STGMEDIUM();
 
                TYMED tymed = (TYMED)0; 

                if (format.Equals(DataFormats.Bitmap)) { 
                    tymed = TYMED.TYMED_GDI;
                }
                else if (format.Equals(DataFormats.EnhancedMetafile)) {
                    tymed = TYMED.TYMED_ENHMF; 
                }
 
                if (tymed == (TYMED)0) { 
                    return null;
                } 

                formatetc.cfFormat = (short)DataFormats.GetFormat(format).Id;
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1; 
                formatetc.tymed = tymed;
                medium.tymed = tymed; 
 
                Object data = null;
                if (NativeMethods.S_OK == QueryGetData(ref formatetc)) { 
                    try {
                        IntSecurity.UnmanagedCode.Assert();
                        try {
                             innerData.GetData(ref formatetc, out medium); 
                        }
                        finally { 
                            CodeAccessPermission.RevertAssert(); 
                        }
                    } 
                    catch {
                    }
                }
 
                if (medium.unionmember != IntPtr.Zero) {
 
                    if (format.Equals(DataFormats.Bitmap) 
                        //||format.Equals(DataFormats.Dib))
                    ) { 
                        // as/urt 140870 -- GDI+ doesn't own this HBITMAP, but we can't
                        // delete it while the object is still around.  So we have to do the really expensive
                        // thing of cloning the image so we can release the HBITMAP.
                        // 

                        //This bitmap is created by the com object which originally copied the bitmap to tbe 
                        //clipboard. We call Add here, since DeleteObject calls Remove. 
                        System.Internal.HandleCollector.Add(medium.unionmember, NativeMethods.CommonHandles.GDI);
                        Image clipboardImage = null; 
                        IntSecurity.ObjectFromWin32Handle.Assert();
                        try
                        {
                            clipboardImage = Image.FromHbitmap(medium.unionmember); 
                        }
                        finally 
                        { 
                            CodeAccessPermission.RevertAssert();
                        } 
                        if (clipboardImage != null) {
                            Image firstImage = clipboardImage;
                            clipboardImage = (Image)clipboardImage.Clone();
                            SafeNativeMethods.DeleteObject(new HandleRef(null, medium.unionmember)); 
                            firstImage.Dispose();
                        } 
                        data = clipboardImage; 
                    }
/* gpr: 
                    else if (format.Equals(DataFormats.EnhancedMetafile)) {
                        data = new Metafile(medium.unionmember);
                    }
*/ 
                }
 
                return data; 
            }
 
            /// 
            /// 
            ///     Extracts a managed Object from the innerData of the specified
            ///     format. This is the base of the OLE to managed conversion. 
            /// 
            ///  
            private Object GetDataFromBoundOleDataObject(string format) { 

                Object data = null; 
                try
                {
                    data = GetDataFromOleOther(format);
                    if (data == null) 
                    {
                        data = GetDataFromOleHGLOBAL(format); 
                    } 
                    if (data == null)
                    { 
                        data = GetDataFromOleIStream(format);
                    }
                }
                catch (Exception e) 
                {
                    Debug.Fail(e.ToString()); 
                } 
                return data;
            } 

            /// 
            /// 
            ///     Creates an Stream from the data stored in handle. 
            /// 
            ///  
            private Stream ReadByteStreamFromHandle(IntPtr handle, out bool isSerializedObject) { 
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle));
                if (ptr == IntPtr.Zero){ 
                    throw new ExternalException(SR.GetString(SR.ExternalException), NativeMethods.E_OUTOFMEMORY);
                }
                try {
                    int size = UnsafeNativeMethods.GlobalSize(new HandleRef(null, handle)); 
                    byte[] bytes = new byte[size];
                    Marshal.Copy(ptr, bytes, 0, size); 
                    int index = 0; 

                    // The object here can either be a stream or a serialized 
                    // object.  We identify a serialized object by writing the
                    // bytes for the guid serializedObjectID at the front
                    // of the stream.  Check for that here.
                    // 
                    if (size > serializedObjectID.Length) {
                        isSerializedObject = true; 
                        for(int i = 0; i < serializedObjectID.Length; i++) { 
                            if (serializedObjectID[i] != bytes[i]) {
                                isSerializedObject = false; 
                                break;
                            }
                        }
 
                        // Advance the byte pointer.
                        // 
                        if (isSerializedObject) { 
                            index = serializedObjectID.Length;
                        } 
                    }
                    else {
                        isSerializedObject = false;
                    } 

                    return new MemoryStream(bytes, index, bytes.Length - index); 
                } 
                finally {
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle)); 
                }
            }

            ///  
            /// 
            ///     Creates a new instance of the Object that has been persisted into the 
            ///     handle. 
            /// 
            ///  
            private Object ReadObjectFromHandle(IntPtr handle)
            {
                object value = null;
 
                bool isSerializedObject;
                Stream stream = ReadByteStreamFromHandle(handle, out isSerializedObject); 
 
                if (isSerializedObject) {
                    value = ReadObjectFromHandleDeserializer(stream); 
                }
                else {
                    value = stream;
                } 

                return value; 
            } 

            [ 
                SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.SerializationFormatter)
            ]
            private static Object ReadObjectFromHandleDeserializer(Stream stream) {
                BinaryFormatter formatter = new BinaryFormatter(); 
                formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
                return formatter.Deserialize(stream); 
            } 

            ///  
            /// 
            ///     Parses the HDROP format and returns a list of strings using
            ///     the DragQueryFile function.
            ///  
            /// 
            private string[] ReadFileListFromHandle(IntPtr hdrop) { 
 
                string[] files = null;
                StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); 

                int count = UnsafeNativeMethods.DragQueryFile(new HandleRef(null, hdrop), unchecked((int)0xFFFFFFFF), null, 0);
                if (count > 0) {
                    files = new string[count]; 

 
                    for (int i=0; i charlen) {
                            s = s.Substring(0, charlen);
                        }
 
                        // SECREVIEW : do we really need to do this?
                        // 
                        string fullPath = Path.GetFullPath(s); 
                        Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + fullPath + ") Demanded");
                        new FileIOPermission(FileIOPermissionAccess.PathDiscovery, fullPath).Demand(); 
                        files[i] = s;
                    }
                }
 
                return files;
            } 
 
            /// 
            ///  
            ///     Creates a string from the data stored in handle. If
            ///     unicode is set to true, then the string is assume to be Unicode,
            ///     else DBCS (ASCI) is assumed.
            ///  
            /// 
            private unsafe string ReadStringFromHandle(IntPtr handle, bool unicode) { 
                string stringData = null; 

                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle)); 
                try {
                    if (unicode) {
                        stringData = new string((char*)ptr);
                    } 
                    else {
                        stringData = new string((sbyte*)ptr); 
                    } 
                }
                finally { 
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
                }

                return stringData; 
            }
 
            //=------------------------------------------------------------------------= 
            // IDataObject
            //=-----------------------------------------------------------------------= 
            public virtual Object GetData(string format, bool autoConvert) {
                Object baseVar = GetDataFromBoundOleDataObject(format);
                Object original = baseVar;
 
                if (autoConvert && (baseVar == null || baseVar is MemoryStream)) {
                    string[] mappedFormats = GetMappedFormats(format); 
                    if (mappedFormats != null) { 
                        for (int i=0; i 0) { 
                        retrieved[0] = 0;
                        try { 
                            enumFORMATETC.Next(1, formatetc, retrieved); 
                        }
                        catch { 
                        }

                        if (retrieved[0] > 0) {
                            string name = DataFormats.GetFormat(formatetc[0].cfFormat).Name; 
                            if (autoConvert) {
                                string[] mappedFormats = GetMappedFormats(name); 
                                for (int i=0; i
        ///  
        /// 
        private class DataStore : IDataObject {
            private class DataStoreEntry {
                public Object data; 
                public bool autoConvert;
 
                public DataStoreEntry(Object data, bool autoConvert) { 
                    this.data = data;
                    this.autoConvert = autoConvert; 
                }
            }

            private Hashtable data = new Hashtable(BackCompatibleStringComparer.Default); 

            public DataStore() { 
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: Constructed DataStore"); 
            }
 
            public virtual Object GetData(string format, bool autoConvert) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetData: " + format + ", " + autoConvert.ToString());
                DataStoreEntry dse = (DataStoreEntry)data[format];
                Object baseVar = null; 
                if (dse != null) {
                    baseVar = dse.data; 
                } 
                Object original = baseVar;
 
                if (autoConvert
                    && (dse == null || dse.autoConvert)
                    && (baseVar == null || baseVar is MemoryStream)) {
 
                    string[] mappedFormats = GetMappedFormats(format);
                    if (mappedFormats != null) { 
                        for (int i=0; i

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK