WriteableBitmap.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / Imaging / WriteableBitmap.cs / 1 / WriteableBitmap.cs

                            //------------------------------------------------------------------------------ 
//
//  Copyright (c) Microsoft Corporation.  All Rights Reserved.
//
//  File: WriteableBitmap.cs 
//-----------------------------------------------------------------------------
 
using System; 
using System.IO;
using System.Collections; 
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Reflection; 
using MS.Internal;
using MS.Win32.PresentationCore; 
using System.Security; 
using System.Security.Permissions;
using System.Diagnostics; 
using System.Windows.Media;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows; 
using System.Windows.Media.Animation;
using System.Windows.Media.Composition; 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.PresentationCore;                        // SecurityHelper 
using System.Threading;

namespace System.Windows.Media.Imaging
{ 
    /// 
    ///   WriteableBitmap provides an efficient, tear-free mechanism for updating 
    ///   a system-memory bitmap. 
    /// 
    public sealed class WriteableBitmap : System.Windows.Media.Imaging.BitmapSource 
    {
        #region Constructors

        ///  
        ///     Internal constructor
        ///  
        internal WriteableBitmap() 
        {
        } 

        /// 
        ///     Creates a new WriteableBitmap instance initialized with the
        ///     contents of the specified BitmapSource. 
        /// 
        ///  
        ///     The BitmapSource to copy. 
        /// 
        ///  
        ///     Critical: Creates and accesses a handle to an unmanaged resource.
        ///     PublicOK: Inputs are safe.
        /// 
        [SecurityCritical] 
        public WriteableBitmap(
            BitmapSource source 
            ) 
            : base(true) // Use base class virtuals
        { 
            InitFromBitmapSource(source);
        }

        ///  
        ///   Initializes a new instance of the WriteableBitmap class with
        ///   the specified parameters. 
        ///  
        /// The desired width of the bitmap.
        /// The desired height of the bitmap. 
        /// The horizontal dots per inch (dpi) of the bitmap.
        /// The vertical dots per inch (dpi) of the bitmap.
        /// The PixelFormat of the bitmap.
        /// The BitmapPalette of the bitmap. 
        /// 
        ///   Critical: Creates and accesses a handle to an unmanaged resource. 
        ///   PublicOK: Inputs are safe. 
        /// 
        [SecurityCritical] 
        public WriteableBitmap(
            int pixelWidth,
            int pixelHeight,
            double dpiX, 
            double dpiY,
            PixelFormat pixelFormat, 
            BitmapPalette palette 
            )
            : base(true) // Use base class virtuals 
        {
            BeginInit();

            // 
            // Sanitize inputs
            // 
 
            if (pixelFormat == null)
            { 
                // Backwards Compat:
                //
                // The original code would null-ref, but we choose to raise a
                // better exception. 
                throw new ArgumentNullException("pixelFormat");
            } 
 
            if (pixelFormat.Palettized && palette == null)
            { 
                throw new InvalidOperationException(SR.Get(SRID.Image_IndexedPixelFormatRequiresPalette));
            }

            if (pixelFormat.Format == PixelFormatEnum.Extended) 
            {
                // We don't support third-party pixel formats yet. 
                throw new ArgumentException(SR.Get(SRID.Effect_PixelFormat), "pixelFormat"); 
            }
 
            if (pixelWidth < 0)
            {
                // Backwards Compat
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
            }
 
            if (pixelWidth == 0) 
            {
                // Backwards Compat 
                HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG);
            }

            if (pixelHeight < 0) 
            {
                // Backwards Compat 
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
            }
 
            if (pixelHeight == 0)
            {
                // Backwards Compat
                HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG); 
            }
 
            // 
            // Create and initialize a new unmanaged double buffered bitmap.
            // 
            Guid formatGuid = pixelFormat.Guid;

            // This SafeMILHandle gets ignored if the pixel format is not palettized.
            SafeMILHandle internalPalette = new SafeMILHandle(); 
            if (pixelFormat.Palettized)
            { 
                internalPalette = palette.InternalPalette; 
            }
 
            HRESULT.Check(MILSwDoubleBufferedBitmap.Create(
                (uint) pixelWidth, // safe cast
                (uint) pixelHeight, // safe cast
                dpiX, 
                dpiY,
                ref formatGuid, 
                internalPalette, 
                out _pDoubleBufferedBitmap
                )); 

            // Momentarily lock to populate the BackBuffer/BackBufferStride properties.
            Lock();
            Unlock(); 

