|
//+----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Abstract:
// Media system holds the relation between an application
// domain and the underlying transport system.
//
//-----------------------------------------------------------------------------
using System;
using System.Windows.Threading;
using System.Collections;
using System.Diagnostics;
using System.Windows.Media.Animation;
using System.Windows.Media.Composition;
using Microsoft.Win32;
using Microsoft.Internal;
using MS.Internal;
using MS.Internal.FontCache;
using MS.Win32;
using System.Security;
using System.Security.Permissions;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods.MilCoreApi;
using SafeNativeMethods=MS.Win32.PresentationCore.SafeNativeMethods;
namespace System.Windows.Media
{
/// <summary>
/// The MediaSystem class controls the media layer.
/// </summary>
/// <remarks>
/// Use <see cref="MediaSystem.Startup"/> to start up the media system and <see cref="MediaSystem.Shutdown"/> to
/// shut down the mediasystem.
/// </remarks>
internal static class MediaSystem
{
/// <summary>
/// This function initializes the MediaSystem. It must be called before any functions in the Media namespace
/// can be used.
/// </summary>
/// <seealso cref="Shutdown"/>
/// <securitynote>
/// Critical -- gets and stores an unmanaged pointer to the current transport from milcore.
/// TreatAsSafe -- starting up the transport is considered a safe operation. Worst case is that
/// we will create a transport object nobody is going to use. Access to the transport
/// object pointer is security critical.
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe ]
public static bool Startup(MediaContext mc)
{
//
// Note to stress triagers:
//
// This call will fail if PresentationCore.dll and milcore.dll have mismatched
// versions -- please make sure that both binaries have been properly built
// and deployed.
//
// *** Failure here does NOT indicate a bug in MediaContext.Startup! ***
//
HRESULT.Check(UnsafeNativeMethods.MilVersionCheck(MS.Internal.Composition.Version.MilSdkVersion));
using (CompositionEngineLock.Acquire())
{
_mediaContexts.Add(mc);
//Is this the first startup?
if (0 == s_refCount)
{
HRESULT.Check(SafeNativeMethods.MilCompositionEngine_InitializePartitionManager(
0 // THREAD_PRIORITY_NORMAL
));
s_forceSoftareForGraphicsStreamMagnifier =
UnsafeNativeMethods.WgxConnection_ShouldForceSoftwareForGraphicsStreamClient();
ConnectTransport();
// Read a flag from the registry to determine whether we should run
// animation smoothing code.
ReadAnimationSmoothingSetting();
}
s_refCount++;
}
//
return true;
}
internal static bool ConnectChannels(MediaContext mc)
{
bool fCreated = false;
using (CompositionEngineLock.Acquire())
{
if (IsTransportConnected)
{
mc.CreateChannels();
fCreated = true;
}
}
return fCreated;
}
/// <summary>
/// Reads a value from the registry to decide whether to disable the animation
/// smoothing algorithm.
/// </summary>
/// <securitynote>
/// Critical - asserts registry permissions to read from HKEY_LOCAL_MACHINE.
/// Treat as safe - we only read a binary value used exclusively for Avalon.
/// </securitynote>
/// <remarks>
/// The code is only present in internal builds
/// </remarks>
[SecurityCritical, SecurityTreatAsSafe ]
private static void ReadAnimationSmoothingSetting()
{
#if PRERELEASE
// Acquire permissions to read the one key we care about from the registry
RegistryPermission permission = new RegistryPermission(
RegistryPermissionAccess.Read,
System.Security.AccessControl.AccessControlActions.View,
@"HKEY_LOCAL_MACHINE\Software\Microsoft\Avalon.Graphics");
permission.Assert();
try
{
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Avalon.Graphics");
if (key != null)
{
object keyValue = key.GetValue("AnimationSmoothing");
// The Regkey now turns off AnimationSmoothing
s_animationSmoothing = !(keyValue is int && ((int)keyValue) == 0);
}
}
finally
{
RegistryPermission.RevertAssert();
}
#endif
}
/// <summary>
/// This deinitializes the MediaSystem and frees any resources that it maintains.
/// </summary>
/// <securitynote>
/// Critical -- results in the release of an unmanaged pointer to the current transport.
/// TreatAsSafe -- shutting down the transport is considered a safe operation. Worst case
/// is that the client stops rendering Avalon content.
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe ]
internal static void Shutdown(MediaContext mc)
{
using (CompositionEngineLock.Acquire())
{
Debug.Assert(s_refCount > 0);
_mediaContexts.Remove(mc);
s_refCount--;
if (0 == s_refCount)
{
// We can shut-down.
// Debug.WriteLine("MediSystem::NotifyDisconnect Stop Transport\n");
if (IsTransportConnected)
{
DisconnectTransport();
}
HRESULT.Check(SafeNativeMethods.MilCompositionEngine_DeinitializePartitionManager());
}
}
}
/// <summary>
/// Handle DWM messages that indicate that the state of the connection needs to change.
/// </summary>
/// <SecurityNote>
/// Critical because NotifyRedirectionEnvironmentChanged calls methods that
/// control the composition engine in native code. TreatAsSafe since caller
/// cannot cause any damages with it besides starting and stopping his application's
/// own composition engine whicih would worst cases prevent his app from rendering.
/// No critical data is being passed in or out since there are no arguments or return values.
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
internal static void NotifyRedirectionEnvironmentChanged()
{
using (CompositionEngineLock.Acquire())
{
// Check to see if we need to force software for the Vista Magnifier
s_forceSoftareForGraphicsStreamMagnifier =
UnsafeNativeMethods.WgxConnection_ShouldForceSoftwareForGraphicsStreamClient();
foreach (MediaContext mc in _mediaContexts)
{
mc.PostInvalidateRenderMode();
}
}
}
/// <summary>
/// Connect the transport.
/// </summary>
/// <securitynote>
/// Critical - Creates a channel, calls methods performing elevations.
/// TreatAsSafe - Transport initialization is considered safe. Service channel
/// creation is safe.
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe]
private static void ConnectTransport()
{
if (IsTransportConnected)
{
throw new System.InvalidOperationException(SR.Get(SRID.MediaSystem_OutOfOrderConnectOrDisconnect));
}
//
// Create a default transport to be used by this media system.
// If creation fails, fall back to a local transport.
//
HRESULT.Check(UnsafeNativeMethods.WgxConnection_Create(
false, // false means asynchronous transport
out s_pConnection));
// Create service channel used by global glyph cache. This channel is
// the first channel created for the app, and by creating it with
// a null channel reference it creates a new partition.
// All subsequent channel creates will pass in a reference to this
// channel thus using its partition.
s_serviceChannel = new DUCE.Channel(
null,
false, // not out of band
s_pConnection,
false);
IsTransportConnected = true;
}
/// <summary>
/// Disconnect the transport. If we are calling this function from a disconnect
/// request we want to keep the service channel around. So that media contexts that
/// have not yet received disconnect event do not crash.
/// </summary>
/// <securitynote>
/// Critical - Closes a channel. Shuts down the transport.
/// TreatAsSafe - Shutting down the transport is considered safe.
/// Closing the service channel is safe.
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe]
private static void DisconnectTransport()
{
if (!IsTransportConnected)
{
return;
}
// Close global glyph cache channel.
s_serviceChannel.Close();
HRESULT.Check(UnsafeNativeMethods.WgxConnection_Disconnect(s_pConnection));
// Release references to global glyph cache and service channel.
s_serviceChannel = null;
s_pConnection = IntPtr.Zero;
IsTransportConnected = false;
}
/// <summary>
/// Checks if to CAO have the same context affinity. This is for example important for
/// ContainerVisual.Children.Add to ensure that the scene graph is homogenously build out
/// of object that have the same context affinity.
/// </summary>
/// <param name="reference">Reference to which to compare to. This argument is usually the this
/// pointer and can not be null.</param>
/// <param name="other">Object for which the check is performed.</param>
/// <remarks>
/// Example:
///
/// class Visual
/// {
/// ...
/// void Add(Visual child)
/// {
/// VerifyContext(this);
/// AssertSameContext(this, child);
/// ...
/// }
/// }
///
/// Note that VerifyContext(A) AND AssertSameContext(A, B) implies that VerifyContext(B) holds. Hence you
/// don't need to check the context for each argument if you assert the same context.
/// </remarks>
internal static void AssertSameContext(
DispatcherObject reference,
DispatcherObject other)
{
Debug.Assert(reference != null, "The reference object can not be null.");
// DispatcherObjects may be created with the option of becoming unbound.
// An unbound DO may be created without a Dispatcher or may detach from
// its Dispatcher (e.g., a Freezable). Unbound DOs return null for their
// Dispatcher and should be accepted anywhere.
if (other != null &&
reference.Dispatcher != null &&
other.Dispatcher != null &&
reference.Dispatcher != other.Dispatcher)
{
throw new ArgumentException(SR.Get(SRID.MediaSystem_ApiInvalidContext));
}
}
/// <summary>
/// This flag indicates if the transport has been disabled by a session disconnect.
/// If the transport has been disabled we need to defer all media system startup requests
/// until we get the next connect message
/// </summary>
internal static bool IsTransportConnected
{
get { return s_isConnected; }
set { s_isConnected = value; }
}
/// <summary>
/// This flag indicates if all rendering should be in software.
/// </summary>
/// <SecurityNote>
/// Critical because s_forceSoftareForGraphicsStreamMagnifier is security critical, but
/// only if it can be set (since that controls if rendering is sw/hw). Because
/// this method does not allow setting s_forceSoftareForGraphicsStreamMagnifier, it cannot
/// be used to control rendering mode. Reading it is safe since this is information
/// we volunteer anyhow in the tiering API.
/// </SecurityNote>
internal static bool ForceSoftwareRendering
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
using (CompositionEngineLock.Acquire())
{
return s_forceSoftareForGraphicsStreamMagnifier;
}
}
}
/// <summary>
/// Returns the service channel for the current media system. This channel
/// is used by the glyph cache infrastructure.
/// </summary>
/// <SecurityNote>
/// Critical - Controlled unmanaged resource.
/// </SecurityNote>
internal static DUCE.Channel ServiceChannel
{
[SecurityCritical]
get { return s_serviceChannel; }
}
/// <summary>
/// Returns the pointer to the unmanaged transport object.
/// </summary>
/// <SecurityNote>
/// Critical - Controlled unmanaged resource.
/// </SecurityNote>
internal static IntPtr Connection
{
[SecurityCritical]
get { return s_pConnection; }
}
internal static bool AnimationSmoothing
{
get { return s_animationSmoothing; }
}
/// <summary>
/// Keeps track of how often MediaSystem.Startup is called. So that the MediaSystem can be shut down at the right
/// point in time.
/// </summary>
private static int s_refCount = 0;
private static ArrayList _mediaContexts = new ArrayList();
private static bool s_isConnected = false;
/// <summary>
/// Service channel to serve global glyph cache.
/// </summary>
/// <SecurityNote>
/// Critical - Controlled unmanaged resource.
/// </SecurityNote>
[SecurityCritical]
private static DUCE.Channel s_serviceChannel;
private static bool s_animationSmoothing = true;
/// <summary>
/// Pointer to the unmanaged transport object.
/// </summary>
/// <SecurityNote>
/// Critical - Controlled unmanaged resource.
/// </SecurityNote>
[SecurityCritical]
private static IntPtr s_pConnection;
/// <summary>
/// Indicates if a graphics stream client is present. If a graphics stream client is present,
/// we drop back to sw rendering to enable the Vista magnifier.
/// </summary>
/// <SecurityNote>
/// Critical - controls rendering mode (hw/sw).
/// </SecurityNote>
[SecurityCritical]
private static bool s_forceSoftareForGraphicsStreamMagnifier;
}
}
|