File: Core\CSharp\System\Windows\Media\ChannelManager.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//------------------------------------------------------------------------------
//
// <copyright file="ChannelManager.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description:
//      The ChannelManager is a helper structure internal to MediaContext
//      that abstracts out channel creation, storage and destruction.
//
//------------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Composition;
using System.Security;
 
using MS.Internal;
using MS.Utility;
using MS.Win32;
 
using Microsoft.Win32.SafeHandles;
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
 
using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods.MilCoreApi;
 
namespace System.Windows.Media
{
    partial class MediaContext
    {
        /// <summary>
        /// A helper structure that abstracts channel management.
        /// </summary>
        /// <remarks>
        /// The common agreement (avcomptm, avpttrev) is that channel creation 
        /// should be considered unsafe and therefore subject to control via 
        /// the SecurityCritical/SecurityTreatAsSafe mechanism.
        /// 
        /// On the other hand, using a channel that has been created by the 
        /// MediaContext is considered safe. 
        ///
        /// This class expresses the above policy by hiding channel creation
        /// and storage within the MediaContext while allowing to access 
        /// the channels at will.
        /// </remarks>
        private struct ChannelManager
        {
            /// <summary>
            /// Opens an asynchronous channel.
            /// </summary>
            /// <securitynote>
            /// Critical - Creates a channel, calls a Channel method, calls methods performing elevations.
            /// TreatAsSafe - It is safe for the media context to create and use a channel.
            /// </securitynote>
            [SecurityCritical, SecurityTreatAsSafe]
            internal void CreateChannels()
            {
                Invariant.Assert(_asyncChannel == null);
                Invariant.Assert(_asyncOutOfBandChannel == null);
 
                // Create a channel into the async composition device.
                // Pass in a reference to the global mediasystem channel so that it uses
                // the same partition.
                _asyncChannel = new DUCE.Channel(
                    System.Windows.Media.MediaSystem.ServiceChannel,
                    false,      // not out of band
                    System.Windows.Media.MediaSystem.Connection,
                    false // sync transport
                    );
 
                _asyncOutOfBandChannel = new DUCE.Channel(
                    System.Windows.Media.MediaSystem.ServiceChannel,
                    true,       // out of band
                    System.Windows.Media.MediaSystem.Connection,
                    false // sync transport
                    );
            }
 
            /// <summary>
            /// Closes all opened channels.
            /// </summary>
            /// <securitynote>
            /// Critical - Closes channels.
            /// TreatAsSafe - It is safe for the media context to sync channels channel.
            /// </securitynote>
            [SecurityCritical, SecurityTreatAsSafe]
            internal void RemoveSyncChannels()
            {
                //
                // Close the synchronous channels.
                //
                
                if (_freeSyncChannels != null)
                {
                    while (_freeSyncChannels.Count > 0) 
                    {
                        _freeSyncChannels.Dequeue().Close();
                    }
                    _freeSyncChannels = null;
                }
 
                if (_syncServiceChannel != null)
                {
                    _syncServiceChannel.Close();
 
                    _syncServiceChannel = null;
                }
            }
 
            /// <summary>
            /// Closes all opened channels.
            /// </summary>
            /// <securitynote>
            /// Critical - Closes channels.
            /// TreatAsSafe - It is safe for the media context to close a channel.
            /// </securitynote>
            [SecurityCritical, SecurityTreatAsSafe]
            internal void RemoveChannels()
            {
                if (_asyncChannel != null)
                {
                    _asyncChannel.Close();
                    _asyncChannel = null;
                }
 
                if (_asyncOutOfBandChannel != null)
                {
                    _asyncOutOfBandChannel.Close();
                    _asyncOutOfBandChannel = null;
                }
               
                RemoveSyncChannels();
 
                if (_pSyncConnection != IntPtr.Zero)
                {
                    HRESULT.Check(UnsafeNativeMethods.WgxConnection_Disconnect(_pSyncConnection));
                    _pSyncConnection = IntPtr.Zero;
                }
 
            }
 