            EndInit(); 
        } 

        #endregion // Constructors 

        #region Public Methods

        ///  
        ///   Adds a dirty region to the WriteableBitmap's back buffer.
        ///  
        ///  
        ///   An Int32Rect structure specifying the dirty region.
        ///  
        /// 
        ///   This method can be called multiple times, and the areas are accumulated
        ///   in a sufficient, but not necessarily minimal, representation.  For efficiency,
        ///   only the areas that are marked as dirty are guaranteed to be copied over to 
        ///   the rendering system.
        ///   AddDirtyRect can only be called while the bitmap is locked, otherwise an 
        ///   InvalidOperationException will be thrown. 
        /// 
        ///  
        ///   Critical: Accesses a handle to an unmanaged resource.
        ///   PublicOK: Input dirty rect is sanitized before use.
        /// 
        [SecurityCritical] 
        public void AddDirtyRect(Int32Rect dirtyRect)
        { 
            WritePreamble(); 

            if (_lockCount == 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Image_MustBeLocked));
            }
 
            //
            // Sanitize the dirty rect. 
            // 
            if (dirtyRect.X < 0)
            { 
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterCannotBeNegative));
            }

            if (dirtyRect.Y < 0) 
            {
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterCannotBeNegative)); 
            } 

            if (dirtyRect.Width < 0 || dirtyRect.Width > _pixelWidth) 
            {
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth));
            }
 
            if (dirtyRect.Height < 0 || dirtyRect.Height > _pixelHeight)
            { 
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight)); 
            }
 
            if (!dirtyRect.IsEmpty)
            {
                MILSwDoubleBufferedBitmap.AddDirtyRect(
                    _pDoubleBufferedBitmap, 
                    ref dirtyRect);
 
                _hasDirtyRects = true; 
            }
 
            // Note: we do not call WritePostscript because we do not want to
            // raise change notifications until the writeable bitmap is unlocked.
        }
 
        /// 
        ///   Shadows inherited Copy() with a strongly typed version for convenience. 
        ///  
        public new WriteableBitmap Clone()
        { 
            return (WriteableBitmap)base.Clone();
        }

        ///  
        ///   Shadows inherited CloneCurrentValue() with a strongly typed version for convenience.
        ///  
        public new WriteableBitmap CloneCurrentValue() 
        {
            return (WriteableBitmap)base.CloneCurrentValue(); 
        }

        /// 
        ///     This method locks the WriteableBitmap and increments the lock count. 
        /// 
        ///  
        ///     By "locking" the WriteableBitmap, updates will not be sent to the rendering system until 
        ///     the WriteableBitmap is fully unlocked.  This can be used to support multi-threaded scenarios.
        ///     This method blocks until the rendering system is finished processing the last frame's update. 
        ///     To provide a timeout see WriteableBitmap.TryLock.
        ///     Locking the WriteableBitmap gives the caller write permission to the back buffer whose address
        ///     can be obtained via the WriteableBitmap.BackBuffer property.
        ///  
        public void Lock()
        { 
            bool locked = TryLock(Duration.Forever); 
            Debug.Assert(locked);
        } 

        /// 
        ///     This method tries to lock the WriteableBitmap for the specified
        ///     timeout and increments the lock count if successful. 
        /// 
        ///  
        ///     The amount of time to wait while trying to acquire the lock. 
        ///     To block indefinitely pass Duration.Forever.
        ///     Duration.Automatic is an invalid value. 
        /// 
        /// Returns true if the lock is now held, false otherwise.
        /// 
        ///   Critical: Obtains and stores pointers to unmanaged memory. 
        ///   PublicOK: Pointers are not exposed to caller.  This method
        ///             should work from partial trust. 
        ///  
        [SecurityCritical]
        public bool TryLock(Duration timeout) 
        {
            WritePreamble();

            TimeSpan timeoutSpan; 
            if (timeout == Duration.Automatic)
            { 
                throw new ArgumentOutOfRangeException("timeout"); 
            }
            else if (timeout == Duration.Forever) 
            {
                timeoutSpan = TimeSpan.FromMilliseconds(-1);
            }
            else 
            {
                timeoutSpan = timeout.TimeSpan; 
            } 

            if (_lockCount == UInt32.MaxValue) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Image_LockCountLimit));
            }
 
            if (_lockCount == 0)
            { 
                // Try to acquire the back buffer by the supplied timeout, if the acquire call times out, return false. 
                if (!AcquireBackBuffer(timeoutSpan, true))
                { 
                    return false;
                }

                Int32Rect rect = new Int32Rect(0, 0, _pixelWidth, _pixelHeight); 

                HRESULT.Check(UnsafeNativeMethods.WICBitmap.Lock( 
                    WicSourceHandle, 
                    ref rect,
                    LockFlags.MIL_LOCK_WRITE, 
                    out _pBackBufferLock
                    ));

                // If this is the first lock operation, cache the BackBuffer and 
                // BackBufferStride.  These two values will never change, so we
                // don't fetch them on every lock. 
                if (_backBuffer == IntPtr.Zero) 
                {
                    IntPtr tempBackBufferPointer = IntPtr.Zero; 
                    uint lockBufferSize = 0;
                    HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetDataPointer(
                        _pBackBufferLock,
                        ref lockBufferSize, 
                        ref tempBackBufferPointer
                        )); 
                    BackBuffer = tempBackBufferPointer; 

                    uint lockBufferStride = 0; 
                    HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetStride(
                        _pBackBufferLock,
                        ref lockBufferStride
                        )); 
                    Invariant.Assert(lockBufferStride <= Int32.MaxValue);
                    _backBufferStride.Value = (int)lockBufferStride; 
                } 

                // If we were subscribed to the CommittingBatch event, unsubscribe 
                // since we should not be part of the batch now that we are
                // locked.  When we unlock, we will subscribe to the
                // CommittingBatch again.
                UnsubscribeFromCommittingBatch(); 
            }
 
            _lockCount++; 
            return true;
        } 

        /// 
        ///   This method decrements the lock count, and if it reaches zero will release the
        ///   on the back buffer and request a render pass. 
        /// 
        ///  
        ///   Critical: Releases lock around unmanaged memory. 
        ///   PublicOK: Pointers are not exposed to caller.  This method
        ///             should work from partial trust. 
        /// 
        [SecurityCritical]
        public void Unlock()
        { 
            WritePreamble();
 
            if (_lockCount == 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Image_MustBeLocked)); 
            }
            Invariant.Assert(_lockCount > 0, "Lock count should never be negative!");

            _lockCount--; 
            if (_lockCount == 0)
            { 
                // This makes the back buffer read-only. 
                _pBackBufferLock.Dispose();
                _pBackBufferLock = null; 

                if (_hasDirtyRects)
                {
                    SubscribeToCommittingBatch(); 

                    // 
                    // Notify listeners that we have changed. 
                    //
                    WritePostscript(); 
                }
            }
        }
 
        /// 
        ///   Updates the pixels in the specified region of the bitmap. 
        ///  
        /// The rect to copy from the input buffer.
        /// The input buffer used to update the bitmap. 
        /// The size of the input buffer in bytes.
        /// The stride of the input buffer in bytes.
        /// The destination x-coordinate of the left-most pixel to copy.
        /// The destination y-coordinate of the top-most pixel to copy. 
        /// 
        ///   Critical: Accesses critical code, performs unsafe operations. 
        ///   PublicOK: Demands unmanaged code permission. 
        /// 
        [SecurityCritical] 
        public void WritePixels(
            Int32Rect sourceRect,
            IntPtr    sourceBuffer,
            int       sourceBufferSize, 
            int       sourceBufferStride,
            int       destinationX, 
            int       destinationY 
            )
        { 
            SecurityHelper.DemandUnmanagedCode();
            WritePreamble();

            WritePixelsImpl(sourceRect, 
                            sourceBuffer,
                            sourceBufferSize, 
                            sourceBufferStride, 
                            destinationX,
                            destinationY, 
                            /*backwardsCompat*/ false);
        }

        ///  
        ///   Updates the pixels in the specified region of the bitmap.
        ///  
        /// The rect to copy from the input buffer. 
        /// The input buffer used to update the bitmap.
        /// The stride of the input buffer in bytes. 
        /// The destination x-coordinate of the left-most pixel to copy.
        /// The destination y-coordinate of the top-most pixel to copy.
        /// 
        ///     Critical: Calls critical methods, has unsafe code. 
        ///     PublicOK: The overall operation is safe, and the input is sanitized.
        ///               This method should work from partial trust. 
        ///  
        [SecurityCritical]
        public void WritePixels( 
            Int32Rect sourceRect,
            Array     sourceBuffer,
            int       sourceBufferStride,
            int       destinationX, 
            int       destinationY
            ) 
        { 
            WritePreamble();
 
            int elementSize;
            int sourceBufferSize;
            Type elementType;
            ValidateArrayAndGetInfo(sourceBuffer, 
                                    /*backwardsCompat*/ false,
                                    out elementSize, 
                                    out sourceBufferSize, 
                                    out elementType);
 
            // We accept arrays of arbitrary value types - but not reference types.
            if (elementType == null || !elementType.IsValueType)
            {
                throw new ArgumentException(SR.Get(SRID.Image_InvalidArrayForPixel)); 
            }
 
            // Get the address of the data in the array by pinning it. 
            GCHandle arrayHandle = GCHandle.Alloc(sourceBuffer, GCHandleType.Pinned);
            try 
            {
                unsafe
                {
                    IntPtr buffer = arrayHandle.AddrOfPinnedObject(); 
                    WritePixelsImpl(sourceRect,
                                    buffer, 
                                    sourceBufferSize, 
                                    sourceBufferStride,
                                    destinationX, 
                                    destinationY,
                                    /*backwardsCompat*/ false);
                }
            } 
            finally
            { 
                arrayHandle.Free(); 
            }
        } 

        /// 
        /// Update the pixels of this Bitmap
        ///  
        /// Area to update
        /// Input buffer 
        /// Size of the buffer 
        /// Stride
        ///  
        /// Critical - access critical code, accepts pointer arguments
        /// PublicOK - demands unmanaged code permission
        /// 
        [SecurityCritical] 
        public unsafe void WritePixels(
            Int32Rect sourceRect, 
            IntPtr buffer, 
            int bufferSize,
            int stride 
            )
        {
            SecurityHelper.DemandUnmanagedCode();
            WritePreamble(); 

            if (bufferSize < 1) 
            { 
                throw new ArgumentOutOfRangeException("bufferSize", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            } 

            if (stride < 1)
            {
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 1)); 
            }
 
            if (sourceRect.IsEmpty || sourceRect.Width <= 0 || sourceRect.Height <= 0) 
            {
                return; 
            }

            // Backwards-Compat:
            // 
            // The "sourceRect" is actually a "destinationRect", as in it
            // refers to the location where the contents are written. 
            // 
            // This method presumes that the pixels are copied from the
            // the specified offset (element count) in the source buffer, and 
            // that no sub-byte pixel formats are used.
            int destinationX = sourceRect.X;
            int destinationY = sourceRect.Y;
            sourceRect.X = 0; 
            sourceRect.Y = 0;
 
            WritePixelsImpl(sourceRect, 
                            buffer,
                            bufferSize, 
                            stride,
                            destinationX,
                            destinationY,
                            /*backwardsCompat*/ true); 
        }
 
        ///  
        /// Update the pixels of this Bitmap
        ///  
        /// Area to update
        /// Input buffer
        /// Stride
        /// Input buffer offset 
        /// 
        /// Critical - This method gets direct access to the input Array's memory. 
        /// PublicOk - Input is a managed buffer which is safe, other inputs are safe as well 
        /// 
        [SecurityCritical] 
        public void WritePixels(
            Int32Rect sourceRect,
            Array pixels,
            int stride, 
            int offset
            ) 
        { 
            WritePreamble();
 
            if (sourceRect.IsEmpty || sourceRect.Width <= 0 || sourceRect.Height <= 0)
            {
                return;
            } 

            int elementSize; 
            int sourceBufferSize; 
            Type elementType;
            ValidateArrayAndGetInfo(pixels, 
                                    /*backwardsCompat*/ true,
                                    out elementSize,
                                    out sourceBufferSize,
                                    out elementType); 

            if (stride < 1) 
            { 
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            } 

            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", SR.Get(SRID.ParameterCannotBeLessThan, 0)); 
            }
 
            // We accept arrays of arbitrary value types - but not reference types. 
            if (elementType == null || !elementType.IsValueType)
            { 
                throw new ArgumentException(SR.Get(SRID.Image_InvalidArrayForPixel));
            }

            checked 
            {
                int offsetInBytes = checked(offset * elementSize); 
                if (offsetInBytes >= sourceBufferSize) 
                {
                    // Backwards compat: 
                    //
                    // The original code would throw an exception deeper in
                    // the code when it indexed off the end of the array.  We
                    // now check earlier (compat break) but throw the same 
                    // exception.
                    throw new IndexOutOfRangeException(); 
                } 

                // Backwards-Compat: 
                //
                // The "sourceRect" is actually a "destinationRect", as in it
                // refers to the location where the contents are written.
                // 
                // This method presumes that the pixels are copied from the
                // the specified offset (element count) in the source buffer, and 
                // that no sub-byte pixel formats are used.  We handle the offset 
                // later.
                int destinationX = sourceRect.X; 
                int destinationY = sourceRect.Y;
                sourceRect.X = 0;
                sourceRect.Y = 0;
 
                // Get the address of the data in the array by pinning it.
                GCHandle arrayHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned); 
                try 
                {
                    IntPtr buffer = arrayHandle.AddrOfPinnedObject(); 

                    checked
                    {
                        buffer = new IntPtr(((long) buffer) + (long) offsetInBytes); 
                        sourceBufferSize -= offsetInBytes;
                    } 
 
                    WritePixelsImpl(sourceRect,
                                    buffer, 
                                    sourceBufferSize,
                                    stride,
                                    destinationX,
                                    destinationY, 
                                    /*backwardsCompat*/ true);
                } 
                finally 
                {
                    arrayHandle.Free(); 
                }
            }
        }
 
        #endregion // Public Methods
 
        #region Protected Methods 

        ///  
        ///   Implementation of Freezable.CreateInstanceCore.
        /// 
        /// The new Freezable.
        protected override Freezable CreateInstanceCore() 
        {
            return new WriteableBitmap(); 
        } 

        ///  
        ///   Implementation of Freezable.CloneCore.
        /// 
        /// 
        ///   Critical:     Accesses critical code. 
        ///   TreatAsSafe:  Method only produces clones of original buffers.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void CloneCore(Freezable sourceFreezable)
        { 
            WriteableBitmap sourceBitmap = (WriteableBitmap) sourceFreezable;

            base.CloneCore(sourceFreezable);
 
            CopyCommon(sourceBitmap);
        } 
 
        /// 
        ///   Implementation of Freezable.FreezeCore. 
        /// 
        /// 
        ///   Critical:     Accesses critical code. (AcquireBackBuffer, FreezeBackBuffer)
        ///   TreatAsSafe:  Method gets the back buffer, but doesn't expose it. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override bool FreezeCore(bool isChecking) 
        {
            bool canFreeze = (_lockCount == 0) && base.FreezeCore(isChecking); 

            if (canFreeze && !isChecking)
            {
                Debug.Assert(_pBackBufferLock == null); 

                // 
                // By entering 'frozen' mode, we convert from being a 
                // DoubleBufferedBitmap to a regular BitmapSource.
                // 

                // Protect the back buffer for writing
                HRESULT.Check(MILSwDoubleBufferedBitmap.ProtectBackBuffer(_pDoubleBufferedBitmap));
 
                // Get the back buffer to be used as our WicSourceHandle
                AcquireBackBuffer(TimeSpan.Zero, false); 
                _needsUpdate = true; 
                _hasDirtyRects = false;
 
                // From here on out we're going to effectively be an ordinary
                // BitmapSource.
                _actLikeSimpleBitmap = true;
 
                // Pull this resource off all the channels and put it back on.
                int channelCount = _duceResource.GetChannelCount(); 
                for (int i = 0; i < channelCount; i++) 
                {
                    DUCE.IResource resource = this as DUCE.IResource; 
                    DUCE.Channel channel = _duceResource.GetChannel(i);

                    //
                    // It could have been added multiple times, so release until 
                    // it's no longer on a channel.
                    // 
                    uint refCount = _duceResource.GetRefCountOnChannel(channel); 
                    for (uint j = 0; j < refCount; j++)
                    { 
                        resource.ReleaseOnChannel(channel);
                    }

                    // Put it back on the Channel, only this time it wont 
                    // be a SwDoubleBufferedBitmap.
                    for (uint j = 0; j < refCount; j++) 
                    { 
                        resource.AddRefOnChannel(channel);
                    } 
                }

                Debug.Assert(!_isWaitingForCommit);
 
                // We no longer need the SwDoubleBufferedBitmap
                _pDoubleBufferedBitmap.Dispose(); 
                _pDoubleBufferedBitmap = null; 

                // We will no longer need to wait for this event. 
                _copyCompletedEvent.Close();
                _copyCompletedEvent = null;

                // Clear out unused variables 
                _committingBatchHandler = null;
                _pBackBuffer = null; 
            } 

            return canFreeze; 
        }

        /// 
        ///   Implementation of Freezable.CloneCurrentValueCore. 
        /// 
        ///  
        ///   Critical:     Accesses critical code. 
        ///   TreatAsSafe:  Method only produces clones of original buffers.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap) sourceFreezable; 

            base.CloneCurrentValueCore(sourceFreezable); 
 
            CopyCommon(sourceBitmap);
        } 

        /// 
        ///   Implementation of Freezable.GetAsFrozenCore.
        ///  
        /// 
        ///   Critical:     Accesses critical code. 
        ///   TreatAsSafe:  Method only produces GetAsFrozen of original buffers. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void GetAsFrozenCore(Freezable sourceFreezable)
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap)sourceFreezable;
 
            base.GetAsFrozenCore(sourceFreezable);
 
            CopyCommon(sourceBitmap); 
        }
 
        /// 
        ///   Implementation of Freezable.GetCurrentValueAsFrozenCore.
        /// 
        ///  
        ///   Critical:     Accesses critical code.
        ///   TreatAsSafe:  Method only produces GetCurrentValueAsFrozen of original image. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) 
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap)sourceFreezable;

            base.GetCurrentValueAsFrozenCore(sourceFreezable); 

            CopyCommon(sourceBitmap); 
        } 

        #endregion // Protected Methods 

        #region Private/Internal Methods

        ///  
        ///     Initializes this WriteableBitmap with the
        ///     contents of the specified BitmapSource. 
        ///  
        /// 
        ///     The BitmapSource to copy. 
        /// 
        /// 
        ///     Critical: Creates and accesses a handle to an unmanaged resource.
        ///     PublicOK: Inputs are safe. 
        /// 
        [SecurityCritical] 
        private void InitFromBitmapSource( 
            BitmapSource source
            ) 
        {
            if (source == null)
            {
                throw new ArgumentNullException("source"); 
            }
 
            if (source.PixelWidth < 0) 
            {
                // Backwards Compat 
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW);
            }

            if (source.PixelHeight < 0) 
            {
                // Backwards Compat 
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
            }
 
            BeginInit();

            _syncObject = source.SyncObject;
            lock (_syncObject) 
            {
                Guid formatGuid = source.Format.Guid; 
 
                SafeMILHandle internalPalette = new SafeMILHandle();
                if (source.Format.Palettized) 
                {
                    internalPalette = source.Palette.InternalPalette;
                }
 
                HRESULT.Check(MILSwDoubleBufferedBitmap.Create(
                    (uint)source.PixelWidth, // safe cast 
                    (uint)source.PixelHeight, // safe cast 
                    source.DpiX,
                    source.DpiY, 
                    ref formatGuid,
                    internalPalette,
                    out _pDoubleBufferedBitmap
                    )); 

                Lock(); 
 
                Int32Rect rcFull = new Int32Rect(0, 0, _pixelWidth, _pixelHeight);
                int bufferSize = checked(_backBufferStride.Value * source.PixelHeight); 
                source.CriticalCopyPixels(rcFull, _backBuffer, bufferSize, _backBufferStride.Value);
                AddDirtyRect(rcFull);

                Unlock(); 
            }
 
            EndInit(); 
        }
 
        /// 
        ///     Updates the pixels in the specified region of the bitmap.
        /// 
        ///  
        ///     The rect to copy from the input buffer.
        ///  
        ///  
        ///     The input buffer used to update the bitmap.
        ///  
        /// 
        ///     The size of the input buffer in bytes.
        /// 
        ///  
        ///     The stride of the input buffer in bytes.
        ///  
        ///  
        ///     The destination x-coordinate of the left-most pixel to copy.
        ///  
        /// 
        ///     The destination y-coordinate of the top-most pixel to copy.
        /// 
        ///  
        ///     Whether or not to preserve the old WritePixels behavior.
        ///  
        ///  
        ///   Critical: Accesses critical code, performs unsafe operations.
        ///  
        [SecurityCritical]
        private void WritePixelsImpl(
            Int32Rect sourceRect,
            IntPtr    sourceBuffer, 
            int       sourceBufferSize,
            int       sourceBufferStride, 
            int       destinationX, 
            int       destinationY,
            bool      backwardsCompat 
            )
        {
            //
            // Sanitize the source rect and assure it will fit within the back buffer. 
            //
            if (sourceRect.X < 0) 
            { 
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterCannotBeNegative)); 
            }

            if (sourceRect.Y < 0)
            { 
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterCannotBeNegative)); 
            } 

            if (sourceRect.Width < 0) 
            {
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth));
            } 

            if (sourceRect.Width > _pixelWidth) 
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG);
                }
                else
                { 
                    throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth));
                } 
            } 

            if (sourceRect.Height < 0) 
            {
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight));
            } 

            if (sourceRect.Height > _pixelHeight) 
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG);
                }
                else
                { 
                    throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight));
                } 
            } 

            if (destinationX < 0) 
            {
                if (backwardsCompat)
                {
                    HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
                }
                else 
                { 
                    throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterCannotBeNegative));
                } 
            }

            if (destinationX > _pixelWidth - sourceRect.Width)
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG); 
                }
                else 
                {
                    throw new ArgumentOutOfRangeException("destinationX", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth - sourceRect.Width));
                }
            } 

            if (destinationY < 0) 
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW);
                }
                else
                { 
                    throw new ArgumentOutOfRangeException("destinationY", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight - sourceRect.Height));
                } 
            } 

            if (destinationY > _pixelHeight - sourceRect.Height) 
            {
                if (backwardsCompat)
                {
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG); 
                }
                else 
                { 
                    throw new ArgumentOutOfRangeException("destinationY", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight - sourceRect.Height));
                } 
            }

            //
            // Sanitize the other parameters. 
            //
            if (sourceBuffer == IntPtr.Zero) 
            { 
                // Backwards Compat:
                // 
                // The original code would null-ref when it was passed a null
                // buffer (IntPtr.Zero).  We choose to throw a better
                // exception.
                throw new ArgumentNullException(backwardsCompat ? "buffer" : "sourceBuffer"); 
            }
 
            if (sourceBufferStride < 1) 
            {
                Debug.Assert(!backwardsCompat); 
                throw new ArgumentOutOfRangeException("sourceBufferStride", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            }

            if (sourceRect.Width == 0 || sourceRect.Height == 0) 
            {
                Debug.Assert(!backwardsCompat); 
 
                // Nothing to do.
                return; 
            }

            checked
            { 
                uint finalRowWidthInBits = (uint)((sourceRect.X + sourceRect.Width) * _format.InternalBitsPerPixel);
                uint finalRowWidthInBytes = ((finalRowWidthInBits + 7) / 8); 
                uint requiredBufferSize = (uint)((sourceRect.Y + sourceRect.Height - 1) * sourceBufferStride) + finalRowWidthInBytes; 
                if (sourceBufferSize < requiredBufferSize)
                { 
                    if (backwardsCompat)
                    {
                        HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER);
                    } 
                    else
                    { 
                        throw new ArgumentException(SR.Get(SRID.Image_InsufficientBufferSize), "sourceBufferSize"); 
                    }
                } 

                uint copyWidthInBits = (uint)(sourceRect.Width * _format.InternalBitsPerPixel);

                // Calculate some offsets that we'll need in a moment. 
                uint sourceXbyteOffset = (uint)((sourceRect.X * _format.InternalBitsPerPixel) / 8);
                uint sourceBufferBitOffset = (uint)((sourceRect.X * _format.InternalBitsPerPixel) % 8); 
                uint firstPixelByteOffet = (uint)((sourceRect.Y * sourceBufferStride) + sourceXbyteOffset); 
                uint destXbyteOffset = (uint)((destinationX * _format.InternalBitsPerPixel) / 8);
                uint destBufferBitOffset = (uint)((destinationX * _format.InternalBitsPerPixel) % 8); 

                Int32Rect destinationRect = sourceRect;
                destinationRect.X = destinationX;
                destinationRect.Y = destinationY; 

                // 
                // Copy pixel information from the user supplied buffer to the back buffer. 
                //
                unsafe 
                {
                    uint destOffset = (uint)(destinationY * _backBufferStride.Value) + destXbyteOffset;
                    byte* pDest = (byte*)_backBuffer.ToPointer();
                    pDest += destOffset; 
                    uint outputBufferSize = _backBufferSize - destOffset;
 
                    byte* pSource = (byte*)sourceBuffer.ToPointer(); 
                    pSource += firstPixelByteOffet;
                    uint inputBufferSize = (uint)sourceBufferSize - firstPixelByteOffet; 

                    Lock();

                    MILUtilities.MILCopyPixelBuffer( 
                        pDest,
                        outputBufferSize, 
                        (uint) _backBufferStride.Value, 
                        destBufferBitOffset,
                        pSource, 
                        inputBufferSize,
                        (uint) sourceBufferStride,
                        sourceBufferBitOffset,
                        (uint) sourceRect.Height, 
                        copyWidthInBits);
 
                    AddDirtyRect(destinationRect); 
                    Unlock();
                } 
            }

            // Note: we do not call WritePostscript because we do not want to
            // raise change notifications until the writeable bitmap is unlocked. 
            //
            // Change notifications may have already been raised in the Unlock 
            // call in this method. 
        }
 
        /// 
        ///   Try to acquire the back buffer of our unmanaged double buffered bitmap in the specified timeout.
        /// 
        ///  
        ///   The time to wait while trying to acquire the lock.
        ///  
        ///  
        ///   Should we try to wait for the copy completed event?
        ///  
        /// Returns true if the back buffer was acquired before the timeout expired.
        /// 
        ///   Critical: Accesses a handle to an unmanaged resource.
        ///  
        [SecurityCritical]
        private bool AcquireBackBuffer(TimeSpan timeout, bool waitForCopy) 
        { 
            bool backBufferAcquired = false;
 
            //
            // Only get the back buffer from the unmanaged double buffered bitmap if this is our
            // first time being called since the last successful call to OnCommittingBatch.
            // OnCommittingBatch sets _pBackBuffer to null. 
            //
            if (_pBackBuffer == null) 
            { 
                bool shouldGetBackBuffer = true;
 
                if (waitForCopy)
                {
                    // If we have committed a copy-forward command, we need to wait
                    // for the render thread to finish the copy before we can use 
                    // the back buffer.
                    shouldGetBackBuffer = _copyCompletedEvent.WaitOne(timeout, false); 
                } 

                if (shouldGetBackBuffer) 
                {
                    MILSwDoubleBufferedBitmap.GetBackBuffer(
                        _pDoubleBufferedBitmap,
                        out _pBackBuffer, 
                        out _backBufferSize);
 
                    _syncObject = WicSourceHandle = _pBackBuffer; 
                    backBufferAcquired = true;
                } 
            }
            else
            {
                backBufferAcquired = true; 
            }
 
            return backBufferAcquired; 
        }
 
        /// 
        ///   Common implementation for CloneCore(), CloneCurrentValueCore(),
        ///   GetAsFrozenCore(), and GetCurrentValueAsFrozenCore().
        ///  
        /// The WriteableBitmap to copy from.
        ///  
        ///   Critical: Accesses a handle to an unmanaged resource. 
        /// 
        [SecurityCritical] 
        private void CopyCommon(WriteableBitmap sourceBitmap)
        {
            // Avoid Animatable requesting resource updates for invalidations
            // that occur during construction. 
            Animatable_IsResourceInvalidationNecessary = false;
            _actLikeSimpleBitmap = false; 
 
            // Create a SwDoubleBufferedBitmap and copy the sourceBitmap into it.
            InitFromBitmapSource(sourceBitmap); 

            // The next invalidation will cause Animatable to register an
            // UpdateResource callback.
            Animatable_IsResourceInvalidationNecessary = true; 
        }
 
 
        // ISupportInitialize
 
        /// 
        ///   Prepare the bitmap to accept initialize paramters.
        /// 
        private void BeginInit() 
        {
            _bitmapInit.BeginInit(); 
        } 

        ///  
        ///   Prepare the bitmap to accept initialize paramters.
        /// 
        /// 
        ///   Critical:     Access critical resources. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void EndInit() 
        {
            _bitmapInit.EndInit(); 

            FinalizeCreation();
        }
 
        /// 
        ///   Create the unmanaged resources. 
        ///  
        /// 
        /// Critical - access critical resource 
        /// 
        [SecurityCritical]
        internal override void FinalizeCreation()
        { 
            IsSourceCached = true;
            CreationCompleted = true; 
            UpdateCachedSettings(); 
        }
 
        /// 
        ///     Get the size of the specified array and of the elements in it.
        /// 
        ///  
        ///     The array to get info about.
        ///  
        ///  
        ///     On output, will contain the size of the elements in the array.
        ///  
        /// 
        ///     On output, will contain the size of the array.
        /// 
        ///  
        ///     Critical - Calls Marshal.SizeOf, which has a link demand for some reason.
        ///  
        [SecurityCritical] 
        private void ValidateArrayAndGetInfo(Array sourceBuffer,
                                                       bool backwardsCompat, 
                                                       out int elementSize,
                                                       out int sourceBufferSize,
                                                       out Type elementType)
        { 
            //
            // Assure that a valid pixels Array was provided. 
            // 
            if (sourceBuffer == null)
            { 
                throw new ArgumentNullException(backwardsCompat ? "pixels" : "sourceBuffer");
            }

            if (sourceBuffer.Rank == 1) 
            {
                if (sourceBuffer.GetLength(0) <= 0) 
                { 
                    if (backwardsCompat)
                    { 
                        elementSize = 1;
                        sourceBufferSize = 0;
                        elementType = null;
                    } 
                    else
                    { 
                        throw new ArgumentException(SR.Get(SRID.Image_InsufficientBuffer), "sourceBuffer"); 
                    }
                } 
                else
                {
                    checked
                    { 
                        object exemplar = sourceBuffer.GetValue(0);
                        elementSize = Marshal.SizeOf(exemplar); 
                        sourceBufferSize = sourceBuffer.GetLength(0) * elementSize; 
                        elementType = exemplar.GetType();
                    } 
                }

            }
            else if (sourceBuffer.Rank == 2) 
            {
                if (sourceBuffer.GetLength(0) <= 0 || sourceBuffer.GetLength(1) <= 0) 
                { 
                    if (backwardsCompat)
                    { 
                        elementSize = 1;
                        sourceBufferSize = 0;
                        elementType = null;
                    } 
                    else
                    { 
                        throw new ArgumentException(SR.Get(SRID.Image_InsufficientBuffer), "sourceBuffer"); 
                    }
                } 
                else
                {
                    checked
                    { 
                        object exemplar = sourceBuffer.GetValue(0,0);
                        elementSize = Marshal.SizeOf(exemplar); 
                        sourceBufferSize = sourceBuffer.GetLength(0) * sourceBuffer.GetLength(1) * elementSize; 
                        elementType = exemplar.GetType();
                    } 
                }
            }
            else
            { 
                throw new ArgumentException(SR.Get(SRID.Collection_BadRank), backwardsCompat ? "pixels" : "sourceBuffer");
            } 
        } 

        ///  
        ///     Adds a reference to our DUCE resource on .
        /// 
        /// 
        ///     The channel we want to AddRef on. 
        /// 
        ///  
        ///     The handle to our DoubleBufferedBitmap or BitmapSource handle. 
        /// 
        ///  
        ///     We override this method because we use a different resource
        ///     type than our base class does.  This probably suggests that the
        ///     base class should not presume the resource type, but it
        ///     currently does.  The base class uses TYPE_BITMAPSOURCE 
        ///     resources, and we use TYPE_DOUBLEBUFFEREDBITMAP resources.
        ///  
        internal override DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel) 
        {
            // 
            // If we're in BitmapSource mode, then just defer to the BitmapSource
            // implementation.
            //
            if (_actLikeSimpleBitmap) 
            {
                return base.AddRefOnChannelCore(channel); 
            } 

            if (_duceResource.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_DOUBLEBUFFEREDBITMAP)) 
            {
                // This is the first AddRef on this channel...

                // If we are being put onto the asynchronous compositor channel in 
                // a dirty state, we need to subscribe to the CommittingBatch event.
                if (!channel.IsSynchronous && _hasDirtyRects) 
                { 
                    SubscribeToCommittingBatch();
                } 

                AddRefOnChannelAnimations(channel);

                // The first time our resource is created on a channel, we need 
                // to update it.  We can skip "on channel" check since we
                // already know that the resource is on channel. 
                UpdateResource(channel, true); 
            }
 
            return _duceResource.GetHandle(channel);
        }

        internal override void ReleaseOnChannelCore(DUCE.Channel channel) 
        {
            Debug.Assert(_duceResource.IsOnChannel(channel)); 
 
            if (_duceResource.ReleaseOnChannel(channel))
            { 
                // This is the last release from this channel...

                // If we are being pulled off the asynchronous compositor channel
                // then unsubscribe from the CommittingBatch event. 
                if (!channel.IsSynchronous)
                { 
                    UnsubscribeFromCommittingBatch(); 
                }
 
                ReleaseOnChannelAnimations(channel);
            }
        }
 
        /// 
        ///   Updates the double-buffered bitmap DUCE resource with a pointer to our acutal object. 
        ///  
        /// The channel to update the resource on.
        ///  
        ///   If this is true, we know we are on channel and don't need to explicitly check.
        /// 
        /// 
        ///   Critical:     Accesses a handle to an unmanaged resource.  Calls critical methods. 
        ///   TreateAsSafe: We allocate the double buffered bitmap ourself and the user can never
        ///                 get ahold of it. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override void UpdateBitmapSourceResource(DUCE.Channel channel, bool skipOnChannelCheck) 
        {
            //
            // If we're in BitmapSource mode, then just defer to the BitmapSource
            // implementation. 
            //
            if (_actLikeSimpleBitmap) 
            { 
                base.UpdateBitmapSourceResource(channel, skipOnChannelCheck);
                return; 
            }

            // We override this method because we use a different resource type
            // than our base class does.  This probably suggests that the base 
            // class should not presume the resource type, but it currently
            // does.  The base class uses TYPE_BITMAPSOURCE resources, and we 
            // use TYPE_DOUBLEBUFFEREDBITMAP resources. 

            // If we're told we can skip the channel check, then we must be on channel 
            Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel));

            if (skipOnChannelCheck || _duceResource.IsOnChannel(channel))
            { 
                DUCE.MILCMD_DOUBLEBUFFEREDBITMAP command;
                command.Type = MILCMD.MilCmdDoubleBufferedBitmap; 
                command.Handle = _duceResource.GetHandle(channel); 
                unsafe
                { 
                    command.SwDoubleBufferedBitmap = (UInt64) _pDoubleBufferedBitmap.DangerousGetHandle().ToPointer();
                }
                command.UseBackBuffer = channel.IsSynchronous ? 1u : 0u;
 
                //
                // We need to ensure that this object stays alive while traveling over the channel 
                // so we'll AddRef it here, and simply take over the reference on the other side. 
                //
                UnsafeNativeMethods.MILUnknown.AddRef(_pDoubleBufferedBitmap); 

                unsafe
                {
                    channel.SendSecurityCriticalCommand( 
                        (byte*)&command,
                        sizeof(DUCE.MILCMD_DOUBLEBUFFEREDBITMAP) 
                        ); 
                }
            } 
        }

        private void SubscribeToCommittingBatch()
        { 
            // Only subscribe the the CommittingBatch event if we are on-channel.
            if (!_isWaitingForCommit) 
            { 
                MediaContext mediaContext = MediaContext.From(Dispatcher);
                if (_duceResource.IsOnChannel(mediaContext.Channel)) 
                {
                    mediaContext.CommittingBatch += CommittingBatchHandler;
                    _isWaitingForCommit = true;
                } 
            }
        } 
 
        private void UnsubscribeFromCommittingBatch()
        { 
            if (_isWaitingForCommit)
            {
                MediaContext mediaContext = MediaContext.From(Dispatcher);
                mediaContext.CommittingBatch -= CommittingBatchHandler; 
                _isWaitingForCommit = false;
            } 
        } 

        ///  
        ///   Send a packet on the DUCE.Channel telling our double-buffered bitmap resource
        ///   to copy forward dirty regions from the back buffer to the front buffer.
        /// 
        ///  
        ///   For the packet to be sent, the user must have added a dirty region to the
        ///   WriteableBitmap and there must be no outstanding locks. 
        ///  
        /// 
        ///   Critical:     Accesses critical methods and a handle to an unmanaged resource. 
        ///   TreatAsSafe:  Inputs are supplied internally.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void OnCommittingBatch(object sender, EventArgs args) 
        {
            Debug.Assert(_isWaitingForCommit);  // How else are we here? 
            UnsubscribeFromCommittingBatch(); 

            Debug.Assert(_lockCount == 0);  // How else are we here? 
            Debug.Assert(_hasDirtyRects);  // How else are we here?

            // Before using the back buffer again, we need to know when
            // the rendering thread has completed the copy. By setting 
            // our back buffer pointer to null, we'll have to re-acquire
            // it the next time, which will wait for the copy to complete. 
            _copyCompletedEvent.Reset(); 
            _pBackBuffer = null;
 
            DUCE.Channel channel = sender as DUCE.Channel;
            Debug.Assert(_duceResource.IsOnChannel(channel));  // How else are we here?

            // We are going to pass an event in the command packet we send to 
            // the composition thread.  We need to make sure the event stays
            // alive in case we get collected before the composition thread 
            // processes the packet.  We do this by duplicating the event 
            // handle, and the composition thread will close the handle after
            // signalling it. 
            IntPtr hDuplicate;
            IntPtr hCurrentProc = MS.Win32.UnsafeNativeMethods.GetCurrentProcess();
            if (!MS.Win32.UnsafeNativeMethods.DuplicateHandle(
                    hCurrentProc, 
                    _copyCompletedEvent.SafeWaitHandle,
                    hCurrentProc, 
                    out hDuplicate, 
                    0,
                    false, 
                    MS.Win32.UnsafeNativeMethods.DUPLICATE_SAME_ACCESS
                    ))
            {
                throw new Win32Exception(); 
            }
 
            DUCE.MILCMD_DOUBLEBUFFEREDBITMAP_COPYFORWARD command; 
            command.Type = MILCMD.MilCmdDoubleBufferedBitmapCopyForward;
            command.Handle = _duceResource.GetHandle(channel); 
            command.CopyCompletedEvent = (UInt64) hDuplicate.ToInt64();

            unsafe
            { 
                channel.SendSecurityCriticalCommand(
                    (byte*)&command, 
                    sizeof(DUCE.MILCMD_DOUBLEBUFFEREDBITMAP_COPYFORWARD) 
                    );
            } 

            // We are committing the batch to the asynchronous compositor,
            // which will copy the rects forward.  The copy will complete
            // before we can access the back buffer again.  So, we consider 
            // ourselves clean.
            _hasDirtyRects = false; 
        } 

        #endregion 

        #region Properties

        ///  
        ///   Read-only data pointer to the back buffer.
        ///  
        ///  
        ///   Critical:  Accesses back buffer pointer.
        ///   PublicOK:  Demands unmanaged code permission. 
        /// 
        public IntPtr BackBuffer
        {
            [SecurityCritical] 
            get
            { 
                SecurityHelper.DemandUnmanagedCode(); 
                ReadPreamble();
 
                return _backBuffer;
            }

            [SecurityCritical] 
            private set
            { 
                _backBuffer = value; 
            }
        } 

        /// 
        ///     Critical: The pointer to the back buffer pixels.
        ///  
        [SecurityCritical]
        private IntPtr _backBuffer; 
 
        /// 
        ///     Critical: The size of the back buffer.  Should never be exposed 
        ///     to external parties.
        /// 
        [SecurityCritical]
        private uint _backBufferSize; 

        ///  
        ///   Read-only stride of the back buffer. 
        /// 
        public int BackBufferStride 
        {
            get
            {
                ReadPreamble(); 

                return _backBufferStride.Value; 
            } 
        }
 
        /// 
        ///     Critical: Sets the back buffer stride, which is important for
        ///               internal pointer arithmetic calculations.
        ///  
        private SecurityCriticalDataForSet _backBufferStride;
 
        #endregion // Properties 

        #region Fields 

        /// 
        ///     Critical: The pointer to the IMILSwDoubleBufferedBitmap
        ///               interface that manages the back and front buffers. 
        /// 
        [SecurityCritical] 
        private SafeMILHandle _pDoubleBufferedBitmap;   // CSwDoubleBufferedBitmap 

        ///  
        ///     Critical: The pointer to the IWICBitmapLock interface that
        ///               provides access to the back buffer pointer.
        /// 
        [SecurityCritical] 
        private SafeMILHandle _pBackBufferLock;         // IWICBitmapLock
 
        ///  
        ///     Critical: The pointer to the IMILBitmap interface that is the
        ///               back buffer. 
        /// 
        [SecurityCritical]
        private BitmapSourceSafeMILHandle _pBackBuffer; // IMILBitmap
 
        private uint _lockCount = 0;
 
        // Flags whether the user has added a dirty rect since the last CopyForward packet was sent. 
        private bool _hasDirtyRects = true;
 
        // Flags whether a MediaContext.CommittingBatch handler has already been added.
        private bool _isWaitingForCommit = false;

        private ManualResetEvent _copyCompletedEvent = new ManualResetEvent(true); 

        private EventHandler CommittingBatchHandler 
        { 
            get
            { 
                if (_committingBatchHandler == null)
                {
                    _committingBatchHandler = OnCommittingBatch;
                } 

                return _committingBatchHandler; 
            } 
        }
        private EventHandler _committingBatchHandler; // = OnCommittingBatch (CS0236) 

        private bool _actLikeSimpleBitmap = false;

        #endregion // Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
