File: winforms\Managed\System\WinForms\DataObject.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="DataObject.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
/*
 */
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;
 
    /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject"]/*' />
    /// <devdoc>
    ///    <para>Implements a basic data transfer mechanism.</para>
    /// </devdoc>
    [
        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;
        internal bool RestrictedFormats {get;set;}
 
        // 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();
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.DataObject"]/*' />
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Windows.Forms.DataObject'/> class, with the specified <see cref='System.Windows.Forms.IDataObject'/>.</para>
        /// </devdoc>
        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");
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.DataObject1"]/*' />
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Windows.Forms.DataObject'/> class, with the specified <see langword='IComDataObject'/>.</para>
        /// </devdoc>
        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");
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.DataObject2"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Windows.Forms.DataObject'/>
        ///       class, which can store arbitrary data.
        ///    </para>
        /// </devdoc>
        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");
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.DataObject3"]/*' />
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Windows.Forms.DataObject'/> class, containing the specified data.</para>
        /// </devdoc>
        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");
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.DataObject4"]/*' />
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Windows.Forms.DataObject'/> class, containing the specified data and its 
        ///    associated format.</para>
        /// </devdoc>
        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;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetData"]/*' />
        /// <devdoc>
        ///    <para>Retrieves the data associated with the specified data 
        ///       format, using an automated conversion parameter to determine whether to convert
        ///       the data to the format.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetData1"]/*' />
        /// <devdoc>
        ///    <para>Retrieves the data associated with the specified data 
        ///       format.</para>
        /// </devdoc>
        public virtual object GetData(string format) {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Request data: " + format);
            return GetData(format, true);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetData2"]/*' />
        /// <devdoc>
        ///    <para>Retrieves the data associated with the specified class 
        ///       type format.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetDataPresent"]/*' />
        /// <devdoc>
        ///    <para>Determines whether data stored in this instance is 
        ///       associated with, or can be converted to, the specified
        ///       format.</para>
        /// </devdoc>
        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;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetDataPresent1"]/*' />
        /// <devdoc>
        ///    <para>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.</para>
        /// </devdoc>
        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;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetDataPresent2"]/*' />
        /// <devdoc>
        ///    <para>Determines whether data stored in this instance is 
        ///       associated with, or can be converted to, the specified
        ///       format.</para>
        /// </devdoc>
        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;
        }
 
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetFormats"]/*' />
        /// <devdoc>
        ///    <para>Gets a list of all formats that data stored in this 
        ///       instance is associated with or can be converted to, using an automatic
        ///       conversion parameter<paramref name=" "/>to
        ///       determine whether to retrieve all formats that the data can be converted to or
        ///       only native data formats.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetFormats1"]/*' />
        /// <devdoc>
        ///    <para>Gets a list of all formats that data stored in this instance is associated
        ///       with or can be converted to.</para>
        /// </devdoc>
        public virtual string[] GetFormats() {
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "Check formats:");
            return GetFormats(true);
        }
 
        // <-- WHIDBEY ADDITIONS 
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.ContainsAudio"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual bool ContainsAudio() {
            return GetDataPresent(DataFormats.WaveAudio, false);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.ContainsFileDropList"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual bool ContainsFileDropList() {
            return GetDataPresent(DataFormats.FileDrop, true);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.ContainsImage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual bool ContainsImage() {
            return GetDataPresent(DataFormats.Bitmap, true);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.ContainsText"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual bool ContainsText() {
            return ContainsText(TextDataFormat.UnicodeText);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.ContainsText1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetAudioStream"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual Stream GetAudioStream() {
            return GetData(DataFormats.WaveAudio, false) as Stream;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetFileDropList"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual StringCollection GetFileDropList() {
            StringCollection retVal = new StringCollection();
            string[] strings = GetData(DataFormats.FileDrop, true) as string[];
            if (strings != null) {
                retVal.AddRange(strings);
            }
            return retVal;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetImage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual Image GetImage() {
            return GetData(DataFormats.Bitmap, true) as Image;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetText"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual string GetText() {
            return GetText(TextDataFormat.UnicodeText);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetText1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        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;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetAudio"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual void SetAudio(byte[] audioBytes) {
            if (audioBytes == null) {
                throw new ArgumentNullException("audioBytes");
            }
            SetAudio(new MemoryStream(audioBytes));
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetAudio1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual void SetAudio(Stream audioStream) {
            if (audioStream == null) {
                throw new ArgumentNullException("audioStream");
            }
            SetData(DataFormats.WaveAudio, false, audioStream);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetFileDropList"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetImage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual void SetImage(Image image) {
            if (image == null) {
                throw new ArgumentNullException("image");
            }
            SetData(DataFormats.Bitmap, true, image);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetText"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual void SetText(string textData) {
            SetText(textData, TextDataFormat.UnicodeText);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetText1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        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 -->
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetDistinctStrings"]/*' />
        /// <devdoc>
        ///     Retrieves a list of distinct strings from the array.
        /// </devdoc>
        private static string[] GetDistinctStrings(string[] formats) {
            ArrayList distinct = new ArrayList();
            for (int i=0; i<formats.Length; i++) {
                string s = formats[i];
                if (!distinct.Contains(s)) {
                    distinct.Add(s);
                }
            }
 
            string[] temp = new string[distinct.Count];
            distinct.CopyTo(temp, 0);
            return temp;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetMappedFormats"]/*' />
        /// <devdoc>
        ///     Returns all the "synonyms" for the specified format.
        /// </devdoc>
        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};
        }
 
        /*
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetMappedFormats1"]/*' />
        /// <devdoc>
        ///     Returns all distinct "synonyms" for the each of the formats.
        /// </devdoc>
        private static string[] GetMappedFormats(string[] formats) {
            ArrayList allChoices = new ArrayList();
 
            for (int i=0; i<formats.Length; i++) {
                allChoices.Add(formats[i]);
            }
 
            if (formats != null) {
                for (int i=0; i<formats.Length; i++) {
                    string[] r = GetMappedFormats(formats[i]);
                    if (r != null) {
                        for (int j=0; j<r.Length; j++) {
                            allChoices.Add(r[j]);
                        }
                    }
                }
            }
 
            string[] temp = new string[allChoices.Count];
            allChoices.CopyTo(temp, 0);
            return GetDistinctStrings(temp);
        }
        */
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetTymedUseable"]/*' />
        /// <devdoc>
        ///     Returns true if the tymed is useable.
        /// </devdoc>
        /// <internalonly/>
        private bool GetTymedUseable(TYMED tymed) {
            for (int i=0; i<ALLOWED_TYMEDS.Length; i++) {
                if ((tymed & ALLOWED_TYMEDS[i]) != 0) {
                    return true;
                }
            }
            return false;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.GetDataIntoOleStructs"]/*' />
        /// <devdoc>
        ///     Populates Ole datastructes from a Microsoft dataObject. This is the core
        ///     of Microsoft to OLE conversion.
        /// </devdoc>
        /// <internalonly/>
        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);
            }
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.DAdvise"]/*' />
        /// <internalonly/>
        // 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);
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.DUnadvise"]/*' />
        /// <internalonly/>
        // 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);
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.EnumDAdvise"]/*' />
        /// <internalonly/>
        // 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);
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.EnumFormatEtc"]/*' />
        /// <internalonly/>
        // 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);
            }
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.GetCanonicalFormatEtc"]/*' />
        /// <internalonly/>
        // 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);
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.GetData"]/*' />
        /// <internalonly/>
        // 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);
            }
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.GetDataHere"]/*' />
        /// <internalonly/>
        // 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);
            }
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.QueryGetData"]/*' />
        /// <internalonly/>
        // 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 = unchecked((ushort)formatetc.cfFormat);
            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "QueryGetData::cfFormat " + format.ToString(CultureInfo.InvariantCulture) + " found");
            #endif
            return NativeMethods.S_OK;
        }
 
        // <devdoc>
        //     Part of IComDataObject, used to interop with OLE.
        // </devdoc>
        // <internalonly/>
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.IComDataObject.SetData"]/*' />
        /// <internalonly/>
        // 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.OemText)) {
                hr = SaveStringToHandle(medium.unionmember, data.ToString(), false);
            }
            else if (format.Equals(DataFormats.Html)) {
                if (WindowsFormsUtils.TargetsAtLeast_v4_5) {
                    hr = SaveHtmlToHandle(medium.unionmember, data.ToString());
                }
                else {
                    // This will return UTF-8 strings as an array of ANSI characters, which makes it the wrong behavior.
                    // Since there are enough samples online how to workaround that, we will continue to return the
                    // incorrect value to applications targeting netfx 4.0
                    // DevDiv2 bug 862524
                    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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SaveStreamToHandle"]/*' />
        /// <devdoc>
        ///     Saves stream out to handle.
        /// </devdoc>
        /// <internalonly/>
        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;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SaveFileListToHandle"]/*' />
        /// <devdoc>
        ///     Saves a list of files out to the handle in HDROP format.
        /// </devdoc>
        /// <internalonly/>
        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<files.Length; i++) {
                    sizeInBytes += (files[i].Length + 1) * 2;
                }
                sizeInBytes += 2;
            }
            else {
                for (int i=0; i<files.Length; i++) {
                    sizeInBytes += NativeMethods.Util.GetPInvokeStringLength(files[i]) + 1;
                }
                sizeInBytes ++;
            }
 
            // Alloc the Win32 memory
            //
            IntPtr newHandle = UnsafeNativeMethods.GlobalReAlloc(new HandleRef(null, handle),
                                                  sizeInBytes,
                                                  NativeMethods.GMEM_MOVEABLE | NativeMethods.GMEM_DDESHARE);
            if (newHandle == IntPtr.Zero) {
                return (NativeMethods.E_OUTOFMEMORY);
            }
            IntPtr basePtr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, newHandle));
            if (basePtr == IntPtr.Zero) {
                return (NativeMethods.E_OUTOFMEMORY);
            }
            currentPtr = basePtr;
 
            // Write out the struct...
            //
            int[] structData = new int[] {baseStructSize, 0, 0, 0, 0};
 
            if (unicode) {
                structData[4] = unchecked((int)0xFFFFFFFF);
            }
            Marshal.Copy(structData, 0, currentPtr, structData.Length);
            currentPtr = (IntPtr)((long)currentPtr + baseStructSize);
 
            // Write out the strings...
            //
            for (int i=0; i<files.Length; i++) {
                if (unicode) {
 
                    // NOTE: DllLib.copy(char[]...) converts to ANSI on Windows 95...
                    UnsafeNativeMethods.CopyMemoryW(currentPtr, files[i], files[i].Length*2);
                    currentPtr = (IntPtr)((long)currentPtr + (files[i].Length * 2));
                    Marshal.Copy(new byte[]{0,0}, 0, currentPtr, 2);
                    currentPtr = (IntPtr)((long)currentPtr + 2);
                }
                else {
                    int pinvokeLen = NativeMethods.Util.GetPInvokeStringLength(files[i]);
                    UnsafeNativeMethods.CopyMemoryA(currentPtr, files[i], pinvokeLen);
                    currentPtr = (IntPtr)((long)currentPtr + pinvokeLen);
                    Marshal.Copy(new byte[]{0}, 0, currentPtr, 1);
                    currentPtr = (IntPtr)((long)currentPtr + 1);
                }
            }
 
            if (unicode) {
                Marshal.Copy(new char[]{'\0'}, 0, currentPtr, 1);
                currentPtr = (IntPtr)((long)currentPtr + 2);
            }
            else {
                Marshal.Copy(new byte[]{0}, 0, currentPtr, 1);
                currentPtr = (IntPtr)((long)currentPtr + 1);
            }
 
            UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, newHandle));
            return NativeMethods.S_OK;
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SaveStringToHandle"]/*' />
        /// <devdoc>
        ///     Save string to handle. If unicode is set to true
        ///     then the string is saved as Unicode, else it is saves as DBCS.
        /// </devdoc>
        /// <internalonly/>
        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;
        }
 
        private int SaveHtmlToHandle(IntPtr handle, string str) {
            if (handle == IntPtr.Zero) {
                return (NativeMethods.E_INVALIDARG);
            }
            IntPtr newHandle = IntPtr.Zero;
           
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            byte[] bytes = encoding.GetBytes(str);
               
            newHandle = UnsafeNativeMethods.GlobalReAlloc(new HandleRef(null, handle),
                                                    bytes.Length +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);
            }
            try { 
                UnsafeNativeMethods.CopyMemory(ptr, bytes, bytes.Length);
                Marshal.Copy(new byte[] { 0 }, 0, (IntPtr)((long)ptr + bytes.Length), 1);
            }
            finally {
                UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, newHandle));
            }
            return NativeMethods.S_OK;
        }
 
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetData"]/*' />
        /// <devdoc>
        ///    <para>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.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetData1"]/*' />
        /// <devdoc>
        ///    <para>Stores the specified data and its associated format in this
        ///       instance.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetData2"]/*' />
        /// <devdoc>
        ///    <para>Stores the specified data and
        ///       its
        ///       associated class type in this instance.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.SetData3"]/*' />
        /// <devdoc>
        ///    <para>Stores the specified data in
        ///       this instance, using the class of the data for the format.</para>
        /// </devdoc>
        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);
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.FormatEnumerator"]/*' />
        /// <devdoc>
        ///     Part of IComDataObject, used to interop with OLE.
        /// </devdoc>
        /// <internalonly/>
        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) {
                    DataObject dataObject = parent as DataObject;
                    if (dataObject != null && dataObject.RestrictedFormats) {
                        if (!Clipboard.IsFormatValid(formats)) {
                            throw new SecurityException(SR.GetString(SR.ClipboardSecurityException));
                        }
                    }
 
                    for (int i=0; i<formats.Length; i++) {
                        FORMATETC currentFormat = formats[i];
 
                        FORMATETC temp = new FORMATETC();
                        temp.cfFormat = currentFormat.cfFormat;
                        temp.dwAspect = currentFormat.dwAspect;
                        temp.ptd = currentFormat.ptd;
                        temp.lindex = currentFormat.lindex;
                        temp.tymed = currentFormat.tymed;
                        this.formats.Add(temp);
                    }
                }
            }
 
            public FormatEnumerator(IDataObject parent, string[] formats) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Constructed: " + parent.ToString() + ", string[]" + formats.Length.ToString(CultureInfo.InvariantCulture));
 
                this.parent = parent;
                this.formats.Clear();
 
                string bitmap = DataFormats.Bitmap;
                string emf = DataFormats.EnhancedMetafile;
                string text = DataFormats.Text;
                string unicode = DataFormats.UnicodeText;
                string standard = DataFormats.StringFormat;
                string str = DataFormats.StringFormat;
 
                if (formats != null) {
 
                    DataObject dataObject = parent as DataObject;
                    if (dataObject != null && dataObject.RestrictedFormats) {
                        if (!Clipboard.IsFormatValid(formats)) {
                            throw new SecurityException(SR.GetString(SR.ClipboardSecurityException));
                        }
                    }
 
                    for (int i=0; i<formats.Length; i++) {
                        string format = formats[i];
                        FORMATETC temp = new FORMATETC();
                        temp.cfFormat = unchecked((short)(ushort)(DataFormats.GetFormat(format).Id));
                        temp.dwAspect = DVASPECT.DVASPECT_CONTENT;
                        temp.ptd = IntPtr.Zero;
                        temp.lindex = -1;
 
                        if (format.Equals(bitmap)) {
                            temp.tymed = TYMED.TYMED_GDI;
                        }
                        else if (format.Equals(emf)) {
                            temp.tymed = TYMED.TYMED_ENHMF;
                        }
                        else if (format.Equals(text)
                                 || format.Equals(unicode)
                                 || format.Equals(standard)
                                 || format.Equals(str)
                                 || format.Equals(DataFormats.Rtf)
                                 || format.Equals(DataFormats.CommaSeparatedValue)
                                 || format.Equals(DataFormats.FileDrop)
                                 || format.Equals(CF_DEPRECATED_FILENAME)
                                 || format.Equals(CF_DEPRECATED_FILENAMEW)) {
 
                            temp.tymed = TYMED.TYMED_HGLOBAL;
                        }
                        else {
                            temp.tymed = TYMED.TYMED_HGLOBAL;
                        }
 
                        if (temp.tymed != 0) {
                            this.formats.Add(temp);
                        }
                    }
                }
            }
 
            public int Next(int celt, FORMATETC[] rgelt, int[] pceltFetched) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "FormatEnumerator: Next");
                if (this.current < formats.Count && celt > 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);
            }
        }
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter"]/*' />
        /// <devdoc>
        ///     OLE Converter.  This class embodies the nastiness required to convert from our
        ///     managed types to standard OLE clipboard formats.
        /// </devdoc>
        private class OleConverter : IDataObject {
            internal IComDataObject innerData;
 
            public OleConverter(IComDataObject data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "OleConverter: Constructed OleConverter");
                innerData = data;
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.OleDataObject"]/*' />
            /// <devdoc>
            ///     Returns the data Object we are wrapping
            /// </devdoc>
            /// <internalonly/>
            public IComDataObject OleDataObject {
                get {
                    return innerData;
                }
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.GetDataFromOleIStream"]/*' />
            /// <devdoc>
            ///     Uses IStream and retrieves the specified format from the bound IComDataObject.
            /// </devdoc>
            /// <internalonly/>
            private Object GetDataFromOleIStream(string format) {
 
                FORMATETC formatetc = new FORMATETC();
                STGMEDIUM medium = new STGMEDIUM();
 
                formatetc.cfFormat = unchecked((short)(ushort)(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 != QueryGetDataUnsafe(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;
            }
 
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.GetDataFromHGLOBLAL"]/*' />
            /// <devdoc>
            ///     Retrieves the specified form from the specified hglobal.
            /// </devdoc>
            /// <internalonly/>
            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.OemText)) {
                        data = ReadStringFromHandle(hglobal, false);
                    } 
                    else if (format.Equals(DataFormats.Html)) {
                        if (WindowsFormsUtils.TargetsAtLeast_v4_5) {
                            data = ReadHtmlFromHandle(hglobal);
                        } 
                        else {
                            // This will return UTF-8 strings as an array of ANSI characters, which makes it the wrong behavior.
                            // Since there are enough samples online how to workaround that, we will continue to return the
                            // incorrect value to applications targeting netfx 4.0
                            // DevDiv2 bug 862524
                            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 if (!LocalAppContextSwitches.EnableLegacyDangerousClipboardDeserializationMode) {
                        // We are restricting all formats that might eventually be processed by the BinaryFormatter 
                        // in ReadObjectFromHandleDeserializer to allow only primitive types.
                        // Application might opt-out from the secure deserialization mode by adding this
                        // switch to app.config file, unless the machine has device guard enabled, in that case 
                        // applications can't can't opt out from restricted deserialization:
                        // <runtime>
                        // <AppContextSwitchOverrides value = "Switch.System.Windows.Forms.EnableLegacyDangerousClipboardDeserializationMode=true" />
                        //</runtime>
                        bool restrictDeserialization = 
                            (format.Equals(DataFormats.StringFormat) ||
                            format.Equals(typeof(Bitmap).FullName) ||
                            format.Equals(DataFormats.CommaSeparatedValue) ||
                            format.Equals(DataFormats.Dib) ||
                            format.Equals(DataFormats.Dif) ||
                            format.Equals(DataFormats.Locale) ||
                            format.Equals(DataFormats.PenData) ||
                            format.Equals(DataFormats.Riff) ||
                            format.Equals(DataFormats.SymbolicLink) ||
                            format.Equals(DataFormats.Tiff) ||
                            format.Equals(DataFormats.WaveAudio) ||
                            format.Equals(DataFormats.Bitmap) ||
                            format.Equals(DataFormats.EnhancedMetafile) ||
                            format.Equals(DataFormats.Palette) ||
                            format.Equals(DataFormats.MetafilePict));
                    data = ReadObjectFromHandle(hglobal, restrictDeserialization);
                    }
                    else {
                        data = ReadObjectFromHandle(hglobal, restrictDeserialization: false);
                        /*
                        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;
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.GetDataFromOleHGLOBAL"]/*' />
            /// <devdoc>
            ///     Uses HGLOBALs and retrieves the specified format from the bound IComDatabject.
            /// </devdoc>
            /// <internalonly/>
            private Object GetDataFromOleHGLOBAL(string format, out bool done) {
                done = false;
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
 
                FORMATETC formatetc = new FORMATETC();
                STGMEDIUM medium = new STGMEDIUM();
 
                formatetc.cfFormat = unchecked((short)(ushort)(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 == QueryGetDataUnsafe(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 (RestrictedTypeDeserializationException) {
                        done = true;
                    }
                    catch {
                    }
                }
                return data;
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.GetDataFromOleOther"]/*' />
            /// <devdoc>
            ///     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.
            /// </devdoc>
            /// <internalonly/>
            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 = unchecked((short)(ushort)(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 == QueryGetDataUnsafe(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;
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.GetDataFromBoundOleDataObject"]/*' />
            /// <devdoc>
            ///     Extracts a managed Object from the innerData of the specified
            ///     format. This is the base of the OLE to managed conversion.
            /// </devdoc>
            /// <internalonly/>
            private Object GetDataFromBoundOleDataObject(string format, out bool done) {
                Object data = null;
                done = false;
                try 
                {
                    data = GetDataFromOleOther(format);
                    if (data == null)
                    {
                        data = GetDataFromOleHGLOBAL(format, out done);
                    }
                    if (data == null && !done)
                    {
                        data = GetDataFromOleIStream(format);
                    }
                }
                catch (Exception e)
                {
                    Debug.Fail(e.ToString());
                }
                return data;
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.ReadByteStreamFromHandle"]/*' />
            /// <devdoc>
            ///     Creates an Stream from the data stored in handle.
            /// </devdoc>
            /// <internalonly/>
            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));
                }
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.ReadObjectFromHandle"]/*' />
            /// <devdoc>
            ///     Creates a new instance of the Object that has been persisted into the
            ///     handle.
            /// </devdoc>
            /// <internalonly/>
            private Object ReadObjectFromHandle(IntPtr handle, bool restrictDeserialization)
            {
                object value = null;
                
                bool isSerializedObject;
                Stream stream = ReadByteStreamFromHandle(handle, out isSerializedObject);
                
                if (isSerializedObject) {
                    value = ReadObjectFromHandleDeserializer(stream, restrictDeserialization);
                }
                else {
                    value = stream;  
                }
 
                return value;
            }
 
            private static Object ReadObjectFromHandleDeserializer(Stream stream, bool restrictDeserialization) {
                BinaryFormatter formatter = new BinaryFormatter();
 
                if (restrictDeserialization) {
                    formatter.Binder = new RestrictiveBinder();
                }
                formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
                return formatter.Deserialize(stream);
            }
            
            /// <summary>
            /// Binder that restricts dataobject content deserialization to safe types.
            /// </summary>
            private class RestrictiveBinder : SerializationBinder {
                private static string s_allowedTypeName;
                private static string s_allowedAssemblyName;
                private static byte[] s_allowedToken;
 
                static RestrictiveBinder() {
                    s_allowedTypeName = typeof(Bitmap).FullName;
                    AssemblyName assemblyName = new AssemblyName(typeof(Bitmap).Assembly.FullName);
                    if (assemblyName != null) {
                        s_allowedAssemblyName = assemblyName.Name;
                        s_allowedToken = assemblyName.GetPublicKeyToken();
                    }
                }
 
                /// <summary>
                ///  Only safe to deserialize types are bypassing this callback, Strings 
                ///  and arrays of primitive types in particular. We are explicitly allowing
                ///  System.Drawing.Bitmap type to bind using the default binder.
                /// </summary>
                /// <param name="assemblyName"></param>
                /// <param name="typeName"></param>
                /// <returns></returns>
                public override Type BindToType(string assemblyName, string typeName) {
                    if (string.CompareOrdinal(typeName, s_allowedTypeName) == 0)  {
                        AssemblyName nameToBind = null;
                        try {
                            nameToBind = new AssemblyName(assemblyName);
                        }
                        catch {
                        }
                        if (nameToBind != null) {
                            if (string.CompareOrdinal(nameToBind.Name, s_allowedAssemblyName) == 0) {
                                byte[] tokenToBind = nameToBind.GetPublicKeyToken();
                                if ((tokenToBind != null) && 
                                    (s_allowedToken != null) && 
                                    (tokenToBind.Length == s_allowedToken.Length)) {
                                    bool block = false;
                                    for (int i = 0; i < s_allowedToken.Length; i++) {
                                        if (s_allowedToken[i] != tokenToBind[i]) {
                                            block = true;
                                            break;
                                        }
                                    }
                                    if (!block) {
                                        return null;
                                    }
                                }
                            }
                        }
                    }
                    throw new RestrictedTypeDeserializationException();
                }
            }
 
            /// <summary>
            /// This exceptionm is used to indicate that clipboard contains a serialized 
            /// managed object that contains unexpected types. 
            /// </summary>
            private class RestrictedTypeDeserializationException : Exception {
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.ReadFileListFromHandle"]/*' />
            /// <devdoc>
            ///     Parses the HDROP format and returns a list of strings using
            ///     the DragQueryFile function.
            /// </devdoc>
            /// <internalonly/>
            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<count; i++) {
                        int charlen = UnsafeNativeMethods.DragQueryFileLongPath(new HandleRef(null, hdrop), i, sb);
                        if (0 == charlen)
                            continue;
                        string s = sb.ToString(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;
            }
 
            /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.OleConverter.ReadStringFromHandle"]/*' />
            /// <devdoc>
            ///     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.
            /// </devdoc>
            /// <internalonly/>
            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;
            }            
 
            // Dev11 92568 Garbled Japanese is produced when a text message is cut and pasted on the editor in Team Explorer of TFS 2010 (was DTS)
            private unsafe string ReadHtmlFromHandle(IntPtr handle) {
                string stringData = null;
                IntPtr ptr = UnsafeNativeMethods.GlobalLock(new HandleRef(null, handle));
                try {
                    int size = UnsafeNativeMethods.GlobalSize(new HandleRef(null, handle));
                    byte[] bytes = new byte[size];
                    Marshal.Copy(ptr, bytes, 0, size);
                    stringData = Encoding.UTF8.GetString(bytes); 
                }
                finally {
                    UnsafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
                }
  
                return stringData;
           }            
 
 
            //=------------------------------------------------------------------------=
            // IDataObject
            //=------------------------------------------------------------------------=
            public virtual Object GetData(string format, bool autoConvert) {
                bool done = false;
                Object baseVar = GetDataFromBoundOleDataObject(format, out done);
                Object original = baseVar;
 
                if (!done && autoConvert && (baseVar == null || baseVar is MemoryStream)) {
                    string[] mappedFormats = GetMappedFormats(format);
                    if (mappedFormats != null) {
                        for (int i=0; ((!done) && (i<mappedFormats.Length)); i++) {
                            if (!format.Equals(mappedFormats[i])) {
                                baseVar = GetDataFromBoundOleDataObject(mappedFormats[i], out done);
                                if (!done && baseVar != null && !(baseVar is MemoryStream)) {
                                    original = null;
                                    break;
                                }
                            }
                        }
                    }
                }
 
                if (original != null) {
                    return original;
                }
                else {
                    return baseVar;
                }
            }
 
            public virtual Object GetData(string format) {
                return GetData(format, true);
            }
 
            public virtual Object GetData(Type format) {
                return GetData(format.FullName);
            }
 
            public virtual void SetData(string format, bool autoConvert, Object data) {
                // 
 
 
            }
            public virtual void SetData(string format, Object data) {
                SetData(format, true, data);
            }
 
            public virtual void SetData(Type format, Object data) {
                SetData(format.FullName, data);
            }
 
            public virtual void SetData(Object data) {
                if (data is ISerializable) {
                    SetData(DataFormats.Serializable, data);
                }
                else {
                    SetData(data.GetType(), data);
                }
            }
 
            [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
            private int QueryGetDataUnsafe(ref FORMATETC formatetc) {
                return innerData.QueryGetData(ref formatetc);
            }
 
            private int QueryGetDataInner(ref FORMATETC formatetc)
            {
                return innerData.QueryGetData(ref formatetc);
            }
 
            public virtual bool GetDataPresent(Type format) {
                return GetDataPresent(format.FullName);
            }
 
            private bool GetDataPresentInner(string format) {
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
                FORMATETC formatetc = new FORMATETC();
                formatetc.cfFormat = unchecked((short)(ushort)(DataFormats.GetFormat(format).Id));
                formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatetc.lindex = -1;
 
                for (int i=0; i<ALLOWED_TYMEDS.Length; i++) {
                    formatetc.tymed |= ALLOWED_TYMEDS[i];
                }
 
                int hr = QueryGetDataUnsafe(ref formatetc);
                return (hr == NativeMethods.S_OK);
            }
 
            public virtual bool GetDataPresent(string format, bool autoConvert) {
                IntSecurity.ClipboardRead.Demand();
                bool baseVar = false;
                
                IntSecurity.UnmanagedCode.Assert();
                try {
                     baseVar = GetDataPresentInner(format);
                }
                finally {
                    CodeAccessPermission.RevertAssert();
                }
                
                if (!baseVar && autoConvert) {
                    string[] mappedFormats = GetMappedFormats(format);
                    if (mappedFormats != null) {
                        for (int i=0; i<mappedFormats.Length; i++) {
                            if (!format.Equals(mappedFormats[i])) {
                                IntSecurity.UnmanagedCode.Assert();
                                try {
                                     baseVar = GetDataPresentInner(mappedFormats[i]);
                                }
                                finally {
                                    CodeAccessPermission.RevertAssert();
                                }
                                if (baseVar) {
                                    break;
                                }
                            }
                        }
                    }
                }
                return baseVar;
            }
 
            public virtual bool GetDataPresent(string format) {
                return GetDataPresent(format, true);
            }
 
            public virtual string[] GetFormats(bool autoConvert) {
                Debug.Assert(innerData != null, "You must have an innerData on all DataObjects");
 
                IEnumFORMATETC enumFORMATETC = null;
                ArrayList formats = new ArrayList();
                try {
                    enumFORMATETC = innerData.EnumFormatEtc(DATADIR.DATADIR_GET);
                }
                catch {
                }
 
                if (enumFORMATETC != null) {
                    enumFORMATETC.Reset();
 
                    FORMATETC[] formatetc = new FORMATETC[] { new FORMATETC()};
                    int[] retrieved = new int[] {1};
 
                    while (retrieved[0] > 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<mappedFormats.Length; i++) {
                                    formats.Add(mappedFormats[i]);
                                }
                            }
                            else {
                                formats.Add(name);
                            }
                        }
                    }
                }
 
                string[] temp = new string[formats.Count];
                formats.CopyTo(temp, 0);
                return GetDistinctStrings(temp);
            }
 
            public virtual string[] GetFormats() {
                return GetFormats(true);
            }
 
 
            
        }
 
        //--------------------------------------------------------------------------
        // Data Store
        //--------------------------------------------------------------------------
 
        /// <include file='doc\DataObject.uex' path='docs/doc[@for="DataObject.DataStore"]/*' />
        /// <devdoc>
        /// </devdoc>
        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<mappedFormats.Length; i++) {
                            if (!format.Equals(mappedFormats[i])) {
                                DataStoreEntry found = (DataStoreEntry)data[mappedFormats[i]];
                                if (found != null) {
                                    baseVar = found.data;
                                }
                                if (baseVar != null && !(baseVar is MemoryStream)) {
                                    original = null;
                                    break;
                                }
                            }
                        }
                    }
                }
 
                if (original != null) {
                    return original;
                }
                else {
                    return baseVar;
                }
            }
 
            public virtual Object GetData(string format) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetData: " + format);
                return GetData(format, true);
            }
 
            public virtual Object GetData(Type format) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetData: " + format.FullName);
                return GetData(format.FullName);
            }            
 
            public virtual void SetData(string format, bool autoConvert, Object data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: SetData: " + format + ", " + autoConvert.ToString() + ", " + data.ToString());
 
                // We do not have proper support for Dibs, so if the user explicitly asked
                // for Dib and provided a Bitmap object we can't convert.  Instead, publish as an HBITMAP
                // and let the system provide the conversion for us.
                //
                if (data is Bitmap && format.Equals(DataFormats.Dib)) {
                    if (autoConvert) {
                        format = DataFormats.Bitmap;
                    }
                    else {
                        throw new NotSupportedException(SR.GetString(SR.DataObjectDibNotSupported));
                    }
                }
 
                this.data[format] = new DataStoreEntry(data, autoConvert);
            }
            public virtual void SetData(string format, Object data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: SetData: " + format + ", " + data.ToString());
                SetData(format, true, data);
            }
 
            public virtual void SetData(Type format, Object data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: SetData: " + format.FullName + ", " + data.ToString());
                SetData(format.FullName, data);
            }
 
            public virtual void SetData(Object data) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: SetData: " + data.ToString());
                if (data is ISerializable
                    && !this.data.ContainsKey(DataFormats.Serializable)) {
 
                    SetData(DataFormats.Serializable, data);
                }
 
                SetData(data.GetType(), data);
            }
 
            public virtual bool GetDataPresent(Type format) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetDataPresent: " + format.FullName);
                return GetDataPresent(format.FullName);
            }
 
            public virtual bool GetDataPresent(string format, bool autoConvert) {
                Debug.Assert(format != null, "Null format passed in");
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetDataPresent: " + format + ", " + autoConvert.ToString());
 
                if (!autoConvert) {
                    Debug.Assert(data != null, "data must be non-null");
                    return data.ContainsKey(format);
                }
                else {
                    string[] formats = GetFormats(autoConvert);
                    Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore:  got " + formats.Length.ToString(CultureInfo.InvariantCulture) + " formats from get formats");
                    Debug.Assert(formats != null, "Null returned from GetFormats");
                    for (int i=0; i<formats.Length; i++) {
                        Debug.Assert(formats[i] != null, "Null format inside of formats at index " + i.ToString(CultureInfo.InvariantCulture));
                        if (format.Equals(formats[i])) {
                            Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetDataPresent: returning true");
                            return true;
                        }
                    }
                    Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetDataPresent: returning false");
                    return false;
                }
            }
 
            public virtual bool GetDataPresent(string format) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetDataPresent: " + format);
                return GetDataPresent(format, true);
            }
 
            public virtual string[] GetFormats(bool autoConvert) {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetFormats: " + autoConvert.ToString());
                Debug.Assert(data != null, "data collection can't be null");
                Debug.Assert(data.Keys != null, "data Keys collection can't be null");
 
                string [] baseVar = new string[data.Keys.Count];
                data.Keys.CopyTo(baseVar, 0);
                Debug.Assert(baseVar != null, "Collections should never return NULL arrays!!!");
                if (autoConvert) {
                    Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: applying autoConvert");
 
                    ArrayList formats = new ArrayList();
                    for (int i=0; i<baseVar.Length; i++) {
                        Debug.Assert(data[baseVar[i]] != null, "Null item in data collection with key '" + baseVar[i] + "'");
                        if (((DataStoreEntry)data[baseVar[i]]).autoConvert) {
 
                            string[] cur = GetMappedFormats(baseVar[i]);
                            Debug.Assert(cur != null, "GetMappedFormats returned null for '" + baseVar[i] + "'");
                            for (int j=0; j<cur.Length; j++) {
                                formats.Add(cur[j]);
                            }
                        }
                        else {
                            formats.Add(baseVar[i]);
                        }
                    }
 
                    string[] temp = new string[formats.Count];
                    formats.CopyTo(temp, 0);
                    baseVar = GetDistinctStrings(temp);
                }
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: returing " + baseVar.Length.ToString(CultureInfo.InvariantCulture) + " formats from GetFormats");
                return baseVar;
            }
            public virtual string[] GetFormats() {
                Debug.WriteLineIf(CompModSwitches.DataObject.TraceVerbose, "DataStore: GetFormats");
                return GetFormats(true);
            }
        }
    }
}