            /// <summary>
            /// Create a fresh or fetch one from the pool synchronous channel.
            /// </summary>
            /// <securitynote>
            /// Critical - Calls critical methods to create a synchronous channel and return it. 
            /// TreatAsSafe - This function allocates the channel in a Channel class that guards channel
            ///     access from insecure access. It is also ok for this method to allocate the native objects
            ///     since there is nothing security critical about having the channel infrastructure initialized.
            /// </securitynote>
            [SecurityCritical, SecurityTreatAsSafe]
            internal DUCE.Channel AllocateSyncChannel()
            {
                DUCE.Channel syncChannel;
 
                if (_pSyncConnection == IntPtr.Zero)
                {
                    HRESULT.Check(UnsafeNativeMethods.WgxConnection_Create(
                        true, // true means synchronous transport
                        out _pSyncConnection));
                }
 
                if (_freeSyncChannels == null)
                {
                    //
                    // Ensure the free sync channels queue...
                    //
 
                    _freeSyncChannels = new Queue<DUCE.Channel>(3);
                }
 
                if (_freeSyncChannels.Count > 0) 
                {
                    //
                    // If there is a free sync channel in the queue, we're done:
                    //
                    
                    return _freeSyncChannels.Dequeue();
                }
                else
                {
                    //
                    // Otherwise, create a new channel. We will try to cache it
                    // when the ReleaseSyncChannel call is made. Also ensure the
                    // synchronous service channel and glyph cache.
                    //
                    
                    if (_syncServiceChannel == null) 
                    {
                        _syncServiceChannel  = new DUCE.Channel(
                            null,
                            false,      // not out of band
                            _pSyncConnection,
                            true        // synchronous
                            );
                    }
                    
                    syncChannel = new DUCE.Channel(
                        _syncServiceChannel,
                        false,      // not out of band
                        _pSyncConnection,
                        true        // synchronous
                        );
 
                    return syncChannel;
                }
            }
 
            /// <summary>
            /// Returns a sync channel back to the pool.
            /// </summary>
            /// <securitynote>
            /// Critical - Creates and returns a synchronous channel.
            /// TreatAsSafe - Closing a channel is safe.
            /// </securitynote>
            [SecurityCritical, SecurityTreatAsSafe]
            internal void ReleaseSyncChannel(DUCE.Channel channel)
            {
                Invariant.Assert(_freeSyncChannels != null);
 
                //
                // A decision needs to be made whether or not we're interested
                // in re-using this channel later. For now, store up to three
                // synchronous channel in the queue.
                //
                
                if (_freeSyncChannels.Count <= 3) 
                {
                    _freeSyncChannels.Enqueue(channel);
                }
                else
                {
                    channel.Close();
                }
 
            }
 
            /// <summary>
            /// Returns the asynchronous channel.
            /// </summary>
            /// <SecurityNote>
            /// Critical - Channels are a controlled unmanaged resource.
            /// TreatAsSafe - Using a channel created by the media context is safe.
            /// </SecurityNote>
            internal DUCE.Channel Channel
            {
                [SecurityCritical, SecurityTreatAsSafe]
                get
                {
                    return _asyncChannel;
                }
            }
 
            /// <summary>
            /// Returns the asynchronous out-of-band channel.
            /// </summary>
            /// <SecurityNote>
            /// Critical - Channels are a controlled unmanaged resource.
            /// TreatAsSafe - Using a channel created by the media context is safe.
            /// </SecurityNote>
            internal DUCE.Channel OutOfBandChannel
            {
                [SecurityCritical, SecurityTreatAsSafe]
                get
                {
                    return _asyncOutOfBandChannel;
                }
            }
            
            /// <summary>
            /// The asynchronous channel.
            /// </summary>
            /// <remarks>
            /// This field will be replaced with an asynchronous channel table as per task #26681.
            /// </remarks>
            /// <SecurityNote>
            /// Critical - Channels are a controlled unmanaged resource.
            /// </SecurityNote>
            [SecurityCritical]
            private DUCE.Channel _asyncChannel;
 
 
            /// <summary>
            /// The asynchronous out-of-band channel.
            /// </summary>
            /// <remarks>
            /// This is needed by CompositionTarget for handling WM_PAINT, etc.
            /// </remarks>
            /// <SecurityNote>
            /// Critical - Channels are a controlled unmanaged resource.
            /// </SecurityNote>
            [SecurityCritical]
            private DUCE.Channel _asyncOutOfBandChannel;
 
            /// <summary>
            /// We store the free synchronous channels for later re-use in this queue.
            /// </summary>
            /// <SecurityNote>
            /// Critical - Channels are a controlled unmanaged resource.
            /// </SecurityNote>
            [SecurityCritical]
            private Queue<DUCE.Channel> _freeSyncChannels;
 
            /// <summary>
            /// The service channel to the synchronous partition.
            /// </summary>
            /// <SecurityNote>
            /// Critical - Channels are a controlled unmanaged resource.
            /// </SecurityNote>
            [SecurityCritical]
            private DUCE.Channel _syncServiceChannel;
 
            /// <summary>
            /// Pointer to the unmanaged connection object.
            /// </summary>
            /// <SecurityNote>
            /// Critical - Controlled unmanaged resource.
            /// </SecurityNote>
            [SecurityCritical]
            private IntPtr _pSyncConnection;
        }
    }
}