//
//  Copyright (c) Microsoft Corporation.  All Rights Reserved.
//
//  File: WriteableBitmap.cs 
//-----------------------------------------------------------------------------
 
using System; 
using System.IO;
using System.Collections; 
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Reflection; 
using MS.Internal;
using MS.Win32.PresentationCore; 
using System.Security; 
using System.Security.Permissions;
using System.Diagnostics; 
using System.Windows.Media;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows; 
using System.Windows.Media.Animation;
using System.Windows.Media.Composition; 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.PresentationCore;                        // SecurityHelper 
using System.Threading;

namespace System.Windows.Media.Imaging
{ 
    /// 
    ///   WriteableBitmap provides an efficient, tear-free mechanism for updating 
    ///   a system-memory bitmap. 
    /// 
    public sealed class WriteableBitmap : System.Windows.Media.Imaging.BitmapSource 
    {
        #region Constructors

        ///  
        ///     Internal constructor
        ///  
        internal WriteableBitmap() 
        {
        } 

        /// 
        ///     Creates a new WriteableBitmap instance initialized with the
        ///     contents of the specified BitmapSource. 
        /// 
        ///  
        ///     The BitmapSource to copy. 
        /// 
        ///  
        ///     Critical: Creates and accesses a handle to an unmanaged resource.
        ///     PublicOK: Inputs are safe.
        /// 
        [SecurityCritical] 
        public WriteableBitmap(
            BitmapSource source 
            ) 
            : base(true) // Use base class virtuals
        { 
            InitFromBitmapSource(source);
        }

