File: System\Windows\Media\ChannelManager.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
//
// 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 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>
            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>
            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>
            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>
            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>
            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>
            internal DUCE.Channel Channel
            {
                get
                {
                    return _asyncChannel;
                }
            }
 
            /// <summary>
            /// Returns the asynchronous out-of-band channel.
            /// </summary>
            internal DUCE.Channel OutOfBandChannel
            {
                get
                {
                    return _asyncOutOfBandChannel;
                }
            }
            
            /// <summary>
            /// The asynchronous channel.
            /// </summary>
            /// <remarks>
            /// This field will be replaced with an asynchronous channel table as per task #26681.
            /// </remarks>
            private DUCE.Channel _asyncChannel;
 
 
            /// <summary>
            /// The asynchronous out-of-band channel.
            /// </summary>
            /// <remarks>
            /// This is needed by CompositionTarget for handling WM_PAINT, etc.
            /// </remarks>
            private DUCE.Channel _asyncOutOfBandChannel;
 
            /// <summary>
            /// We store the free synchronous channels for later re-use in this queue.
            /// </summary>
            private Queue<DUCE.Channel> _freeSyncChannels;
 
            /// <summary>
            /// The service channel to the synchronous partition.
            /// </summary>
            private DUCE.Channel _syncServiceChannel;
 
            /// <summary>
            /// Pointer to the unmanaged connection object.
            /// </summary>
            private IntPtr _pSyncConnection;
        }
    }
}