        ///  
        ///   Initializes a new instance of the WriteableBitmap class with
        ///   the specified parameters. 
        ///  
        /// The desired width of the bitmap.
        /// The desired height of the bitmap. 
        /// The horizontal dots per inch (dpi) of the bitmap.
        /// The vertical dots per inch (dpi) of the bitmap.
        /// The PixelFormat of the bitmap.
        /// The BitmapPalette of the bitmap. 
        /// 
        ///   Critical: Creates and accesses a handle to an unmanaged resource. 
        ///   PublicOK: Inputs are safe. 
        /// 
        [SecurityCritical] 
        public WriteableBitmap(
            int pixelWidth,
            int pixelHeight,
            double dpiX, 
            double dpiY,
            PixelFormat pixelFormat, 
            BitmapPalette palette 
            )
            : base(true) // Use base class virtuals 
        {
            BeginInit();

            // 
            // Sanitize inputs
            // 
 
            if (pixelFormat == null)
            { 
                // Backwards Compat:
                //
                // The original code would null-ref, but we choose to raise a
                // better exception. 
                throw new ArgumentNullException("pixelFormat");
            } 
 
            if (pixelFormat.Palettized && palette == null)
            { 
                throw new InvalidOperationException(SR.Get(SRID.Image_IndexedPixelFormatRequiresPalette));
            }

            if (pixelFormat.Format == PixelFormatEnum.Extended) 
            {
                // We don't support third-party pixel formats yet. 
                throw new ArgumentException(SR.Get(SRID.Effect_PixelFormat), "pixelFormat"); 
            }
 
            if (pixelWidth < 0)
            {
                // Backwards Compat
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
            }
 
            if (pixelWidth == 0) 
            {
                // Backwards Compat 
                HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG);
            }

            if (pixelHeight < 0) 
            {
                // Backwards Compat 
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
            }
 
            if (pixelHeight == 0)
            {
                // Backwards Compat
                HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG); 
            }
 
            // 
            // Create and initialize a new unmanaged double buffered bitmap.
            // 
            Guid formatGuid = pixelFormat.Guid;

            // This SafeMILHandle gets ignored if the pixel format is not palettized.
            SafeMILHandle internalPalette = new SafeMILHandle(); 
            if (pixelFormat.Palettized)
            { 
                internalPalette = palette.InternalPalette; 
            }
 
            HRESULT.Check(MILSwDoubleBufferedBitmap.Create(
                (uint) pixelWidth, // safe cast
                (uint) pixelHeight, // safe cast
                dpiX, 
                dpiY,
                ref formatGuid, 
                internalPalette, 
                out _pDoubleBufferedBitmap
                )); 

            // Momentarily lock to populate the BackBuffer/BackBufferStride properties.
            Lock();
            Unlock(); 

            EndInit(); 
        } 

        #endregion // Constructors 

        #region Public Methods

        ///  
        ///   Adds a dirty region to the WriteableBitmap's back buffer.
        ///  
        ///  
        ///   An Int32Rect structure specifying the dirty region.
        ///  
        /// 
        ///   This method can be called multiple times, and the areas are accumulated
        ///   in a sufficient, but not necessarily minimal, representation.  For efficiency,
        ///   only the areas that are marked as dirty are guaranteed to be copied over to 
        ///   the rendering system.
        ///   AddDirtyRect can only be called while the bitmap is locked, otherwise an 
        ///   InvalidOperationException will be thrown. 
        /// 
        ///  
        ///   Critical: Accesses a handle to an unmanaged resource.
        ///   PublicOK: Input dirty rect is sanitized before use.
        /// 
        [SecurityCritical] 
        public void AddDirtyRect(Int32Rect dirtyRect)
        { 
            WritePreamble(); 

            if (_lockCount == 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Image_MustBeLocked));
            }
 
            //
            // Sanitize the dirty rect. 
            // 
            if (dirtyRect.X < 0)
            { 
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterCannotBeNegative));
            }

            if (dirtyRect.Y < 0) 
            {
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterCannotBeNegative)); 
            } 

            if (dirtyRect.Width < 0 || dirtyRect.Width > _pixelWidth) 
            {
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth));
            }
 
            if (dirtyRect.Height < 0 || dirtyRect.Height > _pixelHeight)
            { 
                throw new ArgumentOutOfRangeException("dirtyRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight)); 
            }
 
            if (!dirtyRect.IsEmpty)
            {
                MILSwDoubleBufferedBitmap.AddDirtyRect(
                    _pDoubleBufferedBitmap, 
                    ref dirtyRect);
 
                _hasDirtyRects = true; 
            }
 
            // Note: we do not call WritePostscript because we do not want to
            // raise change notifications until the writeable bitmap is unlocked.
        }
 
        /// 
        ///   Shadows inherited Copy() with a strongly typed version for convenience. 
        ///  
        public new WriteableBitmap Clone()
        { 
            return (WriteableBitmap)base.Clone();
        }

        ///  
        ///   Shadows inherited CloneCurrentValue() with a strongly typed version for convenience.
        ///  
        public new WriteableBitmap CloneCurrentValue() 
        {
            return (WriteableBitmap)base.CloneCurrentValue(); 
        }

        /// 
        ///     This method locks the WriteableBitmap and increments the lock count. 
        /// 
        ///  
        ///     By "locking" the WriteableBitmap, updates will not be sent to the rendering system until 
        ///     the WriteableBitmap is fully unlocked.  This can be used to support multi-threaded scenarios.
        ///     This method blocks until the rendering system is finished processing the last frame's update. 
        ///     To provide a timeout see WriteableBitmap.TryLock.
        ///     Locking the WriteableBitmap gives the caller write permission to the back buffer whose address
        ///     can be obtained via the WriteableBitmap.BackBuffer property.
        ///  
        public void Lock()
        { 
            bool locked = TryLock(Duration.Forever); 
            Debug.Assert(locked);
        } 

        /// 
        ///     This method tries to lock the WriteableBitmap for the specified
        ///     timeout and increments the lock count if successful. 
        /// 
        ///  
        ///     The amount of time to wait while trying to acquire the lock. 
        ///     To block indefinitely pass Duration.Forever.
        ///     Duration.Automatic is an invalid value. 
        /// 
        /// Returns true if the lock is now held, false otherwise.
        /// 
        ///   Critical: Obtains and stores pointers to unmanaged memory. 
        ///   PublicOK: Pointers are not exposed to caller.  This method
        ///             should work from partial trust. 
        ///  
        [SecurityCritical]
        public bool TryLock(Duration timeout) 
        {
            WritePreamble();

            TimeSpan timeoutSpan; 
            if (timeout == Duration.Automatic)
            { 
                throw new ArgumentOutOfRangeException("timeout"); 
            }
            else if (timeout == Duration.Forever) 
            {
                timeoutSpan = TimeSpan.FromMilliseconds(-1);
            }
            else 
            {
                timeoutSpan = timeout.TimeSpan; 
            } 

            if (_lockCount == UInt32.MaxValue) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Image_LockCountLimit));
            }
 
            if (_lockCount == 0)
            { 
                // Try to acquire the back buffer by the supplied timeout, if the acquire call times out, return false. 
                if (!AcquireBackBuffer(timeoutSpan, true))
                { 
                    return false;
                }

                Int32Rect rect = new Int32Rect(0, 0, _pixelWidth, _pixelHeight); 

                HRESULT.Check(UnsafeNativeMethods.WICBitmap.Lock( 
                    WicSourceHandle, 
                    ref rect,
                    LockFlags.MIL_LOCK_WRITE, 
                    out _pBackBufferLock
                    ));

                // If this is the first lock operation, cache the BackBuffer and 
                // BackBufferStride.  These two values will never change, so we
                // don't fetch them on every lock. 
                if (_backBuffer == IntPtr.Zero) 
                {
                    IntPtr tempBackBufferPointer = IntPtr.Zero; 
                    uint lockBufferSize = 0;
                    HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetDataPointer(
                        _pBackBufferLock,
                        ref lockBufferSize, 
                        ref tempBackBufferPointer
                        )); 
                    BackBuffer = tempBackBufferPointer; 

                    uint lockBufferStride = 0; 
                    HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetStride(
                        _pBackBufferLock,
                        ref lockBufferStride
                        )); 
                    Invariant.Assert(lockBufferStride <= Int32.MaxValue);
                    _backBufferStride.Value = (int)lockBufferStride; 
                } 

                // If we were subscribed to the CommittingBatch event, unsubscribe 
                // since we should not be part of the batch now that we are
                // locked.  When we unlock, we will subscribe to the
                // CommittingBatch again.
                UnsubscribeFromCommittingBatch(); 
            }
 
            _lockCount++; 
            return true;
        } 

        /// 
        ///   This method decrements the lock count, and if it reaches zero will release the
        ///   on the back buffer and request a render pass. 
        /// 
        ///  
        ///   Critical: Releases lock around unmanaged memory. 
        ///   PublicOK: Pointers are not exposed to caller.  This method
        ///             should work from partial trust. 
        /// 
        [SecurityCritical]
        public void Unlock()
        { 
            WritePreamble();
 
            if (_lockCount == 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Image_MustBeLocked)); 
            }
            Invariant.Assert(_lockCount > 0, "Lock count should never be negative!");

            _lockCount--; 
            if (_lockCount == 0)
            { 
                // This makes the back buffer read-only. 
                _pBackBufferLock.Dispose();
                _pBackBufferLock = null; 

                if (_hasDirtyRects)
                {
                    SubscribeToCommittingBatch(); 

                    // 
                    // Notify listeners that we have changed. 
                    //
                    WritePostscript(); 
                }
            }
        }
 
        /// 
        ///   Updates the pixels in the specified region of the bitmap. 
        ///  
        /// The rect to copy from the input buffer.
        /// The input buffer used to update the bitmap. 
        /// The size of the input buffer in bytes.
        /// The stride of the input buffer in bytes.
        /// The destination x-coordinate of the left-most pixel to copy.
        /// The destination y-coordinate of the top-most pixel to copy. 
        /// 
        ///   Critical: Accesses critical code, performs unsafe operations. 
        ///   PublicOK: Demands unmanaged code permission. 
        /// 
        [SecurityCritical] 
        public void WritePixels(
            Int32Rect sourceRect,
            IntPtr    sourceBuffer,
            int       sourceBufferSize, 
            int       sourceBufferStride,
            int       destinationX, 
            int       destinationY 
            )
        { 
            SecurityHelper.DemandUnmanagedCode();
            WritePreamble();

            WritePixelsImpl(sourceRect, 
                            sourceBuffer,
                            sourceBufferSize, 
                            sourceBufferStride, 
                            destinationX,
                            destinationY, 
                            /*backwardsCompat*/ false);
        }

        ///  
        ///   Updates the pixels in the specified region of the bitmap.
        ///  
        /// The rect to copy from the input buffer. 
        /// The input buffer used to update the bitmap.
        /// The stride of the input buffer in bytes. 
        /// The destination x-coordinate of the left-most pixel to copy.
        /// The destination y-coordinate of the top-most pixel to copy.
        /// 
        ///     Critical: Calls critical methods, has unsafe code. 
        ///     PublicOK: The overall operation is safe, and the input is sanitized.
        ///               This method should work from partial trust. 
        ///  
        [SecurityCritical]
        public void WritePixels( 
            Int32Rect sourceRect,
            Array     sourceBuffer,
            int       sourceBufferStride,
            int       destinationX, 
            int       destinationY
            ) 
        { 
            WritePreamble();
 
            int elementSize;
            int sourceBufferSize;
            Type elementType;
            ValidateArrayAndGetInfo(sourceBuffer, 
                                    /*backwardsCompat*/ false,
                                    out elementSize, 
                                    out sourceBufferSize, 
                                    out elementType);
 
            // We accept arrays of arbitrary value types - but not reference types.
            if (elementType == null || !elementType.IsValueType)
            {
                throw new ArgumentException(SR.Get(SRID.Image_InvalidArrayForPixel)); 
            }
 
            // Get the address of the data in the array by pinning it. 
            GCHandle arrayHandle = GCHandle.Alloc(sourceBuffer, GCHandleType.Pinned);
            try 
            {
                unsafe
                {
                    IntPtr buffer = arrayHandle.AddrOfPinnedObject(); 
                    WritePixelsImpl(sourceRect,
                                    buffer, 
                                    sourceBufferSize, 
                                    sourceBufferStride,
                                    destinationX, 
                                    destinationY,
                                    /*backwardsCompat*/ false);
                }
            } 
            finally
            { 
                arrayHandle.Free(); 
            }
        } 

        /// 
        /// Update the pixels of this Bitmap
        ///  
        /// Area to update
        /// Input buffer 
        /// Size of the buffer 
        /// Stride
        ///  
        /// Critical - access critical code, accepts pointer arguments
        /// PublicOK - demands unmanaged code permission
        /// 
        [SecurityCritical] 
        public unsafe void WritePixels(
            Int32Rect sourceRect, 
            IntPtr buffer, 
            int bufferSize,
            int stride 
            )
        {
            SecurityHelper.DemandUnmanagedCode();
            WritePreamble(); 

            if (bufferSize < 1) 
            { 
                throw new ArgumentOutOfRangeException("bufferSize", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            } 

            if (stride < 1)
            {
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 1)); 
            }
 
            if (sourceRect.IsEmpty || sourceRect.Width <= 0 || sourceRect.Height <= 0) 
            {
                return; 
            }

            // Backwards-Compat:
            // 
            // The "sourceRect" is actually a "destinationRect", as in it
            // refers to the location where the contents are written. 
            // 
            // This method presumes that the pixels are copied from the
            // the specified offset (element count) in the source buffer, and 
            // that no sub-byte pixel formats are used.
            int destinationX = sourceRect.X;
            int destinationY = sourceRect.Y;
            sourceRect.X = 0; 
            sourceRect.Y = 0;
 
            WritePixelsImpl(sourceRect, 
                            buffer,
                            bufferSize, 
                            stride,
                            destinationX,
                            destinationY,
                            /*backwardsCompat*/ true); 
        }
 
        ///  
        /// Update the pixels of this Bitmap
        ///  
        /// Area to update
        /// Input buffer
        /// Stride
        /// Input buffer offset 
        /// 
        /// Critical - This method gets direct access to the input Array's memory. 
        /// PublicOk - Input is a managed buffer which is safe, other inputs are safe as well 
        /// 
        [SecurityCritical] 
        public void WritePixels(
            Int32Rect sourceRect,
            Array pixels,
            int stride, 
            int offset
            ) 
        { 
            WritePreamble();
 
            if (sourceRect.IsEmpty || sourceRect.Width <= 0 || sourceRect.Height <= 0)
            {
                return;
            } 

            int elementSize; 
            int sourceBufferSize; 
            Type elementType;
            ValidateArrayAndGetInfo(pixels, 
                                    /*backwardsCompat*/ true,
                                    out elementSize,
                                    out sourceBufferSize,
                                    out elementType); 

            if (stride < 1) 
            { 
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            } 

            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", SR.Get(SRID.ParameterCannotBeLessThan, 0)); 
            }
 
            // We accept arrays of arbitrary value types - but not reference types. 
            if (elementType == null || !elementType.IsValueType)
            { 
                throw new ArgumentException(SR.Get(SRID.Image_InvalidArrayForPixel));
            }

            checked 
            {
                int offsetInBytes = checked(offset * elementSize); 
                if (offsetInBytes >= sourceBufferSize) 
                {
                    // Backwards compat: 
                    //
                    // The original code would throw an exception deeper in
                    // the code when it indexed off the end of the array.  We
                    // now check earlier (compat break) but throw the same 
                    // exception.
                    throw new IndexOutOfRangeException(); 
                } 

                // Backwards-Compat: 
                //
                // The "sourceRect" is actually a "destinationRect", as in it
                // refers to the location where the contents are written.
                // 
                // This method presumes that the pixels are copied from the
                // the specified offset (element count) in the source buffer, and 
                // that no sub-byte pixel formats are used.  We handle the offset 
                // later.
                int destinationX = sourceRect.X; 
                int destinationY = sourceRect.Y;
                sourceRect.X = 0;
                sourceRect.Y = 0;
 
                // Get the address of the data in the array by pinning it.
                GCHandle arrayHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned); 
                try 
                {
                    IntPtr buffer = arrayHandle.AddrOfPinnedObject(); 

                    checked
                    {
                        buffer = new IntPtr(((long) buffer) + (long) offsetInBytes); 
                        sourceBufferSize -= offsetInBytes;
                    } 
 
                    WritePixelsImpl(sourceRect,
                                    buffer, 
                                    sourceBufferSize,
                                    stride,
                                    destinationX,
                                    destinationY, 
                                    /*backwardsCompat*/ true);
                } 
                finally 
                {
                    arrayHandle.Free(); 
                }
            }
        }
 
        #endregion // Public Methods
 
        #region Protected Methods 

        ///  
        ///   Implementation of Freezable.CreateInstanceCore.
        /// 
        /// The new Freezable.
        protected override Freezable CreateInstanceCore() 
        {
            return new WriteableBitmap(); 
        } 

        ///  
        ///   Implementation of Freezable.CloneCore.
        /// 
        /// 
        ///   Critical:     Accesses critical code. 
        ///   TreatAsSafe:  Method only produces clones of original buffers.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void CloneCore(Freezable sourceFreezable)
        { 
            WriteableBitmap sourceBitmap = (WriteableBitmap) sourceFreezable;

            base.CloneCore(sourceFreezable);
 
            CopyCommon(sourceBitmap);
        } 
 
        /// 
        ///   Implementation of Freezable.FreezeCore. 
        /// 
        /// 
        ///   Critical:     Accesses critical code. (AcquireBackBuffer, FreezeBackBuffer)
        ///   TreatAsSafe:  Method gets the back buffer, but doesn't expose it. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override bool FreezeCore(bool isChecking) 
        {
            bool canFreeze = (_lockCount == 0) && base.FreezeCore(isChecking); 

            if (canFreeze && !isChecking)
            {
                Debug.Assert(_pBackBufferLock == null); 

                // 
                // By entering 'frozen' mode, we convert from being a 
                // DoubleBufferedBitmap to a regular BitmapSource.
                // 

                // Protect the back buffer for writing
                HRESULT.Check(MILSwDoubleBufferedBitmap.ProtectBackBuffer(_pDoubleBufferedBitmap));
 
                // Get the back buffer to be used as our WicSourceHandle
                AcquireBackBuffer(TimeSpan.Zero, false); 
                _needsUpdate = true; 
                _hasDirtyRects = false;
 
                // From here on out we're going to effectively be an ordinary
                // BitmapSource.
                _actLikeSimpleBitmap = true;
 
                // Pull this resource off all the channels and put it back on.
                int channelCount = _duceResource.GetChannelCount(); 
                for (int i = 0; i < channelCount; i++) 
                {
                    DUCE.IResource resource = this as DUCE.IResource; 
                    DUCE.Channel channel = _duceResource.GetChannel(i);

                    //
                    // It could have been added multiple times, so release until 
                    // it's no longer on a channel.
                    // 
                    uint refCount = _duceResource.GetRefCountOnChannel(channel); 
                    for (uint j = 0; j < refCount; j++)
                    { 
                        resource.ReleaseOnChannel(channel);
                    }

                    // Put it back on the Channel, only this time it wont 
                    // be a SwDoubleBufferedBitmap.
                    for (uint j = 0; j < refCount; j++) 
                    { 
                        resource.AddRefOnChannel(channel);
                    } 
                }

                Debug.Assert(!_isWaitingForCommit);
 
                // We no longer need the SwDoubleBufferedBitmap
                _pDoubleBufferedBitmap.Dispose(); 
                _pDoubleBufferedBitmap = null; 

                // We will no longer need to wait for this event. 
                _copyCompletedEvent.Close();
                _copyCompletedEvent = null;

                // Clear out unused variables 
                _committingBatchHandler = null;
                _pBackBuffer = null; 
            } 

            return canFreeze; 
        }

        /// 
        ///   Implementation of Freezable.CloneCurrentValueCore. 
        /// 
        ///  
        ///   Critical:     Accesses critical code. 
        ///   TreatAsSafe:  Method only produces clones of original buffers.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap) sourceFreezable; 

            base.CloneCurrentValueCore(sourceFreezable); 
 
            CopyCommon(sourceBitmap);
        } 

        /// 
        ///   Implementation of Freezable.GetAsFrozenCore.
        ///  
        /// 
        ///   Critical:     Accesses critical code. 
        ///   TreatAsSafe:  Method only produces GetAsFrozen of original buffers. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void GetAsFrozenCore(Freezable sourceFreezable)
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap)sourceFreezable;
 
            base.GetAsFrozenCore(sourceFreezable);
 
            CopyCommon(sourceBitmap); 
        }
 
        /// 
        ///   Implementation of Freezable.GetCurrentValueAsFrozenCore.
        /// 
        ///  
        ///   Critical:     Accesses critical code.
        ///   TreatAsSafe:  Method only produces GetCurrentValueAsFrozen of original image. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) 
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap)sourceFreezable;

            base.GetCurrentValueAsFrozenCore(sourceFreezable); 

            CopyCommon(sourceBitmap); 
        } 

        #endregion // Protected Methods 

        #region Private/Internal Methods

        ///  
        ///     Initializes this WriteableBitmap with the
        ///     contents of the specified BitmapSource. 
        ///  
        /// 
        ///     The BitmapSource to copy. 
        /// 
        /// 
        ///     Critical: Creates and accesses a handle to an unmanaged resource.
        ///     PublicOK: Inputs are safe. 
        /// 
        [SecurityCritical] 
        private void InitFromBitmapSource( 
            BitmapSource source
            ) 
        {
            if (source == null)
            {
                throw new ArgumentNullException("source"); 
            }
 
            if (source.PixelWidth < 0) 
            {
                // Backwards Compat 
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW);
            }

            if (source.PixelHeight < 0) 
            {
                // Backwards Compat 
                HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
            }
 
            BeginInit();

            _syncObject = source.SyncObject;
            lock (_syncObject) 
            {
                Guid formatGuid = source.Format.Guid; 
 
                SafeMILHandle internalPalette = new SafeMILHandle();
                if (source.Format.Palettized) 
                {
                    internalPalette = source.Palette.InternalPalette;
                }
 
                HRESULT.Check(MILSwDoubleBufferedBitmap.Create(
                    (uint)source.PixelWidth, // safe cast 
                    (uint)source.PixelHeight, // safe cast 
                    source.DpiX,
                    source.DpiY, 
                    ref formatGuid,
                    internalPalette,
                    out _pDoubleBufferedBitmap
                    )); 

                Lock(); 
 
                Int32Rect rcFull = new Int32Rect(0, 0, _pixelWidth, _pixelHeight);
                int bufferSize = checked(_backBufferStride.Value * source.PixelHeight); 
                source.CriticalCopyPixels(rcFull, _backBuffer, bufferSize, _backBufferStride.Value);
                AddDirtyRect(rcFull);

                Unlock(); 
            }
 
            EndInit(); 
        }
 
        /// 
        ///     Updates the pixels in the specified region of the bitmap.
        /// 
        ///  
        ///     The rect to copy from the input buffer.
        ///  
        ///  
        ///     The input buffer used to update the bitmap.
        ///  
        /// 
        ///     The size of the input buffer in bytes.
        /// 
        ///  
        ///     The stride of the input buffer in bytes.
        ///  
        ///  
        ///     The destination x-coordinate of the left-most pixel to copy.
        ///  
        /// 
        ///     The destination y-coordinate of the top-most pixel to copy.
        /// 
        ///  
        ///     Whether or not to preserve the old WritePixels behavior.
        ///  
        ///  
        ///   Critical: Accesses critical code, performs unsafe operations.
        ///  
        [SecurityCritical]
        private void WritePixelsImpl(
            Int32Rect sourceRect,
            IntPtr    sourceBuffer, 
            int       sourceBufferSize,
            int       sourceBufferStride, 
            int       destinationX, 
            int       destinationY,
            bool      backwardsCompat 
            )
        {
            //
            // Sanitize the source rect and assure it will fit within the back buffer. 
            //
            if (sourceRect.X < 0) 
            { 
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterCannotBeNegative)); 
            }

            if (sourceRect.Y < 0)
            { 
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterCannotBeNegative)); 
            } 

            if (sourceRect.Width < 0) 
            {
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth));
            } 

            if (sourceRect.Width > _pixelWidth) 
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG);
                }
                else
                { 
                    throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth));
                } 
            } 

            if (sourceRect.Height < 0) 
            {
                Debug.Assert(!backwardsCompat);
                throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight));
            } 

            if (sourceRect.Height > _pixelHeight) 
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG);
                }
                else
                { 
                    throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight));
                } 
            } 

            if (destinationX < 0) 
            {
                if (backwardsCompat)
                {
                    HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); 
                }
                else 
                { 
                    throw new ArgumentOutOfRangeException("sourceRect", SR.Get(SRID.ParameterCannotBeNegative));
                } 
            }

            if (destinationX > _pixelWidth - sourceRect.Width)
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG); 
                }
                else 
                {
                    throw new ArgumentOutOfRangeException("destinationX", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelWidth - sourceRect.Width));
                }
            } 

            if (destinationY < 0) 
            { 
                if (backwardsCompat)
                { 
                    HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW);
                }
                else
                { 
                    throw new ArgumentOutOfRangeException("destinationY", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight - sourceRect.Height));
                } 
            } 

            if (destinationY > _pixelHeight - sourceRect.Height) 
            {
                if (backwardsCompat)
                {
                    HRESULT.Check(MS.Win32.NativeMethods.E_INVALIDARG); 
                }
                else 
                { 
                    throw new ArgumentOutOfRangeException("destinationY", SR.Get(SRID.ParameterMustBeBetween, 0, _pixelHeight - sourceRect.Height));
                } 
            }

            //
            // Sanitize the other parameters. 
            //
            if (sourceBuffer == IntPtr.Zero) 
            { 
                // Backwards Compat:
                // 
                // The original code would null-ref when it was passed a null
                // buffer (IntPtr.Zero).  We choose to throw a better
                // exception.
                throw new ArgumentNullException(backwardsCompat ? "buffer" : "sourceBuffer"); 
            }
 
            if (sourceBufferStride < 1) 
            {
                Debug.Assert(!backwardsCompat); 
                throw new ArgumentOutOfRangeException("sourceBufferStride", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            }

            if (sourceRect.Width == 0 || sourceRect.Height == 0) 
            {
                Debug.Assert(!backwardsCompat); 
 
                // Nothing to do.
                return; 
            }

            checked
            { 
                uint finalRowWidthInBits = (uint)((sourceRect.X + sourceRect.Width) * _format.InternalBitsPerPixel);
                uint finalRowWidthInBytes = ((finalRowWidthInBits + 7) / 8); 
                uint requiredBufferSize = (uint)((sourceRect.Y + sourceRect.Height - 1) * sourceBufferStride) + finalRowWidthInBytes; 
                if (sourceBufferSize < requiredBufferSize)
                { 
                    if (backwardsCompat)
                    {
                        HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER);
                    } 
                    else
                    { 
                        throw new ArgumentException(SR.Get(SRID.Image_InsufficientBufferSize), "sourceBufferSize"); 
                    }
                } 

                uint copyWidthInBits = (uint)(sourceRect.Width * _format.InternalBitsPerPixel);

                // Calculate some offsets that we'll need in a moment. 
                uint sourceXbyteOffset = (uint)((sourceRect.X * _format.InternalBitsPerPixel) / 8);
                uint sourceBufferBitOffset = (uint)((sourceRect.X * _format.InternalBitsPerPixel) % 8); 
                uint firstPixelByteOffet = (uint)((sourceRect.Y * sourceBufferStride) + sourceXbyteOffset); 
                uint destXbyteOffset = (uint)((destinationX * _format.InternalBitsPerPixel) / 8);
                uint destBufferBitOffset = (uint)((destinationX * _format.InternalBitsPerPixel) % 8); 

                Int32Rect destinationRect = sourceRect;
                destinationRect.X = destinationX;
                destinationRect.Y = destinationY; 

                // 
                // Copy pixel information from the user supplied buffer to the back buffer. 
                //
                unsafe 
                {
                    uint destOffset = (uint)(destinationY * _backBufferStride.Value) + destXbyteOffset;
                    byte* pDest = (byte*)_backBuffer.ToPointer();
                    pDest += destOffset; 
                    uint outputBufferSize = _backBufferSize - destOffset;
 
                    byte* pSource = (byte*)sourceBuffer.ToPointer(); 
                    pSource += firstPixelByteOffet;
                    uint inputBufferSize = (uint)sourceBufferSize - firstPixelByteOffet; 

                    Lock();

                    MILUtilities.MILCopyPixelBuffer( 
                        pDest,
                        outputBufferSize, 
                        (uint) _backBufferStride.Value, 
                        destBufferBitOffset,
                        pSource, 
                        inputBufferSize,
                        (uint) sourceBufferStride,
                        sourceBufferBitOffset,
                        (uint) sourceRect.Height, 
                        copyWidthInBits);
 
                    AddDirtyRect(destinationRect); 
                    Unlock();
                } 
            }

            // Note: we do not call WritePostscript because we do not want to
            // raise change notifications until the writeable bitmap is unlocked. 
            //
            // Change notifications may have already been raised in the Unlock 
            // call in this method. 
        }
 
        /// 
        ///   Try to acquire the back buffer of our unmanaged double buffered bitmap in the specified timeout.
        /// 
        ///  
        ///   The time to wait while trying to acquire the lock.
        ///  
        ///  
        ///   Should we try to wait for the copy completed event?
        ///  
        /// Returns true if the back buffer was acquired before the timeout expired.
        /// 
        ///   Critical: Accesses a handle to an unmanaged resource.
        ///  
        [SecurityCritical]
        private bool AcquireBackBuffer(TimeSpan timeout, bool waitForCopy) 
        { 
            bool backBufferAcquired = false;
 
            //
            // Only get the back buffer from the unmanaged double buffered bitmap if this is our
            // first time being called since the last successful call to OnCommittingBatch.
            // OnCommittingBatch sets _pBackBuffer to null. 
            //
            if (_pBackBuffer == null) 
            { 
                bool shouldGetBackBuffer = true;
 
                if (waitForCopy)
                {
                    // If we have committed a copy-forward command, we need to wait
                    // for the render thread to finish the copy before we can use 
                    // the back buffer.
                    shouldGetBackBuffer = _copyCompletedEvent.WaitOne(timeout, false); 
                } 

                if (shouldGetBackBuffer) 
                {
                    MILSwDoubleBufferedBitmap.GetBackBuffer(
                        _pDoubleBufferedBitmap,
                        out _pBackBuffer, 
                        out _backBufferSize);
 
                    _syncObject = WicSourceHandle = _pBackBuffer; 
                    backBufferAcquired = true;
                } 
            }
            else
            {
                backBufferAcquired = true; 
            }
 
            return backBufferAcquired; 
        }
 
        /// 
        ///   Common implementation for CloneCore(), CloneCurrentValueCore(),
        ///   GetAsFrozenCore(), and GetCurrentValueAsFrozenCore().
        ///  
        /// The WriteableBitmap to copy from.
        ///  
        ///   Critical: Accesses a handle to an unmanaged resource. 
        /// 
        [SecurityCritical] 
        private void CopyCommon(WriteableBitmap sourceBitmap)
        {
            // Avoid Animatable requesting resource updates for invalidations
            // that occur during construction. 
            Animatable_IsResourceInvalidationNecessary = false;
            _actLikeSimpleBitmap = false; 
 
            // Create a SwDoubleBufferedBitmap and copy the sourceBitmap into it.
            InitFromBitmapSource(sourceBitmap); 

            // The next invalidation will cause Animatable to register an
            // UpdateResource callback.
            Animatable_IsResourceInvalidationNecessary = true; 
        }
 
 
        // ISupportInitialize
 
        /// 
        ///   Prepare the bitmap to accept initialize paramters.
        /// 
        private void BeginInit() 
        {
            _bitmapInit.BeginInit(); 
        } 

        ///  
        ///   Prepare the bitmap to accept initialize paramters.
        /// 
        /// 
        ///   Critical:     Access critical resources. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void EndInit() 
        {
            _bitmapInit.EndInit(); 

            FinalizeCreation();
        }
 
        /// 
        ///   Create the unmanaged resources. 
        ///  
        /// 
        /// Critical - access critical resource 
        /// 
        [SecurityCritical]
        internal override void FinalizeCreation()
        { 
            IsSourceCached = true;
            CreationCompleted = true; 
            UpdateCachedSettings(); 
        }
 
        /// 
        ///     Get the size of the specified array and of the elements in it.
        /// 
        ///  
        ///     The array to get info about.
        ///  
        ///  
        ///     On output, will contain the size of the elements in the array.
        ///  
        /// 
        ///     On output, will contain the size of the array.
        /// 
        ///  
        ///     Critical - Calls Marshal.SizeOf, which has a link demand for some reason.
        ///  
        [SecurityCritical] 
        private void ValidateArrayAndGetInfo(Array sourceBuffer,
                                                       bool backwardsCompat, 
                                                       out int elementSize,
                                                       out int sourceBufferSize,
                                                       out Type elementType)
        { 
            //
            // Assure that a valid pixels Array was provided. 
            // 
            if (sourceBuffer == null)
            { 
                throw new ArgumentNullException(backwardsCompat ? "pixels" : "sourceBuffer");
            }

            if (sourceBuffer.Rank == 1) 
            {
                if (sourceBuffer.GetLength(0) <= 0) 
                { 
                    if (backwardsCompat)
                    { 
                        elementSize = 1;
                        sourceBufferSize = 0;
                        elementType = null;
                    } 
                    else
                    { 
                        throw new ArgumentException(SR.Get(SRID.Image_InsufficientBuffer), "sourceBuffer"); 
                    }
                } 
                else
                {
                    checked
                    { 
                        object exemplar = sourceBuffer.GetValue(0);
                        elementSize = Marshal.SizeOf(exemplar); 
                        sourceBufferSize = sourceBuffer.GetLength(0) * elementSize; 
                        elementType = exemplar.GetType();
                    } 
                }

            }
            else if (sourceBuffer.Rank == 2) 
            {
                if (sourceBuffer.GetLength(0) <= 0 || sourceBuffer.GetLength(1) <= 0) 
                { 
                    if (backwardsCompat)
                    { 
                        elementSize = 1;
                        sourceBufferSize = 0;
                        elementType = null;
                    } 
                    else
                    { 
                        throw new ArgumentException(SR.Get(SRID.Image_InsufficientBuffer), "sourceBuffer"); 
                    }
                } 
                else
                {
                    checked
                    { 
                        object exemplar = sourceBuffer.GetValue(0,0);
                        elementSize = Marshal.SizeOf(exemplar); 
                        sourceBufferSize = sourceBuffer.GetLength(0) * sourceBuffer.GetLength(1) * elementSize; 
                        elementType = exemplar.GetType();
                    } 
                }
            }
            else
            { 
                throw new ArgumentException(SR.Get(SRID.Collection_BadRank), backwardsCompat ? "pixels" : "sourceBuffer");
            } 
        } 

        ///  
        ///     Adds a reference to our DUCE resource on .
        /// 
        /// 
        ///     The channel we want to AddRef on. 
        /// 
        ///  
        ///     The handle to our DoubleBufferedBitmap or BitmapSource handle. 
        /// 
        ///  
        ///     We override this method because we use a different resource
        ///     type than our base class does.  This probably suggests that the
        ///     base class should not presume the resource type, but it
        ///     currently does.  The base class uses TYPE_BITMAPSOURCE 
        ///     resources, and we use TYPE_DOUBLEBUFFEREDBITMAP resources.
        ///  
        internal override DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel) 
        {
            // 
            // If we're in BitmapSource mode, then just defer to the BitmapSource
            // implementation.
            //
            if (_actLikeSimpleBitmap) 
            {
                return base.AddRefOnChannelCore(channel); 
            } 

            if (_duceResource.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_DOUBLEBUFFEREDBITMAP)) 
            {
                // This is the first AddRef on this channel...

                // If we are being put onto the asynchronous compositor channel in 
                // a dirty state, we need to subscribe to the CommittingBatch event.
                if (!channel.IsSynchronous && _hasDirtyRects) 
                { 
                    SubscribeToCommittingBatch();
                } 

                AddRefOnChannelAnimations(channel);

                // The first time our resource is created on a channel, we need 
                // to update it.  We can skip "on channel" check since we
                // already know that the resource is on channel. 
                UpdateResource(channel, true); 
            }
 
            return _duceResource.GetHandle(channel);
        }

        internal override void ReleaseOnChannelCore(DUCE.Channel channel) 
        {
            Debug.Assert(_duceResource.IsOnChannel(channel)); 
 
            if (_duceResource.ReleaseOnChannel(channel))
            { 
                // This is the last release from this channel...

                // If we are being pulled off the asynchronous compositor channel
                // then unsubscribe from the CommittingBatch event. 
                if (!channel.IsSynchronous)
                { 
                    UnsubscribeFromCommittingBatch(); 
                }
 
                ReleaseOnChannelAnimations(channel);
            }
        }
 
        /// 
        ///   Updates the double-buffered bitmap DUCE resource with a pointer to our acutal object. 
        ///  
        /// The channel to update the resource on.
        ///  
        ///   If this is true, we know we are on channel and don't need to explicitly check.
        /// 
        /// 
        ///   Critical:     Accesses a handle to an unmanaged resource.  Calls critical methods. 
        ///   TreateAsSafe: We allocate the double buffered bitmap ourself and the user can never
        ///                 get ahold of it. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override void UpdateBitmapSourceResource(DUCE.Channel channel, bool skipOnChannelCheck) 
        {
            //
            // If we're in BitmapSource mode, then just defer to the BitmapSource
            // implementation. 
            //
            if (_actLikeSimpleBitmap) 
            { 
                base.UpdateBitmapSourceResource(channel, skipOnChannelCheck);
                return; 
            }

            // We override this method because we use a different resource type
            // than our base class does.  This probably suggests that the base 
            // class should not presume the resource type, but it currently
            // does.  The base class uses TYPE_BITMAPSOURCE resources, and we 
            // use TYPE_DOUBLEBUFFEREDBITMAP resources. 

            // If we're told we can skip the channel check, then we must be on channel 
            Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel));

            if (skipOnChannelCheck || _duceResource.IsOnChannel(channel))
            { 
                DUCE.MILCMD_DOUBLEBUFFEREDBITMAP command;
                command.Type = MILCMD.MilCmdDoubleBufferedBitmap; 
                command.Handle = _duceResource.GetHandle(channel); 
                unsafe
                { 
                    command.SwDoubleBufferedBitmap = (UInt64) _pDoubleBufferedBitmap.DangerousGetHandle().ToPointer();
                }
                command.UseBackBuffer = channel.IsSynchronous ? 1u : 0u;
 
                //
                // We need to ensure that this object stays alive while traveling over the channel 
                // so we'll AddRef it here, and simply take over the reference on the other side. 
                //
                UnsafeNativeMethods.MILUnknown.AddRef(_pDoubleBufferedBitmap); 

                unsafe
                {
                    channel.SendSecurityCriticalCommand( 
                        (byte*)&command,
                        sizeof(DUCE.MILCMD_DOUBLEBUFFEREDBITMAP) 
                        ); 
                }
            } 
        }

        private void SubscribeToCommittingBatch()
        { 
            // Only subscribe the the CommittingBatch event if we are on-channel.
            if (!_isWaitingForCommit) 
            { 
                MediaContext mediaContext = MediaContext.From(Dispatcher);
                if (_duceResource.IsOnChannel(mediaContext.Channel)) 
                {
                    mediaContext.CommittingBatch += CommittingBatchHandler;
                    _isWaitingForCommit = true;
                } 
            }
        } 
 
        private void UnsubscribeFromCommittingBatch()
        { 
            if (_isWaitingForCommit)
            {
                MediaContext mediaContext = MediaContext.From(Dispatcher);
                mediaContext.CommittingBatch -= CommittingBatchHandler; 
                _isWaitingForCommit = false;
            } 
        } 

        ///  
        ///   Send a packet on the DUCE.Channel telling our double-buffered bitmap resource
        ///   to copy forward dirty regions from the back buffer to the front buffer.
        /// 
        ///  
        ///   For the packet to be sent, the user must have added a dirty region to the
        ///   WriteableBitmap and there must be no outstanding locks. 
        ///  
        /// 
        ///   Critical:     Accesses critical methods and a handle to an unmanaged resource. 
        ///   TreatAsSafe:  Inputs are supplied internally.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void OnCommittingBatch(object sender, EventArgs args) 
        {
            Debug.Assert(_isWaitingForCommit);  // How else are we here? 
            UnsubscribeFromCommittingBatch(); 

            Debug.Assert(_lockCount == 0);  // How else are we here? 
            Debug.Assert(_hasDirtyRects);  // How else are we here?

            // Before using the back buffer again, we need to know when
            // the rendering thread has completed the copy. By setting 
            // our back buffer pointer to null, we'll have to re-acquire
            // it the next time, which will wait for the copy to complete. 
            _copyCompletedEvent.Reset(); 
            _pBackBuffer = null;
 
            DUCE.Channel channel = sender as DUCE.Channel;
            Debug.Assert(_duceResource.IsOnChannel(channel));  // How else are we here?

            // We are going to pass an event in the command packet we send to 
            // the composition thread.  We need to make sure the event stays
            // alive in case we get collected before the composition thread 
            // processes the packet.  We do this by duplicating the event 
            // handle, and the composition thread will close the handle after
            // signalling it. 
            IntPtr hDuplicate;
            IntPtr hCurrentProc = MS.Win32.UnsafeNativeMethods.GetCurrentProcess();
            if (!MS.Win32.UnsafeNativeMethods.DuplicateHandle(
                    hCurrentProc, 
                    _copyCompletedEvent.SafeWaitHandle,
                    hCurrentProc, 
                    out hDuplicate, 
                    0,
                    false, 
                    MS.Win32.UnsafeNativeMethods.DUPLICATE_SAME_ACCESS
                    ))
            {
                throw new Win32Exception(); 
            }
 
            DUCE.MILCMD_DOUBLEBUFFEREDBITMAP_COPYFORWARD command; 
            command.Type = MILCMD.MilCmdDoubleBufferedBitmapCopyForward;
            command.Handle = _duceResource.GetHandle(channel); 
            command.CopyCompletedEvent = (UInt64) hDuplicate.ToInt64();

            unsafe
            { 
                channel.SendSecurityCriticalCommand(
                    (byte*)&command, 
                    sizeof(DUCE.MILCMD_DOUBLEBUFFEREDBITMAP_COPYFORWARD) 
                    );
            } 

            // We are committing the batch to the asynchronous compositor,
            // which will copy the rects forward.  The copy will complete
            // before we can access the back buffer again.  So, we consider 
            // ourselves clean.
            _hasDirtyRects = false; 
        } 

        #endregion 

        #region Properties

        ///  
        ///   Read-only data pointer to the back buffer.
        ///  
        ///  
        ///   Critical:  Accesses back buffer pointer.
        ///   PublicOK:  Demands unmanaged code permission. 
        /// 
        public IntPtr BackBuffer
        {
            [SecurityCritical] 
            get
            { 
                SecurityHelper.DemandUnmanagedCode(); 
                ReadPreamble();
 
                return _backBuffer;
            }

            [SecurityCritical] 
            private set
            { 
                _backBuffer = value; 
            }
        } 

        /// 
        ///     Critical: The pointer to the back buffer pixels.
        ///  
        [SecurityCritical]
        private IntPtr _backBuffer; 
 
        /// 
        ///     Critical: The size of the back buffer.  Should never be exposed 
        ///     to external parties.
        /// 
        [SecurityCritical]
        private uint _backBufferSize; 

        ///  
        ///   Read-only stride of the back buffer. 
        /// 
        public int BackBufferStride 
        {
            get
            {
                ReadPreamble(); 

                return _backBufferStride.Value; 
            } 
        }
 
        /// 
        ///     Critical: Sets the back buffer stride, which is important for
        ///               internal pointer arithmetic calculations.
        ///  
        private SecurityCriticalDataForSet _backBufferStride;
 
        #endregion // Properties 

        #region Fields 

        /// 
        ///     Critical: The pointer to the IMILSwDoubleBufferedBitmap
        ///               interface that manages the back and front buffers. 
        /// 
        [SecurityCritical] 
        private SafeMILHandle _pDoubleBufferedBitmap;   // CSwDoubleBufferedBitmap 

        ///  
        ///     Critical: The pointer to the IWICBitmapLock interface that
        ///               provides access to the back buffer pointer.
        /// 
        [SecurityCritical] 
        private SafeMILHandle _pBackBufferLock;         // IWICBitmapLock
 
        ///  
        ///     Critical: The pointer to the IMILBitmap interface that is the
        ///               back buffer. 
        /// 
        [SecurityCritical]
        private BitmapSourceSafeMILHandle _pBackBuffer; // IMILBitmap
 
        private uint _lockCount = 0;
 
        // Flags whether the user has added a dirty rect since the last CopyForward packet was sent. 
        private bool _hasDirtyRects = true;
 
        // Flags whether a MediaContext.CommittingBatch handler has already been added.
        private bool _isWaitingForCommit = false;

        private ManualResetEvent _copyCompletedEvent = new ManualResetEvent(true); 

        private EventHandler CommittingBatchHandler 
        { 
            get
            { 
                if (_committingBatchHandler == null)
                {
                    _committingBatchHandler = OnCommittingBatch;
                } 

                return _committingBatchHandler; 
            } 
        }
        private EventHandler _committingBatchHandler; // = OnCommittingBatch (CS0236) 

        private bool _actLikeSimpleBitmap = false;

        #endregion // Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

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