Dispatcher.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / System / Windows / Threading / Dispatcher.cs / 3 / Dispatcher.cs

                            using System;                                // Console 
using System.Collections.Generic;            // List
using MS.Win32;                              // win32 interop
using System.Windows.Interop;                // ComponentDispatcher & MSG
using Microsoft.Win32;                       // Registry 
using System.Security;                       // CAS
using System.Security.Permissions;           // Registry permissions 
using System.Diagnostics;                    // Debug 
using MS.Utility;                            // EventTrace
using System.Reflection;                     // Assembly 
using System.Runtime.InteropServices;        // SEHException
using MS.Internal;                           // SecurityCriticalData, TextServicesInterop
using MS.Internal.WindowsBase;               // SecurityHelper
using System.Threading; 
using System.ComponentModel; // EditorBrowsableAttribute, BrowsableAttribute
 
// Disabling 1634 and 1691: 
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler, 
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691

namespace System.Windows.Threading 
{
    ///  
    ///     Provides UI services for a thread. 
    /// 
    public sealed class Dispatcher 
    {
        /// 
        ///     Critical: This code calls into RegisterWindowMesssage which is critical
        ///     TreatAsSafe: This is safe to call as no external parameters are taken in 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        static Dispatcher() 
        {
            _msgProcessQueue = UnsafeNativeMethods.RegisterWindowMessage("DispatcherProcessQueue"); 
            _globalLock = new object();
            _dispatchers = new List();
            _possibleDispatcher = new WeakReference(null);
            _exceptionWrapper = new ExceptionWrapper(); 
            _exceptionWrapper.Catch += new ExceptionWrapper.CatchHandler(CatchExceptionStatic);
            _exceptionWrapper.Filter += new ExceptionWrapper.FilterHandler(ExceptionFilterStatic); 
        } 

        ///  
        ///     Returns the Dispatcher for the calling thread.
        /// 
        /// 
        ///     If there is no dispatcher available for the current thread, 
        ///     and the thread allows a dispatcher to be auto-created, a new
        ///     dispatcher will be created. 
        ///     

/// If there is no dispatcher for the current thread, and thread /// does not allow one to be auto-created, an exception is thrown. /// public static Dispatcher CurrentDispatcher { get { // Find the dispatcher for this thread. Dispatcher currentDispatcher = FromThread(Thread.CurrentThread);; // Auto-create the dispatcher if there is no dispatcher for // this thread (if we are allowed to). if(currentDispatcher == null) { currentDispatcher = new Dispatcher(); } return currentDispatcher; } } ///

/// Returns the Dispatcher for the specified thread. /// /// /// If there is no dispatcher available for the specified thread, /// this method will return null. /// public static Dispatcher FromThread(Thread thread) { lock(_globalLock) { Dispatcher dispatcher = null; if(thread != null) { // Shortcut: we track one static reference to the last current // dispatcher we gave out. For single-threaded apps, this will // be set all the time. For multi-threaded apps, this will be // set for periods of time during which accessing CurrentDispatcher // is cheap. When a thread switch happens, the next call to // CurrentDispatcher is expensive, but then the rest are fast // again. dispatcher = _possibleDispatcher.Target as Dispatcher; if(dispatcher == null || dispatcher.Thread != thread) { // The "possible" dispatcher either was null or belongs to // the a different thread. dispatcher = null; // Spin over the list of dispatchers looking for one that belongs // to this thread. We could use TLS here, but managed TLS is very // expensive, so we think it is cheaper to search our own data // structure. // // Note: Do not cache _dispatchers.Count because we rely on it // being updated if we encounter a dead weak reference. for(int i = 0; i < _dispatchers.Count; i++) { Dispatcher d = _dispatchers[i].Target as Dispatcher; if(d != null) { // Note: we compare the thread objects themselves to protect // against threads reusing old thread IDs. Thread dispatcherThread = d.Thread; if(dispatcherThread == thread) { dispatcher = d; // Do not exit the loop early since we are also // looking for dead references. } } else { // We found a dead reference, so remove it from // the list, and adjust the index so we account // for it. _dispatchers.RemoveAt(i); i--; } } // Stash this dispatcher as a "possible" dispatcher for the // next call to FromThread. if(dispatcher != null) { _possibleDispatcher.Target = dispatcher; } } } return dispatcher; } } /// /// public Thread Thread { get { return _dispatcherThread; } } /// /// Checks that the calling thread has access to this object. /// /// /// Only the dispatcher thread may access DispatcherObjects. ///

/// This method is public so that any thread can probe to /// see if it has access to the DispatcherObject. /// /// /// True if the calling thread has access to this object. /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public bool CheckAccess() { return Thread == Thread.CurrentThread; } ///

/// Verifies that the calling thread has access to this object. /// /// /// Only the dispatcher thread may access DispatcherObjects. ///

/// This method is public so that derived classes can probe to /// see if the calling thread has access to itself. /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void VerifyAccess() { if(!CheckAccess()) { throw new InvalidOperationException(SR.Get(SRID.VerifyAccess)); } } ///

/// Begins the process of shutting down the dispatcher. /// /// /// This API demand unrestricted UI Permission /// /// /// Critical - it calls critical methods (ShutdownCallback). /// PublicOK - it demands unrestricted UI permission. /// [SecurityCritical] public void BeginInvokeShutdown(DispatcherPriority priority) // NOTE: should be Priority { // We didn't want to enable quitting in the SEE SecurityHelper.DemandUnrestrictedUIPermission(); BeginInvoke(priority, new ShutdownCallback(ShutdownCallbackInternal)); } /// /// Begins the process of shutting down the dispatcher. /// /// /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical - it calls critical methods (ShutdownCallback). /// PublicOK - it demands unrestricted UI permission /// [SecurityCritical] public void InvokeShutdown() { // We didn't want to enable quitting in the SEE SecurityHelper.DemandUnrestrictedUIPermission(); CriticalInvokeShutdown(); } /// /// Critical - it calls critical methods (ShutdownCallback). /// [SecurityCritical] [FriendAccessAllowed] //used by Application.ShutdownImpl() in PresentationFramework internal void CriticalInvokeShutdown() { Invoke(DispatcherPriority.Send, new ShutdownCallback(ShutdownCallbackInternal)); // NOTE: should be Priority.Max } /// /// Whether or not the dispatcher is shutting down. /// public bool HasShutdownStarted { get { return _hasShutdownStarted; // Free-Thread access OK. } } /// /// Whether or not the dispatcher has been shut down. /// public bool HasShutdownFinished { get { return _hasShutdownFinished; // Free-Thread access OK. } } /// /// Raised when the dispatcher is shutting down. /// public event EventHandler ShutdownStarted; /// /// Raised when the dispatcher is shut down. /// public event EventHandler ShutdownFinished; /// /// Push the main execution frame. /// /// /// This frame will continue until the dispatcher is shut down. /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical: This code is blocked off more as defense in depth /// PublicOk: From a public perspective there is a link demand here /// [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] [SecurityCritical] public static void Run() { PushFrame(new DispatcherFrame()); } /// /// Push an execution frame. /// /// /// The frame for the dispatcher to process. /// /// /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical: This code is blocked off more as defense in depth /// PublicOk: From a public perspective there is a link demand here /// [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] [SecurityCritical] public static void PushFrame(DispatcherFrame frame) { if(frame == null) { throw new ArgumentNullException("frame"); } Dispatcher dispatcher = Dispatcher.CurrentDispatcher; if(dispatcher._hasShutdownFinished) // Dispatcher thread - no lock needed for read { throw new InvalidOperationException(SR.Get(SRID.DispatcherHasShutdown)); } if(frame.Dispatcher != dispatcher) { throw new InvalidOperationException(SR.Get(SRID.MismatchedDispatchers)); } if(dispatcher._disableProcessingCount > 0) { throw new InvalidOperationException(SR.Get(SRID.DispatcherProcessingDisabled)); } dispatcher.PushFrameImpl(frame); } /// /// Requests that all nested frames exit. /// /// /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical - calls a critical method - postThreadMessage. /// PublicOK - all we're doing is posting a current message to our thread. /// net effect is the dispatcher "wakes up" /// and uses the continue flag ( which may have just changed). /// [SecurityCritical] public static void ExitAllFrames() { // We didn't want to enable exiting all frames in the SEE SecurityHelper.DemandUnrestrictedUIPermission(); Dispatcher dispatcher = Dispatcher.CurrentDispatcher; if(dispatcher._frameDepth > 0) { dispatcher._exitAllFrames = true; // Post a message so that the message pump will wake up and // check our continue state. dispatcher.BeginInvoke(DispatcherPriority.Send, (DispatcherOperationCallback) delegate(object unused) {return null;}, null); } } /// /// Executes the specified delegate asynchronously on the thread that /// the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes no parameters. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method) // NOTE: should be Priority { return BeginInvokeImpl(priority, method, null, false /* isSingleParameter */); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// A object to pass as an argument to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg) // NOTE: should be Priority { return BeginInvokeImpl(priority, method, arg, true /* isSingleParameter */); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// enh /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg, params object[] args) // NOTE: should be Priority { return BeginInvokeImpl(priority, method, CombineParameters(arg, args), false /* isSingleParameter */); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// public DispatcherOperation BeginInvoke(Delegate method, params object[] args) { return BeginInvokeImpl(DispatcherPriority.Normal, method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// public DispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args) { return BeginInvokeImpl(priority, method, args, false /*isSingleParameter*/); } /// /// Critical: accesses _hooks /// TreatAsSafe: does not expose _hooks /// [SecurityCritical, SecurityTreatAsSafe] [FriendAccessAllowed] //used by DispatcherExtensionMethods in System.Windows.Presentation.dll internal DispatcherOperation BeginInvokeImpl(DispatcherPriority priority, Delegate method, object args, bool isSingleParameter) // NOTE: should be Priority { ValidatePriority(priority, "priority"); if(method == null) { throw new ArgumentNullException("method"); } DispatcherOperation operation = null; DispatcherHooks hooks = null; bool succeeded = false; // Could be a non-dispatcher thread, lock to read lock(_instanceLock) { if (!_hasShutdownFinished && !Environment.HasShutdownStarted) { operation = new DispatcherOperation(this, method, priority, args, isSingleParameter); // Add the operation to the work queue operation._item = _queue.Enqueue(priority, operation); // Make sure we will wake up to process this operation. succeeded = RequestProcessing(); if (succeeded) { hooks = _hooks; } else { // Dequeue and abort the item. We can safely return this to the user. _queue.RemoveItem(operation._item); operation._status = DispatcherOperationStatus.Aborted; } } else { // Rather than returning null we'll create an aborted operation and return it to the user operation = new DispatcherOperation(this, method, priority); } } if (operation != null && succeeded == true) { if(hooks != null) { hooks.RaiseOperationPosted(this, operation); } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERPOSTGUID), MS.Utility.EventType.Info, priority, operation.Name); } } return operation; } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes no parameters. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, Delegate method) // NOTE: should be Priority { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, null, false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An object to pass as an argument to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, Delegate method, object arg) // NOTE: should be Priority { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, arg, true /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, Delegate method, object arg, params object[] args) // NOTE: should be Priority { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, CombineParameters(arg, args), false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// A delegate to a method that takes no parameters. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method) // NOTE: should be Priority { return InvokeImpl(priority, timeout, method, null, false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An object to pass as an argument to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method, object arg) // NOTE: should be Priority { return InvokeImpl(priority, timeout, method, arg, true /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method, object arg, params object[] args) // NOTE: should be Priority { return InvokeImpl(priority, timeout, method, CombineParameters(arg, args), false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, params object[] args) { return InvokeImpl(DispatcherPriority.Normal, TimeSpan.FromMilliseconds(-1), method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, DispatcherPriority priority, params object[] args) { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, TimeSpan timeout, params object[] args) { return InvokeImpl(DispatcherPriority.Normal, timeout, method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, TimeSpan timeout, DispatcherPriority priority, params object[] args) { return InvokeImpl(priority, timeout, method, args, false /*isSingleParameter*/); } /// /// Critical:This code causes arbitrary delegate to execute. Also link demand in SetSynchronizationContext /// TreatAsSafe: Having a delegate execute is ok , it will break if it does anything that violate the trust boundaries /// [SecurityCritical,SecurityTreatAsSafe] [FriendAccessAllowed] //used by DispatcherExtensionMethods in System.Windows.Presentation.dll internal object InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, object args, bool isSingleParameter) // NOTE: should be Priority { ValidatePriority(priority, "priority"); if(priority == DispatcherPriority.Inactive) { throw new ArgumentException(SR.Get(SRID.InvalidPriority), "priority"); } if(method == null) { throw new ArgumentNullException("method"); } object result = null; if(priority == DispatcherPriority.Send && CheckAccess()) // NOTE: should be Priority.Max { // This is a special case for when the UI thread calls Invoke with // the maximum priority. In such cases, we do not go through the // queue, but instead we execute the delegate directly. This allows // the caller to know that nothing will execute before their callback. // Make sure we set this Dispatcher as the synchronization context. SynchronizationContext oldSynchronizationContext = SynchronizationContext.Current; try { SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(this)); result = WrappedInvoke(method, args, isSingleParameter); } finally { SynchronizationContext.SetSynchronizationContext(oldSynchronizationContext); } } else { DispatcherOperation op = BeginInvokeImpl(priority, method, args, isSingleParameter); if(op != null) { op.Wait(timeout); if(op.Status == DispatcherOperationStatus.Completed) { result = op.Result; } else if(op.Status == DispatcherOperationStatus.Aborted) { // Hm, someone aborted us. Maybe the dispatcher got // shut down on us? Just return null. result = null; } else { // We timed out, just abort the op so that it doesn't // invoke later. // // Note the race condition: if this is a foreign thread, // it is possible that the dispatcher thread could actually // dispatch the operation between the time our Wait() // call returns and we get here. In the case the operation // will actually be dispatched, but we will return failure. // // We recognize this but decide not to do anything about it, // as this is a common problem is multi-threaded programming. op.Abort(); } } } return result; } /// /// Disable the event processing of the dispatcher. /// /// /// This is an advanced method intended to elliminate the chance of /// unrelated reentrancy. The effect of disabling processing is: /// 1) CLR locks will not pump messages internally. /// 2) No one is allowed to push a frame. /// 3) No message processing is permitted. /// public DispatcherProcessingDisabled DisableProcessing() { VerifyAccess(); // Turn off processing. _disableProcessingCount++; DispatcherProcessingDisabled dpd = new DispatcherProcessingDisabled(); dpd._dispatcher = this; return dpd; } /* /// /// Reports the range of priorities that are considered /// as foreground priorities. /// /// /// A foreground priority is processed before input. /// public static PriorityRange ForegroundPriorityRange { get { return _foregroundPriorityRange; } } /// /// Reports the range of priorities that are considered /// as background priorities. /// /// /// A background priority is processed after input. /// public static PriorityRange BackgroundPriorityRange { get { return _backgroundPriorityRange; } } /// /// Reports the range of priorities that are considered /// as idle priorities. /// /// /// An idle priority is processed periodically after background /// priorities have been processed. /// public static PriorityRange IdlePriorityRange { get { return _idlePriorityRange; } } /// /// Represents a convenient foreground priority. /// /// /// A foreground priority is processed before input. In general /// you should define your own foreground priority to allow for /// more fine-grained ordering of queued items. /// public static Priority ForegroundPriority { get { return _foregroundPriority; } } /// /// Represents a convenient background priority. /// /// /// A background priority is processed after input. In general you /// should define your own background priority to allow for more /// fine-grained ordering of queued items. /// public static Priority BackgroundPriority { get { return _backgroundPriority; } } /// /// Represents a convenient idle priority. /// /// /// An idle priority is processed periodically after background /// priorities have been processed. In general you should define /// your own idle priority to allow for more fine-grained ordering /// of queued items. /// public static Priority IdlePriority { get { return _idlePriority; } } */ /// /// Validates that a priority is suitable for use by the dispatcher. /// /// /// The priority to validate. /// /// /// The name if the argument to report in the ArgumentException /// that is raised if the priority is not suitable for use by /// the dispatcher. /// public static void ValidatePriority(DispatcherPriority priority, string parameterName) // NOTE: should be Priority { // First make sure the Priority is valid. // Priority.ValidatePriority(priority, paramName); // Second, make sure the priority is in a range recognized by // the dispatcher. if(!_foregroundPriorityRange.Contains(priority) && !_backgroundPriorityRange.Contains(priority) && !_idlePriorityRange.Contains(priority) && DispatcherPriority.Inactive != priority) // NOTE: should be Priority.Min { // If we move to a Priority class, this exception will have to change too. throw new System.ComponentModel.InvalidEnumArgumentException(parameterName, (int)priority, typeof(DispatcherPriority)); } } /// /// Checks that the calling thread has access to this object. /// /// /// Only the dispatcher thread may access DispatcherObjects. ///

/// This method is public so that any thread can probe to /// see if it has access to the DispatcherObject. /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// True if the calling thread has access to this object. /// /// /// Critical: Accesses _hooks, which is critical. /// TreatAsSafe: link-demands /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] public DispatcherHooks Hooks { [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] get { DispatcherHooks hooks = null; lock(_instanceLock) { if(_hooks == null) { _hooks = new DispatcherHooks(); } hooks = _hooks; } return hooks; } } ///

/// Occurs when an untrapped thread exception is thrown. /// /// /// Raised during the filter stage for an exception raised during /// execution of a delegate via Invoke or BeginInvoke. ///

/// The callstack is not unwound at this time (first-chance exception). ///

/// Listeners to this event must be written with care to avoid /// creating secondary exceptions and to catch any that occur. /// It is recommended to avoid allocating memory or doing any /// heavylifting if possible. /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical: partially-trusted code is not allowed to access our exception filter. /// TreatAsSafe: link-demands /// public event DispatcherUnhandledExceptionFilterEventHandler UnhandledExceptionFilter { [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] add { _unhandledExceptionFilter += value; } [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] remove { _unhandledExceptionFilter -= value; } } ///

/// Occurs when an untrapped thread exception is thrown. /// /// /// Raised when an exception was caught that was raised during /// execution of a delegate via Invoke or BeginInvoke. ///

/// A handler can mark the exception as handled which will prevent /// the internal "final" exception handler from being called. ///

/// Listeners to this event must be written with care to avoid /// creating secondary exceptions and to catch any that occur. /// It is recommended to avoid allocating memory or doing any /// heavylifting if possible. /// public event DispatcherUnhandledExceptionEventHandler UnhandledException; ///

/// Reserved Dispatcher member /// internal object Reserved0 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved0; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved0 = value; } } /// /// Reserved Dispatcher member /// internal object Reserved1 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved1; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved1 = value; } } /// /// Reserved Dispatcher member /// internal object Reserved2 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved2; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved2 = value; } } /// /// Reserved Dispatcher member /// internal object Reserved3 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved3; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved3 = value; } } /// /// Reserved Dispatcher member for PtsCache /// internal object PtsCache { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reservedPtsCache; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reservedPtsCache = value; } } internal object InputMethod { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reservedInputMethod; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reservedInputMethod = value; } } /// /// Critical: Since it hands out the InputManager /// internal object InputManager { [FriendAccessAllowed] // Built into Base, used by Core or Framework. [SecurityCritical] get { return _reservedInputManager; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. [SecurityCritical] set { _reservedInputManager = value; } } /// /// Critical: Does an elevation via an unsafeNativeMethods call /// TreatAsSafe: stores critical data in SecurityCritical wrapper /// [SecurityCritical, SecurityTreatAsSafe] private Dispatcher() { _queue = new PriorityQueue(); _tlsDispatcher = this; // use TLS for ownership only _dispatcherThread = Thread.CurrentThread; // Add ourselves to the map of dispatchers to threads. lock(_globalLock) { _dispatchers.Add(new WeakReference(this)); } _unhandledExceptionEventArgs = new DispatcherUnhandledExceptionEventArgs(this); _exceptionFilterEventArgs = new DispatcherUnhandledExceptionFilterEventArgs(this); // Create the message-only window we use to receive messages // that tell us to process the queue. MessageOnlyHwndWrapper window = new MessageOnlyHwndWrapper(); _window = new SecurityCriticalData( window ); _hook = new HwndWrapperHook(WndProcHook); _window.Value.AddHook(_hook); } /// /// Critical - it calls critical methods (ShutdownImpl). it can initiate a shutdown process, disabled /// in partial trust. /// [SecurityCritical] private void StartShutdownImpl() { if(!_startingShutdown) { // We only need this to prevent reentrancy if the ShutdownStarted event // tries to shut down again. _startingShutdown = true; // Call the ShutdownStarted event before we actually mark ourselves // as shutting down. This is so the handlers can actaully do work // when they get this event without throwing exceptions. if(ShutdownStarted != null) { ShutdownStarted(this, EventArgs.Empty); } _hasShutdownStarted = true; // Because we may have to defer the actual shutting-down until // later, we need to remember the execution context we started // the shutdown from. // // Note that we demanded permissions when BeginInvokeShutdown // or InvokeShutdown were called. So if there were not enough // permissions, we would have thrown then. // ExecutionContext shutdownExecutionContext = ExecutionContext.Capture(); _shutdownExecutionContext = new SecurityCriticalDataClass(shutdownExecutionContext); // Tell Win32 to exit the message loop for this thread. // NOTE: I removed this code because of bug 1062099. // // UnsafeNativeMethods.PostQuitMessage(0); if(_frameDepth > 0) { // If there are any frames running, we have to wait for them // to unwind before we can safely destroy the dispatcher. } else { // The current thread is not spinning inside of the Dispatcher, // so we can go ahead and destroy it. ShutdownImpl(); } } } // // Critical - Calls ShutdownImplInSecurityContext with the execution context that was // active when the shutdown was initiated. // [SecurityCritical] private void ShutdownImpl() { if(!_hasShutdownFinished) // Dispatcher thread - no lock needed for read { if(_shutdownExecutionContext != null && _shutdownExecutionContext.Value != null) { // Continue using the execution context that was active when the shutdown // was initiated. ExecutionContext.Run(_shutdownExecutionContext.Value, new ContextCallback(ShutdownImplInSecurityContext), null); } else { // It is possible to be called from WM_DESTROY, in which case no one has begun // the shutdown process, so there is no execution context to use. ShutdownImplInSecurityContext(null); } _shutdownExecutionContext = null; } } // // Critical - as it accesses security critical data ( window handle) // [SecurityCritical] private void ShutdownImplInSecurityContext(Object state) { // Call the ShutdownFinished event before we actually mark ourselves // as shut down. This is so the handlers can actaully do work // when they get this event without throwing exceptions. if(ShutdownFinished != null) { ShutdownFinished(this, EventArgs.Empty); } // Destroy the message-only window we use to process Win32 messages // // Note: we need to do this BEFORE we actually mark the dispatcher // as shutdown. This is because the window will need the dispatcher // to execute the window proc. MessageOnlyHwndWrapper window = null; lock(_instanceLock) { window = _window.Value; _window = new SecurityCriticalData(null); } window.Dispose(); // Mark this dispatcher as shut down. Attempts to BeginInvoke // or Invoke will result in an exception. lock(_instanceLock) { _hasShutdownFinished = true; // Dispatcher thread - lock to write } // Now that the queue is off-line, abort all pending operations, // including inactive ones. DispatcherOperation operation = null; do { lock(_instanceLock) { if(_queue.MaxPriority != DispatcherPriority.Invalid) { operation = _queue.Peek(); } else { operation = null; } } if(operation != null) { operation.Abort(); } } while(operation != null); // clear out the fields that could be holding onto large graphs of objects. lock(_instanceLock) { // We should not need the queue any more. _queue = null; // We should not need the timers any more. _timers = null; // Clear out the reserved fields. _reserved0 = null; _reserved1 = null; _reserved2 = null; _reserved3 = null; // _reservedPtsCache = null; // PTS needs this in a finalizer... the PTS code should not assume access to this in their finalizer. _reservedInputMethod = null; _reservedInputManager = null; } // Note: the Dispatcher is still held in TLS. This maintains the 1-1 relationship // between the thread and the Dispatcher. However the dispatcher is basically // dead - it has been marked as _hasShutdownFinished, and most operations are // now illegal. } // Returns whether or not the priority was set. //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 /// /// Critical: accesses _hooks /// TreatAsSafe: does not expose _hooks /// [SecurityCritical, SecurityTreatAsSafe] internal bool SetPriority(DispatcherOperation operation, DispatcherPriority priority) // NOTE: should be Priority { bool notify = false; DispatcherHooks hooks = null; lock(_instanceLock) { if(_queue != null && operation._item.IsQueued) { _queue.ChangeItemPriority(operation._item, priority); notify = true; if(notify) { // Make sure we will wake up to process this operation. RequestProcessing(); hooks = _hooks; } } } if (notify) { if(hooks != null) { hooks.RaiseOperationPriorityChanged(this, operation); } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERPROMOTEGUID), MS.Utility.EventType.Info, priority, operation.Name); } } return notify; } // Returns whether or not the operation was removed. //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 /// /// Critical: accesses _hooks /// TreatAsSafe: does not expose _hooks /// [SecurityCritical, SecurityTreatAsSafe] internal bool Abort(DispatcherOperation operation) { bool notify = false; DispatcherHooks hooks = null; lock(_instanceLock) { if(_queue != null && operation._item.IsQueued) { _queue.RemoveItem(operation._item); operation._status = DispatcherOperationStatus.Aborted; notify = true; hooks = _hooks; } } if (notify) { if(hooks != null) { hooks.RaiseOperationAborted(this, operation); } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERABORTGUID), MS.Utility.EventType.Info, operation.Priority, operation.Name); } } return notify; } //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 /// /// Critical: This code can be used to process input and calls into DispatcherOperation.Invoke which /// is critical /// [SecurityCritical] private void ProcessQueue() { DispatcherPriority maxPriority = DispatcherPriority.Invalid; // NOTE: should be Priority.Invalid DispatcherOperation op = null; DispatcherHooks hooks = null; // // Dequeue the next operation if appropriate. lock(_instanceLock) { _postedProcessingType = PROCESS_NONE; // We can only do background processing if there is // no input in the Win32 queue. bool backgroundProcessingOK = !IsInputPending(); maxPriority = _queue.MaxPriority; if(maxPriority != DispatcherPriority.Invalid && // Nothing. NOTE: should be Priority.Invalid maxPriority != DispatcherPriority.Inactive) // Not processed. // NOTE: should be Priority.Min { if(_foregroundPriorityRange.Contains(maxPriority) || backgroundProcessingOK) { op = _queue.Dequeue(); hooks = _hooks; } } // Hm... we are grabbing this here... but it could change while we are invoking // the operation... maybe we should move this code to after the invoke? maxPriority = _queue.MaxPriority; // If there is more to do, request processing for it. RequestProcessing(); } if(op != null) { bool eventlogged = false; if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERDISPATCHGUID), MS.Utility.EventType.StartEvent, op.Priority, op.Name); eventlogged = true; } op.Invoke(); if(hooks != null) { hooks.RaiseOperationCompleted(this, op); } if (eventlogged) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERDISPATCHGUID), MS.Utility.EventType.EndEvent); if (_idlePriorityRange.Contains(maxPriority)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERIDLEGUID), MS.Utility.EventType.Info); } } } } internal delegate void ShutdownCallback(); /// /// Critical - it calls critical methods (StartShutdownImpl). it can initiate a shutdown process, disabled /// in partial trust. /// [SecurityCritical] private void ShutdownCallbackInternal() { StartShutdownImpl(); } // // Critical - as this calls critical methods (GetMessage, TranslateMessage, DispatchMessage). // TreatAsSafe - as the critical method is not leaked out, and not controlled by external inputs. // [SecurityCritical, SecurityTreatAsSafe ] private void PushFrameImpl(DispatcherFrame frame) { SynchronizationContext oldSyncContext = null; SynchronizationContext newSyncContext = null; MSG msg = new MSG(); _frameDepth++; try { // Change the CLR SynchronizationContext to be compatable with our Dispatcher. oldSyncContext = SynchronizationContext.Current; newSyncContext = new DispatcherSynchronizationContext(this); SynchronizationContext.SetSynchronizationContext(newSyncContext); try { while(frame.Continue) { if (!GetMessage(ref msg, IntPtr.Zero, 0, 0)) break; TranslateAndDispatchMessage(ref msg); } // If this was the last frame to exit after a quit, we // can now dispose the dispatcher. if(_frameDepth == 1) { if(_hasShutdownStarted) { ShutdownImpl(); } } } finally { // Restore the old SynchronizationContext. SynchronizationContext.SetSynchronizationContext(oldSyncContext); } } finally { _frameDepth--; if(_frameDepth == 0) { // We have exited all frames. _exitAllFrames = false; } } } // // SecurityCritical - as this does unsafe operations. // [SecurityCritical] private bool GetMessage(ref MSG msg, IntPtr hwnd, int minMessage, int maxMessage) { // If Any TextServices for Cicero is not installed GetMessagePump() returns null. // If TextServices are there, we can get ITfMessagePump and have to use it instead of // Win32 GetMessage(). bool result; UnsafeNativeMethods.ITfMessagePump messagePump = GetMessagePump(); try { if (messagePump == null) { // We have foreground items to process. // By posting a message, Win32 will service us fairly promptly. result = UnsafeNativeMethods.GetMessageW(ref msg, new HandleRef(this, hwnd), minMessage, maxMessage); } else { messagePump.GetMessageW( ref msg, (int)(IntPtr)hwnd, (int)minMessage, (int)maxMessage, out result); } } finally { if (messagePump != null) Marshal.ReleaseComObject(messagePump); } return result; } // Get ITfMessagePump interface from Cicero. /// /// Critical - calls critical code, created objects deal with raw input /// [SecurityCritical] private UnsafeNativeMethods.ITfMessagePump GetMessagePump() { UnsafeNativeMethods.ITfMessagePump messagePump = null; if (_isTSFMessagePumpEnabled) { // If the current thread is not STA, Cicero just does not work. // Probably this Dispatcher is running for worker thread. if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { // If there is no text services, we don't have to use ITfMessagePump. if (TextServicesLoader.ServicesInstalled) { UnsafeNativeMethods.ITfThreadMgr threadManager; threadManager = TextServicesLoader.Load(); // ThreadManager does not exist. No MessagePump yet. if (threadManager != null) { // QI ITfMessagePump. messagePump = threadManager as UnsafeNativeMethods.ITfMessagePump; } } } } return messagePump; } /// /// Enables/disables ITfMessagePump handshake with Text Services Framework. /// /// /// PresentationCore's TextServicesManager sets this property false when /// no WPF element has focus. This is important to ensure that native /// controls receive unfiltered input. /// [FriendAccessAllowed] // Used by TextServicesManager in PresentationCore. internal bool IsTSFMessagePumpEnabled { set { _isTSFMessagePumpEnabled = value; } } // // SecurityCritical - as this does unsafe operations. // [SecurityCritical] private void TranslateAndDispatchMessage(ref MSG msg) { bool handled = false; handled = ComponentDispatcher.RaiseThreadMessage(ref msg); if(!handled) { UnsafeNativeMethods.TranslateMessage(ref msg); UnsafeNativeMethods.DispatchMessage(ref msg); } } // // Critical - as it accesses security critical data ( window handle) // [SecurityCritical] private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if(_disableProcessingCount > 0) { throw new InvalidOperationException(SR.Get(SRID.DispatcherProcessingDisabledButStillPumping)); } if(msg == NativeMethods.WM_DESTROY) { if(!_hasShutdownStarted && !_hasShutdownFinished) // Dispatcher thread - no lock needed for read { // Aack! We are being torn down rudely! Try to // shut the dispatcher down as nicely as we can. ShutdownImpl(); } } else if(msg == _msgProcessQueue) { ProcessQueue(); } else if(msg == NativeMethods.WM_TIMER && (int) wParam == 1) { // We want 1-shot only timers. So stop the timer // that just fired. SafeNativeMethods.KillTimer(new HandleRef(this, hwnd), 1); ProcessQueue(); } else if(msg == NativeMethods.WM_TIMER && (int) wParam == 2) { // We want 1-shot only timers. So stop the timer // that just fired. KillWin32Timer(); PromoteTimers(Environment.TickCount); } // We are about to return to the OS. If there is nothing left // to do in the queue, then we will effectively go to sleep. // This is the condition that means Idle. DispatcherHooks hooks = null; bool idle = false; lock(_instanceLock) { idle = (_postedProcessingType < PROCESS_BACKGROUND); if (idle) { hooks = _hooks; } } if (idle) { if(hooks != null) { hooks.RaiseDispatcherInactive(this); } ComponentDispatcher.RaiseIdle(); } return IntPtr.Zero ; } /// /// SecurityCritical - as this code performs an elevation. /// TreatAsSafe - this method returns "I have input that can be processed". /// equivalent to saying a 'key has been hit'. /// Considered safe. /// [SecurityCritical, SecurityTreatAsSafe ] private bool IsInputPending() { int retVal = 0; // We need to know if there is any pending input in the Win32 // queue because we want to only process Avalon "background" // items after Win32 input has been processed. // // Win32 provides the GetQueueStatus API -- but it has a major // drawback: it only counts "new" input. This means that // sometimes it could return false, even if there really is input // that needs to be processed. This results in very hard to // find bugs. // // Luckily, Win32 also provides the MsgWaitForMultipleObjectsEx // API. While more awkward to use, this API can return queue // status information even if the input is "old". The various // flags we use are: // // QS_INPUT // This represents any pending input - such as mouse moves, or // key presses. It also includes the new GenericInput messages. // // QS_EVENT // This is actually a private flag that represents the various // events that can be queued in Win32. Some of these events // can cause input, but Win32 doesn't include them in the // QS_INPUT flag. An example is WM_MOUSELEAVE. // // QS_POSTMESSAGE // If there is already a message in the queue, we need to process // it before we can process input. // // MWMO_INPUTAVAILABLE // This flag indicates that any input (new or old) is to be // reported. // retVal = UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, null, 0, NativeMethods.QS_INPUT | NativeMethods.QS_EVENT | NativeMethods.QS_POSTMESSAGE, NativeMethods.MWMO_INPUTAVAILABLE); return retVal == 0; } private bool RequestProcessing() // NOTE: should be Priority { bool succeeded = true; // This method is called from within the instance lock. So we // can reliably check the _window field without worrying about // it being changed out from underneath us during shutdown. if (IsWindowNull()) return false; DispatcherPriority priority = _queue.MaxPriority; if(priority != DispatcherPriority.Invalid && // Nothing. NOTE: should be Priority.Invalid priority != DispatcherPriority.Inactive) // Not processed. NOTE: should be Priority.Min { if(_foregroundPriorityRange.Contains(priority)) { succeeded = RequestForegroundProcessing(); } else { succeeded = RequestBackgroundProcessing(); } } return succeeded; } /// /// Critical: This code accesses window /// TreatAsSafe: This code is ok to call since it does not expose the resource /// [SecurityCritical,SecurityTreatAsSafe] private bool IsWindowNull() { if(_window.Value == null) { return true; } return false; } // // Critical as it access critical data - for the window handle. // TreatAsSafe - as this is a request to do queued work. Analogous to VB's DoEvents() // [SecurityCritical, SecurityTreatAsSafe] private bool RequestForegroundProcessing() { if(_postedProcessingType < PROCESS_FOREGROUND) { // If we have already set a timer to do background processing, // make sure we stop it before posting a message for foreground // processing. if(_postedProcessingType == PROCESS_BACKGROUND) { SafeNativeMethods.KillTimer(new HandleRef(this, _window.Value.Handle), 1); } _postedProcessingType = PROCESS_FOREGROUND; // We have foreground items to process. // By posting a message, Win32 will service us fairly promptly. return UnsafeNativeMethods.TryPostMessage(new HandleRef(this, _window.Value.Handle), _msgProcessQueue, IntPtr.Zero, IntPtr.Zero); } return true; } // // Critical - as it accesses critical data - to get the Window Handle. // TreatAsSafe - as this method would be ok to expose publically, this is just a request for Timer processing. // [SecurityCritical, SecurityTreatAsSafe] private bool RequestBackgroundProcessing() { bool succeeded = true; if(_postedProcessingType < PROCESS_BACKGROUND) { // If there is Win32 input pending, we can't do any background // processing until it is done. We use a short timer to // get processing time after the input. if(IsInputPending()) { _postedProcessingType = PROCESS_BACKGROUND; succeeded = SafeNativeMethods.TrySetTimer(new HandleRef(this, _window.Value.Handle), 1, 1); } else { succeeded = RequestForegroundProcessing(); } } return succeeded; } private void PromoteTimers(int currentTimeInTicks) { try { List timers = null; long timersVersion = 0; lock(_instanceLock) { if(!_hasShutdownFinished) // Could be a non-dispatcher thread, lock to read { if(_dueTimeFound && _dueTimeInTicks - currentTimeInTicks <= 0) { timers = _timers; timersVersion = _timersVersion; } } } if(timers != null) { DispatcherTimer timer = null; int iTimer = 0; do { lock(_instanceLock) { timer = null; // If the timers collection changed while we are in the middle of // looking for timers, start over. if(timersVersion != _timersVersion) { timersVersion = _timersVersion; iTimer = 0; } while(iTimer < _timers.Count) { // WARNING: this is vulnerable to wrapping if(timers[iTimer]._dueTimeInTicks - currentTimeInTicks <= 0) { // Remove this timer from our list. // Do not increment the index. timer = timers[iTimer]; timers.RemoveAt(iTimer); break; } else { iTimer++; } } } // Now that we are outside of the lock, promote the timer. if(timer != null) { timer.Promote(); } } while(timer != null); } } finally { UpdateWin32Timer(); } } internal void AddTimer(DispatcherTimer timer) { lock(_instanceLock) { if(!_hasShutdownFinished) // Could be a non-dispatcher thread, lock to read { _timers.Add(timer); _timersVersion++; } } UpdateWin32Timer(); } internal void RemoveTimer(DispatcherTimer timer) { lock(_instanceLock) { if(!_hasShutdownFinished) // Could be a non-dispatcher thread, lock to read { _timers.Remove(timer); _timersVersion++; } } UpdateWin32Timer(); } internal void UpdateWin32Timer() // Called from DispatcherTimer { if(CheckAccess()) { UpdateWin32TimerFromDispatcherThread(null); } else { BeginInvoke(DispatcherPriority.Send, new DispatcherOperationCallback(UpdateWin32TimerFromDispatcherThread), null); } } private object UpdateWin32TimerFromDispatcherThread(object unused) { lock(_instanceLock) { if(!_hasShutdownFinished) // Dispatcher thread, does not technically need the lock to read { bool oldDueTimeFound = _dueTimeFound; int oldDueTimeInTicks = _dueTimeInTicks; _dueTimeFound = false; _dueTimeInTicks = 0; if(_timers.Count > 0) { // We could do better if we sorted the list of timers. for(int i = 0; i < _timers.Count; i++) { DispatcherTimer timer = _timers[i]; if(!_dueTimeFound || timer._dueTimeInTicks - _dueTimeInTicks < 0) { _dueTimeFound = true; _dueTimeInTicks = timer._dueTimeInTicks; } } } if(_dueTimeFound) { if(!_isWin32TimerSet || !oldDueTimeFound || (oldDueTimeInTicks != _dueTimeInTicks)) { SetWin32Timer(_dueTimeInTicks); } } else if(oldDueTimeFound) { KillWin32Timer(); } } } return null; } /// /// Critical - accesses critical data /// TreatAsSafe - we think it's ok to expose timers in the SEE. /// a denial-of-service attack may be possible - but these are low-pri and possible in many other ways. /// we can never bring down the iexplore process. /// [SecurityCritical, SecurityTreatAsSafe] private void SetWin32Timer(int dueTimeInTicks) { if(!IsWindowNull()) { int delta = dueTimeInTicks - Environment.TickCount; if(delta < 1) { delta = 1; } // We are being called on the dispatcher thread so we can rely on // _window.Value being non-null without taking the instance lock. SafeNativeMethods.SetTimer( new HandleRef(this, _window.Value.Handle), // this HWND 2, // win32 timer #2 delta); // unused timer proc _isWin32TimerSet = true; } } /// /// Critical - accesses critical data _window.Value.Handle /// TreatAsSafe - OK to stop a dispatcher timer. /// [SecurityCritical, SecurityTreatAsSafe] private void KillWin32Timer() { if(!IsWindowNull()) { // We are being called on the dispatcher thread so we can rely on // _window.Value being non-null without taking the instance lock. SafeNativeMethods.KillTimer( new HandleRef(this, _window.Value.Handle), // this HWND 2); // win32 timer #2 _isWin32TimerSet = false; } } // Exception filter returns true if exception should be caught. /// /// Critical: calls ExceptionFilter, which is critical /// [SecurityCritical] private static bool ExceptionFilterStatic(object source, Exception e) { Dispatcher d = (Dispatcher)source; return d.ExceptionFilter(e); } /// /// Critical: accesses _unhandledExceptionFilter /// [SecurityCritical] private bool ExceptionFilter(Exception e) { // see whether this dispatcher has already seen the exception. // This can happen when the dispatcher is re-entered via // PushFrame (or similar). if (!e.Data.Contains(ExceptionDataKey)) { // first time we've seen this exception - add data to the exception e.Data.Add(ExceptionDataKey, null); } else { // we've seen this exception before - don't catch it return false; } // By default, Request catch if there's anyone signed up to catch it; bool requestCatch = HasUnhandledExceptionHandler; // The app can hook up an ExceptionFilter to avoid catching it. // ExceptionFilter will run REGARDLESS of whether there are exception handlers. if (_unhandledExceptionFilter != null) { // The default requestCatch value that is passed in the args // should be returned unchanged if filters don't set them explicitly. _exceptionFilterEventArgs.Initialize(e, requestCatch); bool bSuccess = false; try { _unhandledExceptionFilter(this, _exceptionFilterEventArgs); bSuccess = true; } finally { if (bSuccess) { requestCatch = _exceptionFilterEventArgs.RequestCatch; } // For bSuccess is false, // To be in line with default behavior of structured exception handling, // we would want to set requestCatch to false, however, this means one // poorly programmed filter will knock out all dispatcher exception handling. // If an exception filter fails, we run with whatever value is set thus far. } } return requestCatch; } // This returns false when caller should rethrow the exception. // true means Exception is "handled" and things just continue on. private static bool CatchExceptionStatic(object source, Exception e) { Dispatcher dispatcher = (Dispatcher)source; return dispatcher.CatchException(e); } // The exception filter called for catching an unhandled exception. private bool CatchException(Exception e) { bool handled = false; if (UnhandledException != null) { _unhandledExceptionEventArgs.Initialize(e, false); bool bSuccess = false; try { UnhandledException(this, _unhandledExceptionEventArgs); handled = _unhandledExceptionEventArgs.Handled; bSuccess = true; } finally { if (!bSuccess) handled = false; } } return(handled); } // This is called by DRT (via reflection) to see if there is a UnhandledException handler. private bool HasUnhandledExceptionHandler { get { return (UnhandledException != null); } } internal object WrappedInvoke(Delegate callback, object args, bool isSingleParameter) { return WrappedInvoke(callback, args, isSingleParameter, null); } [FriendAccessAllowed] //used by ResourceReferenceExpression in PresentationFramework internal object WrappedInvoke(Delegate callback, object args, bool isSingleParameter, Delegate catchHandler) { // Win32 considers timers to be low priority. Avalon does not, since different timers // are associated with different priorities. So we promote the timers before we // dequeue any work items. PromoteTimers(Environment.TickCount); return _exceptionWrapper.TryCatchWhen(this, callback, args, isSingleParameter, catchHandler); } private object[] CombineParameters(object arg, object[] args) { object[] parameters = new object[1 + (args == null ? 1 : args.Length)]; parameters[0] = arg; if (args != null) { Array.Copy(args, 0, parameters, 1, args.Length); } else { parameters[1] = null; } return parameters; } private const int PROCESS_NONE = 0; private const int PROCESS_BACKGROUND = 1; private const int PROCESS_FOREGROUND = 2; private static List _dispatchers; private static WeakReference _possibleDispatcher; private static object _globalLock; [ThreadStatic] private static Dispatcher _tlsDispatcher; // use TLS for ownership only private Thread _dispatcherThread; private int _frameDepth; internal bool _exitAllFrames; // used from DispatcherFrame private bool _startingShutdown; internal bool _hasShutdownStarted; // used from DispatcherFrame private SecurityCriticalDataClass _shutdownExecutionContext; internal int _disableProcessingCount; // read by DispatcherSynchronizationContext, decremented by DispatcherProcessingDisabled //private static Priority _foregroundBackgroundBorderPriority = new Priority(Priority.Min, Priority.Max, "Dispatcher.ForegroundBackgroundBorder"); //private static Priority _backgroundIdleBorderPriority = new Priority(Priority.Min, _foregroundBackgroundBorderPriority, "Dispatcher.BackgroundIdleBorder"); //private static Priority _foregroundPriority = new Priority(_foregroundBackgroundBorderPriority, Priority.Max, "Dispatcher.Foreground"); //private static Priority _backgroundPriority = new Priority(_backgroundIdleBorderPriority, _foregroundBackgroundBorderPriority, "Dispatcher.Background"); //private static Priority _idlePriority = new Priority(Priority.Min, _backgroundIdleBorderPriority, "Dispatcher.Idle"); //private static PriorityRange _foregroundPriorityRange = new PriorityRange(_foregroundBackgroundBorderPriority, false, Priority.Max, true); //private static PriorityRange _backgroundPriorityRange = new PriorityRange(_backgroundIdleBorderPriority, false, _foregroundBackgroundBorderPriority, false); //private static PriorityRange _idlePriorityRange = new PriorityRange(Priority.Min, false, _backgroundIdleBorderPriority, false); private static PriorityRange _foregroundPriorityRange = new PriorityRange(DispatcherPriority.Loaded, true, DispatcherPriority.Send, true); private static PriorityRange _backgroundPriorityRange = new PriorityRange(DispatcherPriority.Background, true, DispatcherPriority.Input, true); private static PriorityRange _idlePriorityRange = new PriorityRange(DispatcherPriority.SystemIdle, true, DispatcherPriority.ContextIdle, true); private SecurityCriticalData _window; /// /// Critical: If disclosed, would allow untrusted parties to listen to raw messages. /// [SecurityCritical] private HwndWrapperHook _hook; private int _postedProcessingType; /// /// Critical: This code gets set by RegisterWindowMessage which is under an elevation. /// [SecurityCritical] private static int _msgProcessQueue; private static ExceptionWrapper _exceptionWrapper; private static readonly object ExceptionDataKey = new object(); // Preallocated arguments for exception handling. // This helps avoid allocations in the handler code, a potential // source of secondary exceptions (i.e. in Out-Of-Memory cases). private DispatcherUnhandledExceptionEventArgs _unhandledExceptionEventArgs; /// /// Do not expose to partially trusted code. /// [SecurityCritical] private DispatcherUnhandledExceptionFilterEventHandler _unhandledExceptionFilter; private DispatcherUnhandledExceptionFilterEventArgs _exceptionFilterEventArgs; private object _reserved0; private object _reserved1; private object _reserved2; private object _reserved3; private object _reservedPtsCache; private object _reservedInputMethod; private object _reservedInputManager; internal object _instanceLock = new object(); // Also used by DispatcherOperation private PriorityQueue _queue; private List _timers = new List(); private long _timersVersion; private bool _dueTimeFound; private int _dueTimeInTicks; private bool _isWin32TimerSet; // This can be read from any thread, but only written by the dispatcher thread. // Dispatcher Thread - lock _instanceLock only on write // Non-Dispatcher Threads - lock _instanceLock on read private bool _hasShutdownFinished; // Enables/disables ITfMessagePump handshake with Text Services Framework. private bool _isTSFMessagePumpEnabled; /// /// Do not expose hooks to partial trust. /// [SecurityCritical] private DispatcherHooks _hooks; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using System; // Console using System.Collections.Generic; // List using MS.Win32; // win32 interop using System.Windows.Interop; // ComponentDispatcher & MSG using Microsoft.Win32; // Registry using System.Security; // CAS using System.Security.Permissions; // Registry permissions using System.Diagnostics; // Debug using MS.Utility; // EventTrace using System.Reflection; // Assembly using System.Runtime.InteropServices; // SEHException using MS.Internal; // SecurityCriticalData, TextServicesInterop using MS.Internal.WindowsBase; // SecurityHelper using System.Threading; using System.ComponentModel; // EditorBrowsableAttribute, BrowsableAttribute // Disabling 1634 and 1691: // In order to avoid generating warnings about unknown message numbers and // unknown pragmas when compiling C# source code with the C# compiler, // you need to disable warnings 1634 and 1691. (Presharp Documentation) #pragma warning disable 1634, 1691 namespace System.Windows.Threading { /// /// Provides UI services for a thread. /// public sealed class Dispatcher { /// /// Critical: This code calls into RegisterWindowMesssage which is critical /// TreatAsSafe: This is safe to call as no external parameters are taken in /// [SecurityCritical,SecurityTreatAsSafe] static Dispatcher() { _msgProcessQueue = UnsafeNativeMethods.RegisterWindowMessage("DispatcherProcessQueue"); _globalLock = new object(); _dispatchers = new List(); _possibleDispatcher = new WeakReference(null); _exceptionWrapper = new ExceptionWrapper(); _exceptionWrapper.Catch += new ExceptionWrapper.CatchHandler(CatchExceptionStatic); _exceptionWrapper.Filter += new ExceptionWrapper.FilterHandler(ExceptionFilterStatic); } /// /// Returns the Dispatcher for the calling thread. /// /// /// If there is no dispatcher available for the current thread, /// and the thread allows a dispatcher to be auto-created, a new /// dispatcher will be created. ///

/// If there is no dispatcher for the current thread, and thread /// does not allow one to be auto-created, an exception is thrown. /// public static Dispatcher CurrentDispatcher { get { // Find the dispatcher for this thread. Dispatcher currentDispatcher = FromThread(Thread.CurrentThread);; // Auto-create the dispatcher if there is no dispatcher for // this thread (if we are allowed to). if(currentDispatcher == null) { currentDispatcher = new Dispatcher(); } return currentDispatcher; } } ///

/// Returns the Dispatcher for the specified thread. /// /// /// If there is no dispatcher available for the specified thread, /// this method will return null. /// public static Dispatcher FromThread(Thread thread) { lock(_globalLock) { Dispatcher dispatcher = null; if(thread != null) { // Shortcut: we track one static reference to the last current // dispatcher we gave out. For single-threaded apps, this will // be set all the time. For multi-threaded apps, this will be // set for periods of time during which accessing CurrentDispatcher // is cheap. When a thread switch happens, the next call to // CurrentDispatcher is expensive, but then the rest are fast // again. dispatcher = _possibleDispatcher.Target as Dispatcher; if(dispatcher == null || dispatcher.Thread != thread) { // The "possible" dispatcher either was null or belongs to // the a different thread. dispatcher = null; // Spin over the list of dispatchers looking for one that belongs // to this thread. We could use TLS here, but managed TLS is very // expensive, so we think it is cheaper to search our own data // structure. // // Note: Do not cache _dispatchers.Count because we rely on it // being updated if we encounter a dead weak reference. for(int i = 0; i < _dispatchers.Count; i++) { Dispatcher d = _dispatchers[i].Target as Dispatcher; if(d != null) { // Note: we compare the thread objects themselves to protect // against threads reusing old thread IDs. Thread dispatcherThread = d.Thread; if(dispatcherThread == thread) { dispatcher = d; // Do not exit the loop early since we are also // looking for dead references. } } else { // We found a dead reference, so remove it from // the list, and adjust the index so we account // for it. _dispatchers.RemoveAt(i); i--; } } // Stash this dispatcher as a "possible" dispatcher for the // next call to FromThread. if(dispatcher != null) { _possibleDispatcher.Target = dispatcher; } } } return dispatcher; } } /// /// public Thread Thread { get { return _dispatcherThread; } } /// /// Checks that the calling thread has access to this object. /// /// /// Only the dispatcher thread may access DispatcherObjects. ///

/// This method is public so that any thread can probe to /// see if it has access to the DispatcherObject. /// /// /// True if the calling thread has access to this object. /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public bool CheckAccess() { return Thread == Thread.CurrentThread; } ///

/// Verifies that the calling thread has access to this object. /// /// /// Only the dispatcher thread may access DispatcherObjects. ///

/// This method is public so that derived classes can probe to /// see if the calling thread has access to itself. /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void VerifyAccess() { if(!CheckAccess()) { throw new InvalidOperationException(SR.Get(SRID.VerifyAccess)); } } ///

/// Begins the process of shutting down the dispatcher. /// /// /// This API demand unrestricted UI Permission /// /// /// Critical - it calls critical methods (ShutdownCallback). /// PublicOK - it demands unrestricted UI permission. /// [SecurityCritical] public void BeginInvokeShutdown(DispatcherPriority priority) // NOTE: should be Priority { // We didn't want to enable quitting in the SEE SecurityHelper.DemandUnrestrictedUIPermission(); BeginInvoke(priority, new ShutdownCallback(ShutdownCallbackInternal)); } /// /// Begins the process of shutting down the dispatcher. /// /// /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical - it calls critical methods (ShutdownCallback). /// PublicOK - it demands unrestricted UI permission /// [SecurityCritical] public void InvokeShutdown() { // We didn't want to enable quitting in the SEE SecurityHelper.DemandUnrestrictedUIPermission(); CriticalInvokeShutdown(); } /// /// Critical - it calls critical methods (ShutdownCallback). /// [SecurityCritical] [FriendAccessAllowed] //used by Application.ShutdownImpl() in PresentationFramework internal void CriticalInvokeShutdown() { Invoke(DispatcherPriority.Send, new ShutdownCallback(ShutdownCallbackInternal)); // NOTE: should be Priority.Max } /// /// Whether or not the dispatcher is shutting down. /// public bool HasShutdownStarted { get { return _hasShutdownStarted; // Free-Thread access OK. } } /// /// Whether or not the dispatcher has been shut down. /// public bool HasShutdownFinished { get { return _hasShutdownFinished; // Free-Thread access OK. } } /// /// Raised when the dispatcher is shutting down. /// public event EventHandler ShutdownStarted; /// /// Raised when the dispatcher is shut down. /// public event EventHandler ShutdownFinished; /// /// Push the main execution frame. /// /// /// This frame will continue until the dispatcher is shut down. /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical: This code is blocked off more as defense in depth /// PublicOk: From a public perspective there is a link demand here /// [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] [SecurityCritical] public static void Run() { PushFrame(new DispatcherFrame()); } /// /// Push an execution frame. /// /// /// The frame for the dispatcher to process. /// /// /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical: This code is blocked off more as defense in depth /// PublicOk: From a public perspective there is a link demand here /// [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] [SecurityCritical] public static void PushFrame(DispatcherFrame frame) { if(frame == null) { throw new ArgumentNullException("frame"); } Dispatcher dispatcher = Dispatcher.CurrentDispatcher; if(dispatcher._hasShutdownFinished) // Dispatcher thread - no lock needed for read { throw new InvalidOperationException(SR.Get(SRID.DispatcherHasShutdown)); } if(frame.Dispatcher != dispatcher) { throw new InvalidOperationException(SR.Get(SRID.MismatchedDispatchers)); } if(dispatcher._disableProcessingCount > 0) { throw new InvalidOperationException(SR.Get(SRID.DispatcherProcessingDisabled)); } dispatcher.PushFrameImpl(frame); } /// /// Requests that all nested frames exit. /// /// /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical - calls a critical method - postThreadMessage. /// PublicOK - all we're doing is posting a current message to our thread. /// net effect is the dispatcher "wakes up" /// and uses the continue flag ( which may have just changed). /// [SecurityCritical] public static void ExitAllFrames() { // We didn't want to enable exiting all frames in the SEE SecurityHelper.DemandUnrestrictedUIPermission(); Dispatcher dispatcher = Dispatcher.CurrentDispatcher; if(dispatcher._frameDepth > 0) { dispatcher._exitAllFrames = true; // Post a message so that the message pump will wake up and // check our continue state. dispatcher.BeginInvoke(DispatcherPriority.Send, (DispatcherOperationCallback) delegate(object unused) {return null;}, null); } } /// /// Executes the specified delegate asynchronously on the thread that /// the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes no parameters. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method) // NOTE: should be Priority { return BeginInvokeImpl(priority, method, null, false /* isSingleParameter */); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// A object to pass as an argument to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg) // NOTE: should be Priority { return BeginInvokeImpl(priority, method, arg, true /* isSingleParameter */); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// enh /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg, params object[] args) // NOTE: should be Priority { return BeginInvokeImpl(priority, method, CombineParameters(arg, args), false /* isSingleParameter */); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// public DispatcherOperation BeginInvoke(Delegate method, params object[] args) { return BeginInvokeImpl(DispatcherPriority.Normal, method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate asynchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// An IAsyncResult object that represents the result of the /// BeginInvoke operation. /// public DispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args) { return BeginInvokeImpl(priority, method, args, false /*isSingleParameter*/); } /// /// Critical: accesses _hooks /// TreatAsSafe: does not expose _hooks /// [SecurityCritical, SecurityTreatAsSafe] [FriendAccessAllowed] //used by DispatcherExtensionMethods in System.Windows.Presentation.dll internal DispatcherOperation BeginInvokeImpl(DispatcherPriority priority, Delegate method, object args, bool isSingleParameter) // NOTE: should be Priority { ValidatePriority(priority, "priority"); if(method == null) { throw new ArgumentNullException("method"); } DispatcherOperation operation = null; DispatcherHooks hooks = null; bool succeeded = false; // Could be a non-dispatcher thread, lock to read lock(_instanceLock) { if (!_hasShutdownFinished && !Environment.HasShutdownStarted) { operation = new DispatcherOperation(this, method, priority, args, isSingleParameter); // Add the operation to the work queue operation._item = _queue.Enqueue(priority, operation); // Make sure we will wake up to process this operation. succeeded = RequestProcessing(); if (succeeded) { hooks = _hooks; } else { // Dequeue and abort the item. We can safely return this to the user. _queue.RemoveItem(operation._item); operation._status = DispatcherOperationStatus.Aborted; } } else { // Rather than returning null we'll create an aborted operation and return it to the user operation = new DispatcherOperation(this, method, priority); } } if (operation != null && succeeded == true) { if(hooks != null) { hooks.RaiseOperationPosted(this, operation); } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERPOSTGUID), MS.Utility.EventType.Info, priority, operation.Name); } } return operation; } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes no parameters. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, Delegate method) // NOTE: should be Priority { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, null, false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An object to pass as an argument to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, Delegate method, object arg) // NOTE: should be Priority { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, arg, true /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, Delegate method, object arg, params object[] args) // NOTE: should be Priority { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, CombineParameters(arg, args), false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// A delegate to a method that takes no parameters. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method) // NOTE: should be Priority { return InvokeImpl(priority, timeout, method, null, false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An object to pass as an argument to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method, object arg) // NOTE: should be Priority { return InvokeImpl(priority, timeout, method, arg, true /* isSingleParameter */); } /// /// Executes the specified delegate synchronously with the specified /// arguments, on the thread that the Dispatcher was created on. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public object Invoke(DispatcherPriority priority, TimeSpan timeout, Delegate method, object arg, params object[] args) // NOTE: should be Priority { return InvokeImpl(priority, timeout, method, CombineParameters(arg, args), false /* isSingleParameter */); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, params object[] args) { return InvokeImpl(DispatcherPriority.Normal, TimeSpan.FromMilliseconds(-1), method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, DispatcherPriority priority, params object[] args) { return InvokeImpl(priority, TimeSpan.FromMilliseconds(-1), method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, TimeSpan timeout, params object[] args) { return InvokeImpl(DispatcherPriority.Normal, timeout, method, args, false /*isSingleParameter*/); } /// /// Executes the specified delegate synchronously on the thread that /// the Dispatcher was created on. /// /// /// A delegate to a method that takes parameters of the same number /// and type that are contained in the args parameter. /// /// /// The maximum amount of time to wait for the operation to complete. /// /// /// The priority that determines in what order the specified method /// is invoked relative to the other pending methods in the Dispatcher. /// /// /// An array of objects to pass as arguments to the given method. /// This can be null if no arguments are needed. /// /// /// The return value from the delegate being invoked, or null if /// the delegate has no return value. /// public object Invoke(Delegate method, TimeSpan timeout, DispatcherPriority priority, params object[] args) { return InvokeImpl(priority, timeout, method, args, false /*isSingleParameter*/); } /// /// Critical:This code causes arbitrary delegate to execute. Also link demand in SetSynchronizationContext /// TreatAsSafe: Having a delegate execute is ok , it will break if it does anything that violate the trust boundaries /// [SecurityCritical,SecurityTreatAsSafe] [FriendAccessAllowed] //used by DispatcherExtensionMethods in System.Windows.Presentation.dll internal object InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, object args, bool isSingleParameter) // NOTE: should be Priority { ValidatePriority(priority, "priority"); if(priority == DispatcherPriority.Inactive) { throw new ArgumentException(SR.Get(SRID.InvalidPriority), "priority"); } if(method == null) { throw new ArgumentNullException("method"); } object result = null; if(priority == DispatcherPriority.Send && CheckAccess()) // NOTE: should be Priority.Max { // This is a special case for when the UI thread calls Invoke with // the maximum priority. In such cases, we do not go through the // queue, but instead we execute the delegate directly. This allows // the caller to know that nothing will execute before their callback. // Make sure we set this Dispatcher as the synchronization context. SynchronizationContext oldSynchronizationContext = SynchronizationContext.Current; try { SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(this)); result = WrappedInvoke(method, args, isSingleParameter); } finally { SynchronizationContext.SetSynchronizationContext(oldSynchronizationContext); } } else { DispatcherOperation op = BeginInvokeImpl(priority, method, args, isSingleParameter); if(op != null) { op.Wait(timeout); if(op.Status == DispatcherOperationStatus.Completed) { result = op.Result; } else if(op.Status == DispatcherOperationStatus.Aborted) { // Hm, someone aborted us. Maybe the dispatcher got // shut down on us? Just return null. result = null; } else { // We timed out, just abort the op so that it doesn't // invoke later. // // Note the race condition: if this is a foreign thread, // it is possible that the dispatcher thread could actually // dispatch the operation between the time our Wait() // call returns and we get here. In the case the operation // will actually be dispatched, but we will return failure. // // We recognize this but decide not to do anything about it, // as this is a common problem is multi-threaded programming. op.Abort(); } } } return result; } /// /// Disable the event processing of the dispatcher. /// /// /// This is an advanced method intended to elliminate the chance of /// unrelated reentrancy. The effect of disabling processing is: /// 1) CLR locks will not pump messages internally. /// 2) No one is allowed to push a frame. /// 3) No message processing is permitted. /// public DispatcherProcessingDisabled DisableProcessing() { VerifyAccess(); // Turn off processing. _disableProcessingCount++; DispatcherProcessingDisabled dpd = new DispatcherProcessingDisabled(); dpd._dispatcher = this; return dpd; } /* /// /// Reports the range of priorities that are considered /// as foreground priorities. /// /// /// A foreground priority is processed before input. /// public static PriorityRange ForegroundPriorityRange { get { return _foregroundPriorityRange; } } /// /// Reports the range of priorities that are considered /// as background priorities. /// /// /// A background priority is processed after input. /// public static PriorityRange BackgroundPriorityRange { get { return _backgroundPriorityRange; } } /// /// Reports the range of priorities that are considered /// as idle priorities. /// /// /// An idle priority is processed periodically after background /// priorities have been processed. /// public static PriorityRange IdlePriorityRange { get { return _idlePriorityRange; } } /// /// Represents a convenient foreground priority. /// /// /// A foreground priority is processed before input. In general /// you should define your own foreground priority to allow for /// more fine-grained ordering of queued items. /// public static Priority ForegroundPriority { get { return _foregroundPriority; } } /// /// Represents a convenient background priority. /// /// /// A background priority is processed after input. In general you /// should define your own background priority to allow for more /// fine-grained ordering of queued items. /// public static Priority BackgroundPriority { get { return _backgroundPriority; } } /// /// Represents a convenient idle priority. /// /// /// An idle priority is processed periodically after background /// priorities have been processed. In general you should define /// your own idle priority to allow for more fine-grained ordering /// of queued items. /// public static Priority IdlePriority { get { return _idlePriority; } } */ /// /// Validates that a priority is suitable for use by the dispatcher. /// /// /// The priority to validate. /// /// /// The name if the argument to report in the ArgumentException /// that is raised if the priority is not suitable for use by /// the dispatcher. /// public static void ValidatePriority(DispatcherPriority priority, string parameterName) // NOTE: should be Priority { // First make sure the Priority is valid. // Priority.ValidatePriority(priority, paramName); // Second, make sure the priority is in a range recognized by // the dispatcher. if(!_foregroundPriorityRange.Contains(priority) && !_backgroundPriorityRange.Contains(priority) && !_idlePriorityRange.Contains(priority) && DispatcherPriority.Inactive != priority) // NOTE: should be Priority.Min { // If we move to a Priority class, this exception will have to change too. throw new System.ComponentModel.InvalidEnumArgumentException(parameterName, (int)priority, typeof(DispatcherPriority)); } } /// /// Checks that the calling thread has access to this object. /// /// /// Only the dispatcher thread may access DispatcherObjects. ///

/// This method is public so that any thread can probe to /// see if it has access to the DispatcherObject. /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// True if the calling thread has access to this object. /// /// /// Critical: Accesses _hooks, which is critical. /// TreatAsSafe: link-demands /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] public DispatcherHooks Hooks { [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] get { DispatcherHooks hooks = null; lock(_instanceLock) { if(_hooks == null) { _hooks = new DispatcherHooks(); } hooks = _hooks; } return hooks; } } ///

/// Occurs when an untrapped thread exception is thrown. /// /// /// Raised during the filter stage for an exception raised during /// execution of a delegate via Invoke or BeginInvoke. ///

/// The callstack is not unwound at this time (first-chance exception). ///

/// Listeners to this event must be written with care to avoid /// creating secondary exceptions and to catch any that occur. /// It is recommended to avoid allocating memory or doing any /// heavylifting if possible. /// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// /// /// Critical: partially-trusted code is not allowed to access our exception filter. /// TreatAsSafe: link-demands /// public event DispatcherUnhandledExceptionFilterEventHandler UnhandledExceptionFilter { [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] add { _unhandledExceptionFilter += value; } [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] remove { _unhandledExceptionFilter -= value; } } ///

/// Occurs when an untrapped thread exception is thrown. /// /// /// Raised when an exception was caught that was raised during /// execution of a delegate via Invoke or BeginInvoke. ///

/// A handler can mark the exception as handled which will prevent /// the internal "final" exception handler from being called. ///

/// Listeners to this event must be written with care to avoid /// creating secondary exceptions and to catch any that occur. /// It is recommended to avoid allocating memory or doing any /// heavylifting if possible. /// public event DispatcherUnhandledExceptionEventHandler UnhandledException; ///

/// Reserved Dispatcher member /// internal object Reserved0 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved0; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved0 = value; } } /// /// Reserved Dispatcher member /// internal object Reserved1 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved1; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved1 = value; } } /// /// Reserved Dispatcher member /// internal object Reserved2 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved2; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved2 = value; } } /// /// Reserved Dispatcher member /// internal object Reserved3 { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reserved3; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reserved3 = value; } } /// /// Reserved Dispatcher member for PtsCache /// internal object PtsCache { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reservedPtsCache; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reservedPtsCache = value; } } internal object InputMethod { [FriendAccessAllowed] // Built into Base, used by Core or Framework. get { return _reservedInputMethod; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. set { _reservedInputMethod = value; } } /// /// Critical: Since it hands out the InputManager /// internal object InputManager { [FriendAccessAllowed] // Built into Base, used by Core or Framework. [SecurityCritical] get { return _reservedInputManager; } [FriendAccessAllowed] // Built into Base, used by Core or Framework. [SecurityCritical] set { _reservedInputManager = value; } } /// /// Critical: Does an elevation via an unsafeNativeMethods call /// TreatAsSafe: stores critical data in SecurityCritical wrapper /// [SecurityCritical, SecurityTreatAsSafe] private Dispatcher() { _queue = new PriorityQueue(); _tlsDispatcher = this; // use TLS for ownership only _dispatcherThread = Thread.CurrentThread; // Add ourselves to the map of dispatchers to threads. lock(_globalLock) { _dispatchers.Add(new WeakReference(this)); } _unhandledExceptionEventArgs = new DispatcherUnhandledExceptionEventArgs(this); _exceptionFilterEventArgs = new DispatcherUnhandledExceptionFilterEventArgs(this); // Create the message-only window we use to receive messages // that tell us to process the queue. MessageOnlyHwndWrapper window = new MessageOnlyHwndWrapper(); _window = new SecurityCriticalData( window ); _hook = new HwndWrapperHook(WndProcHook); _window.Value.AddHook(_hook); } /// /// Critical - it calls critical methods (ShutdownImpl). it can initiate a shutdown process, disabled /// in partial trust. /// [SecurityCritical] private void StartShutdownImpl() { if(!_startingShutdown) { // We only need this to prevent reentrancy if the ShutdownStarted event // tries to shut down again. _startingShutdown = true; // Call the ShutdownStarted event before we actually mark ourselves // as shutting down. This is so the handlers can actaully do work // when they get this event without throwing exceptions. if(ShutdownStarted != null) { ShutdownStarted(this, EventArgs.Empty); } _hasShutdownStarted = true; // Because we may have to defer the actual shutting-down until // later, we need to remember the execution context we started // the shutdown from. // // Note that we demanded permissions when BeginInvokeShutdown // or InvokeShutdown were called. So if there were not enough // permissions, we would have thrown then. // ExecutionContext shutdownExecutionContext = ExecutionContext.Capture(); _shutdownExecutionContext = new SecurityCriticalDataClass(shutdownExecutionContext); // Tell Win32 to exit the message loop for this thread. // NOTE: I removed this code because of bug 1062099. // // UnsafeNativeMethods.PostQuitMessage(0); if(_frameDepth > 0) { // If there are any frames running, we have to wait for them // to unwind before we can safely destroy the dispatcher. } else { // The current thread is not spinning inside of the Dispatcher, // so we can go ahead and destroy it. ShutdownImpl(); } } } // // Critical - Calls ShutdownImplInSecurityContext with the execution context that was // active when the shutdown was initiated. // [SecurityCritical] private void ShutdownImpl() { if(!_hasShutdownFinished) // Dispatcher thread - no lock needed for read { if(_shutdownExecutionContext != null && _shutdownExecutionContext.Value != null) { // Continue using the execution context that was active when the shutdown // was initiated. ExecutionContext.Run(_shutdownExecutionContext.Value, new ContextCallback(ShutdownImplInSecurityContext), null); } else { // It is possible to be called from WM_DESTROY, in which case no one has begun // the shutdown process, so there is no execution context to use. ShutdownImplInSecurityContext(null); } _shutdownExecutionContext = null; } } // // Critical - as it accesses security critical data ( window handle) // [SecurityCritical] private void ShutdownImplInSecurityContext(Object state) { // Call the ShutdownFinished event before we actually mark ourselves // as shut down. This is so the handlers can actaully do work // when they get this event without throwing exceptions. if(ShutdownFinished != null) { ShutdownFinished(this, EventArgs.Empty); } // Destroy the message-only window we use to process Win32 messages // // Note: we need to do this BEFORE we actually mark the dispatcher // as shutdown. This is because the window will need the dispatcher // to execute the window proc. MessageOnlyHwndWrapper window = null; lock(_instanceLock) { window = _window.Value; _window = new SecurityCriticalData(null); } window.Dispose(); // Mark this dispatcher as shut down. Attempts to BeginInvoke // or Invoke will result in an exception. lock(_instanceLock) { _hasShutdownFinished = true; // Dispatcher thread - lock to write } // Now that the queue is off-line, abort all pending operations, // including inactive ones. DispatcherOperation operation = null; do { lock(_instanceLock) { if(_queue.MaxPriority != DispatcherPriority.Invalid) { operation = _queue.Peek(); } else { operation = null; } } if(operation != null) { operation.Abort(); } } while(operation != null); // clear out the fields that could be holding onto large graphs of objects. lock(_instanceLock) { // We should not need the queue any more. _queue = null; // We should not need the timers any more. _timers = null; // Clear out the reserved fields. _reserved0 = null; _reserved1 = null; _reserved2 = null; _reserved3 = null; // _reservedPtsCache = null; // PTS needs this in a finalizer... the PTS code should not assume access to this in their finalizer. _reservedInputMethod = null; _reservedInputManager = null; } // Note: the Dispatcher is still held in TLS. This maintains the 1-1 relationship // between the thread and the Dispatcher. However the dispatcher is basically // dead - it has been marked as _hasShutdownFinished, and most operations are // now illegal. } // Returns whether or not the priority was set. //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 /// /// Critical: accesses _hooks /// TreatAsSafe: does not expose _hooks /// [SecurityCritical, SecurityTreatAsSafe] internal bool SetPriority(DispatcherOperation operation, DispatcherPriority priority) // NOTE: should be Priority { bool notify = false; DispatcherHooks hooks = null; lock(_instanceLock) { if(_queue != null && operation._item.IsQueued) { _queue.ChangeItemPriority(operation._item, priority); notify = true; if(notify) { // Make sure we will wake up to process this operation. RequestProcessing(); hooks = _hooks; } } } if (notify) { if(hooks != null) { hooks.RaiseOperationPriorityChanged(this, operation); } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERPROMOTEGUID), MS.Utility.EventType.Info, priority, operation.Name); } } return notify; } // Returns whether or not the operation was removed. //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 /// /// Critical: accesses _hooks /// TreatAsSafe: does not expose _hooks /// [SecurityCritical, SecurityTreatAsSafe] internal bool Abort(DispatcherOperation operation) { bool notify = false; DispatcherHooks hooks = null; lock(_instanceLock) { if(_queue != null && operation._item.IsQueued) { _queue.RemoveItem(operation._item); operation._status = DispatcherOperationStatus.Aborted; notify = true; hooks = _hooks; } } if (notify) { if(hooks != null) { hooks.RaiseOperationAborted(this, operation); } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERABORTGUID), MS.Utility.EventType.Info, operation.Priority, operation.Name); } } return notify; } //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 /// /// Critical: This code can be used to process input and calls into DispatcherOperation.Invoke which /// is critical /// [SecurityCritical] private void ProcessQueue() { DispatcherPriority maxPriority = DispatcherPriority.Invalid; // NOTE: should be Priority.Invalid DispatcherOperation op = null; DispatcherHooks hooks = null; // // Dequeue the next operation if appropriate. lock(_instanceLock) { _postedProcessingType = PROCESS_NONE; // We can only do background processing if there is // no input in the Win32 queue. bool backgroundProcessingOK = !IsInputPending(); maxPriority = _queue.MaxPriority; if(maxPriority != DispatcherPriority.Invalid && // Nothing. NOTE: should be Priority.Invalid maxPriority != DispatcherPriority.Inactive) // Not processed. // NOTE: should be Priority.Min { if(_foregroundPriorityRange.Contains(maxPriority) || backgroundProcessingOK) { op = _queue.Dequeue(); hooks = _hooks; } } // Hm... we are grabbing this here... but it could change while we are invoking // the operation... maybe we should move this code to after the invoke? maxPriority = _queue.MaxPriority; // If there is more to do, request processing for it. RequestProcessing(); } if(op != null) { bool eventlogged = false; if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERDISPATCHGUID), MS.Utility.EventType.StartEvent, op.Priority, op.Name); eventlogged = true; } op.Invoke(); if(hooks != null) { hooks.RaiseOperationCompleted(this, op); } if (eventlogged) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERDISPATCHGUID), MS.Utility.EventType.EndEvent); if (_idlePriorityRange.Contains(maxPriority)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DISPATCHERIDLEGUID), MS.Utility.EventType.Info); } } } } internal delegate void ShutdownCallback(); /// /// Critical - it calls critical methods (StartShutdownImpl). it can initiate a shutdown process, disabled /// in partial trust. /// [SecurityCritical] private void ShutdownCallbackInternal() { StartShutdownImpl(); } // // Critical - as this calls critical methods (GetMessage, TranslateMessage, DispatchMessage). // TreatAsSafe - as the critical method is not leaked out, and not controlled by external inputs. // [SecurityCritical, SecurityTreatAsSafe ] private void PushFrameImpl(DispatcherFrame frame) { SynchronizationContext oldSyncContext = null; SynchronizationContext newSyncContext = null; MSG msg = new MSG(); _frameDepth++; try { // Change the CLR SynchronizationContext to be compatable with our Dispatcher. oldSyncContext = SynchronizationContext.Current; newSyncContext = new DispatcherSynchronizationContext(this); SynchronizationContext.SetSynchronizationContext(newSyncContext); try { while(frame.Continue) { if (!GetMessage(ref msg, IntPtr.Zero, 0, 0)) break; TranslateAndDispatchMessage(ref msg); } // If this was the last frame to exit after a quit, we // can now dispose the dispatcher. if(_frameDepth == 1) { if(_hasShutdownStarted) { ShutdownImpl(); } } } finally { // Restore the old SynchronizationContext. SynchronizationContext.SetSynchronizationContext(oldSyncContext); } } finally { _frameDepth--; if(_frameDepth == 0) { // We have exited all frames. _exitAllFrames = false; } } } // // SecurityCritical - as this does unsafe operations. // [SecurityCritical] private bool GetMessage(ref MSG msg, IntPtr hwnd, int minMessage, int maxMessage) { // If Any TextServices for Cicero is not installed GetMessagePump() returns null. // If TextServices are there, we can get ITfMessagePump and have to use it instead of // Win32 GetMessage(). bool result; UnsafeNativeMethods.ITfMessagePump messagePump = GetMessagePump(); try { if (messagePump == null) { // We have foreground items to process. // By posting a message, Win32 will service us fairly promptly. result = UnsafeNativeMethods.GetMessageW(ref msg, new HandleRef(this, hwnd), minMessage, maxMessage); } else { messagePump.GetMessageW( ref msg, (int)(IntPtr)hwnd, (int)minMessage, (int)maxMessage, out result); } } finally { if (messagePump != null) Marshal.ReleaseComObject(messagePump); } return result; } // Get ITfMessagePump interface from Cicero. /// /// Critical - calls critical code, created objects deal with raw input /// [SecurityCritical] private UnsafeNativeMethods.ITfMessagePump GetMessagePump() { UnsafeNativeMethods.ITfMessagePump messagePump = null; if (_isTSFMessagePumpEnabled) { // If the current thread is not STA, Cicero just does not work. // Probably this Dispatcher is running for worker thread. if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { // If there is no text services, we don't have to use ITfMessagePump. if (TextServicesLoader.ServicesInstalled) { UnsafeNativeMethods.ITfThreadMgr threadManager; threadManager = TextServicesLoader.Load(); // ThreadManager does not exist. No MessagePump yet. if (threadManager != null) { // QI ITfMessagePump. messagePump = threadManager as UnsafeNativeMethods.ITfMessagePump; } } } } return messagePump; } /// /// Enables/disables ITfMessagePump handshake with Text Services Framework. /// /// /// PresentationCore's TextServicesManager sets this property false when /// no WPF element has focus. This is important to ensure that native /// controls receive unfiltered input. /// [FriendAccessAllowed] // Used by TextServicesManager in PresentationCore. internal bool IsTSFMessagePumpEnabled { set { _isTSFMessagePumpEnabled = value; } } // // SecurityCritical - as this does unsafe operations. // [SecurityCritical] private void TranslateAndDispatchMessage(ref MSG msg) { bool handled = false; handled = ComponentDispatcher.RaiseThreadMessage(ref msg); if(!handled) { UnsafeNativeMethods.TranslateMessage(ref msg); UnsafeNativeMethods.DispatchMessage(ref msg); } } // // Critical - as it accesses security critical data ( window handle) // [SecurityCritical] private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if(_disableProcessingCount > 0) { throw new InvalidOperationException(SR.Get(SRID.DispatcherProcessingDisabledButStillPumping)); } if(msg == NativeMethods.WM_DESTROY) { if(!_hasShutdownStarted && !_hasShutdownFinished) // Dispatcher thread - no lock needed for read { // Aack! We are being torn down rudely! Try to // shut the dispatcher down as nicely as we can. ShutdownImpl(); } } else if(msg == _msgProcessQueue) { ProcessQueue(); } else if(msg == NativeMethods.WM_TIMER && (int) wParam == 1) { // We want 1-shot only timers. So stop the timer // that just fired. SafeNativeMethods.KillTimer(new HandleRef(this, hwnd), 1); ProcessQueue(); } else if(msg == NativeMethods.WM_TIMER && (int) wParam == 2) { // We want 1-shot only timers. So stop the timer // that just fired. KillWin32Timer(); PromoteTimers(Environment.TickCount); } // We are about to return to the OS. If there is nothing left // to do in the queue, then we will effectively go to sleep. // This is the condition that means Idle. DispatcherHooks hooks = null; bool idle = false; lock(_instanceLock) { idle = (_postedProcessingType < PROCESS_BACKGROUND); if (idle) { hooks = _hooks; } } if (idle) { if(hooks != null) { hooks.RaiseDispatcherInactive(this); } ComponentDispatcher.RaiseIdle(); } return IntPtr.Zero ; } /// /// SecurityCritical - as this code performs an elevation. /// TreatAsSafe - this method returns "I have input that can be processed". /// equivalent to saying a 'key has been hit'. /// Considered safe. /// [SecurityCritical, SecurityTreatAsSafe ] private bool IsInputPending() { int retVal = 0; // We need to know if there is any pending input in the Win32 // queue because we want to only process Avalon "background" // items after Win32 input has been processed. // // Win32 provides the GetQueueStatus API -- but it has a major // drawback: it only counts "new" input. This means that // sometimes it could return false, even if there really is input // that needs to be processed. This results in very hard to // find bugs. // // Luckily, Win32 also provides the MsgWaitForMultipleObjectsEx // API. While more awkward to use, this API can return queue // status information even if the input is "old". The various // flags we use are: // // QS_INPUT // This represents any pending input - such as mouse moves, or // key presses. It also includes the new GenericInput messages. // // QS_EVENT // This is actually a private flag that represents the various // events that can be queued in Win32. Some of these events // can cause input, but Win32 doesn't include them in the // QS_INPUT flag. An example is WM_MOUSELEAVE. // // QS_POSTMESSAGE // If there is already a message in the queue, we need to process // it before we can process input. // // MWMO_INPUTAVAILABLE // This flag indicates that any input (new or old) is to be // reported. // retVal = UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, null, 0, NativeMethods.QS_INPUT | NativeMethods.QS_EVENT | NativeMethods.QS_POSTMESSAGE, NativeMethods.MWMO_INPUTAVAILABLE); return retVal == 0; } private bool RequestProcessing() // NOTE: should be Priority { bool succeeded = true; // This method is called from within the instance lock. So we // can reliably check the _window field without worrying about // it being changed out from underneath us during shutdown. if (IsWindowNull()) return false; DispatcherPriority priority = _queue.MaxPriority; if(priority != DispatcherPriority.Invalid && // Nothing. NOTE: should be Priority.Invalid priority != DispatcherPriority.Inactive) // Not processed. NOTE: should be Priority.Min { if(_foregroundPriorityRange.Contains(priority)) { succeeded = RequestForegroundProcessing(); } else { succeeded = RequestBackgroundProcessing(); } } return succeeded; } /// /// Critical: This code accesses window /// TreatAsSafe: This code is ok to call since it does not expose the resource /// [SecurityCritical,SecurityTreatAsSafe] private bool IsWindowNull() { if(_window.Value == null) { return true; } return false; } // // Critical as it access critical data - for the window handle. // TreatAsSafe - as this is a request to do queued work. Analogous to VB's DoEvents() // [SecurityCritical, SecurityTreatAsSafe] private bool RequestForegroundProcessing() { if(_postedProcessingType < PROCESS_FOREGROUND) { // If we have already set a timer to do background processing, // make sure we stop it before posting a message for foreground // processing. if(_postedProcessingType == PROCESS_BACKGROUND) { SafeNativeMethods.KillTimer(new HandleRef(this, _window.Value.Handle), 1); } _postedProcessingType = PROCESS_FOREGROUND; // We have foreground items to process. // By posting a message, Win32 will service us fairly promptly. return UnsafeNativeMethods.TryPostMessage(new HandleRef(this, _window.Value.Handle), _msgProcessQueue, IntPtr.Zero, IntPtr.Zero); } return true; } // // Critical - as it accesses critical data - to get the Window Handle. // TreatAsSafe - as this method would be ok to expose publically, this is just a request for Timer processing. // [SecurityCritical, SecurityTreatAsSafe] private bool RequestBackgroundProcessing() { bool succeeded = true; if(_postedProcessingType < PROCESS_BACKGROUND) { // If there is Win32 input pending, we can't do any background // processing until it is done. We use a short timer to // get processing time after the input. if(IsInputPending()) { _postedProcessingType = PROCESS_BACKGROUND; succeeded = SafeNativeMethods.TrySetTimer(new HandleRef(this, _window.Value.Handle), 1, 1); } else { succeeded = RequestForegroundProcessing(); } } return succeeded; } private void PromoteTimers(int currentTimeInTicks) { try { List timers = null; long timersVersion = 0; lock(_instanceLock) { if(!_hasShutdownFinished) // Could be a non-dispatcher thread, lock to read { if(_dueTimeFound && _dueTimeInTicks - currentTimeInTicks <= 0) { timers = _timers; timersVersion = _timersVersion; } } } if(timers != null) { DispatcherTimer timer = null; int iTimer = 0; do { lock(_instanceLock) { timer = null; // If the timers collection changed while we are in the middle of // looking for timers, start over. if(timersVersion != _timersVersion) { timersVersion = _timersVersion; iTimer = 0; } while(iTimer < _timers.Count) { // WARNING: this is vulnerable to wrapping if(timers[iTimer]._dueTimeInTicks - currentTimeInTicks <= 0) { // Remove this timer from our list. // Do not increment the index. timer = timers[iTimer]; timers.RemoveAt(iTimer); break; } else { iTimer++; } } } // Now that we are outside of the lock, promote the timer. if(timer != null) { timer.Promote(); } } while(timer != null); } } finally { UpdateWin32Timer(); } } internal void AddTimer(DispatcherTimer timer) { lock(_instanceLock) { if(!_hasShutdownFinished) // Could be a non-dispatcher thread, lock to read { _timers.Add(timer); _timersVersion++; } } UpdateWin32Timer(); } internal void RemoveTimer(DispatcherTimer timer) { lock(_instanceLock) { if(!_hasShutdownFinished) // Could be a non-dispatcher thread, lock to read { _timers.Remove(timer); _timersVersion++; } } UpdateWin32Timer(); } internal void UpdateWin32Timer() // Called from DispatcherTimer { if(CheckAccess()) { UpdateWin32TimerFromDispatcherThread(null); } else { BeginInvoke(DispatcherPriority.Send, new DispatcherOperationCallback(UpdateWin32TimerFromDispatcherThread), null); } } private object UpdateWin32TimerFromDispatcherThread(object unused) { lock(_instanceLock) { if(!_hasShutdownFinished) // Dispatcher thread, does not technically need the lock to read { bool oldDueTimeFound = _dueTimeFound; int oldDueTimeInTicks = _dueTimeInTicks; _dueTimeFound = false; _dueTimeInTicks = 0; if(_timers.Count > 0) { // We could do better if we sorted the list of timers. for(int i = 0; i < _timers.Count; i++) { DispatcherTimer timer = _timers[i]; if(!_dueTimeFound || timer._dueTimeInTicks - _dueTimeInTicks < 0) { _dueTimeFound = true; _dueTimeInTicks = timer._dueTimeInTicks; } } } if(_dueTimeFound) { if(!_isWin32TimerSet || !oldDueTimeFound || (oldDueTimeInTicks != _dueTimeInTicks)) { SetWin32Timer(_dueTimeInTicks); } } else if(oldDueTimeFound) { KillWin32Timer(); } } } return null; } /// /// Critical - accesses critical data /// TreatAsSafe - we think it's ok to expose timers in the SEE. /// a denial-of-service attack may be possible - but these are low-pri and possible in many other ways. /// we can never bring down the iexplore process. /// [SecurityCritical, SecurityTreatAsSafe] private void SetWin32Timer(int dueTimeInTicks) { if(!IsWindowNull()) { int delta = dueTimeInTicks - Environment.TickCount; if(delta < 1) { delta = 1; } // We are being called on the dispatcher thread so we can rely on // _window.Value being non-null without taking the instance lock. SafeNativeMethods.SetTimer( new HandleRef(this, _window.Value.Handle), // this HWND 2, // win32 timer #2 delta); // unused timer proc _isWin32TimerSet = true; } } /// /// Critical - accesses critical data _window.Value.Handle /// TreatAsSafe - OK to stop a dispatcher timer. /// [SecurityCritical, SecurityTreatAsSafe] private void KillWin32Timer() { if(!IsWindowNull()) { // We are being called on the dispatcher thread so we can rely on // _window.Value being non-null without taking the instance lock. SafeNativeMethods.KillTimer( new HandleRef(this, _window.Value.Handle), // this HWND 2); // win32 timer #2 _isWin32TimerSet = false; } } // Exception filter returns true if exception should be caught. /// /// Critical: calls ExceptionFilter, which is critical /// [SecurityCritical] private static bool ExceptionFilterStatic(object source, Exception e) { Dispatcher d = (Dispatcher)source; return d.ExceptionFilter(e); } /// /// Critical: accesses _unhandledExceptionFilter /// [SecurityCritical] private bool ExceptionFilter(Exception e) { // see whether this dispatcher has already seen the exception. // This can happen when the dispatcher is re-entered via // PushFrame (or similar). if (!e.Data.Contains(ExceptionDataKey)) { // first time we've seen this exception - add data to the exception e.Data.Add(ExceptionDataKey, null); } else { // we've seen this exception before - don't catch it return false; } // By default, Request catch if there's anyone signed up to catch it; bool requestCatch = HasUnhandledExceptionHandler; // The app can hook up an ExceptionFilter to avoid catching it. // ExceptionFilter will run REGARDLESS of whether there are exception handlers. if (_unhandledExceptionFilter != null) { // The default requestCatch value that is passed in the args // should be returned unchanged if filters don't set them explicitly. _exceptionFilterEventArgs.Initialize(e, requestCatch); bool bSuccess = false; try { _unhandledExceptionFilter(this, _exceptionFilterEventArgs); bSuccess = true; } finally { if (bSuccess) { requestCatch = _exceptionFilterEventArgs.RequestCatch; } // For bSuccess is false, // To be in line with default behavior of structured exception handling, // we would want to set requestCatch to false, however, this means one // poorly programmed filter will knock out all dispatcher exception handling. // If an exception filter fails, we run with whatever value is set thus far. } } return requestCatch; } // This returns false when caller should rethrow the exception. // true means Exception is "handled" and things just continue on. private static bool CatchExceptionStatic(object source, Exception e) { Dispatcher dispatcher = (Dispatcher)source; return dispatcher.CatchException(e); } // The exception filter called for catching an unhandled exception. private bool CatchException(Exception e) { bool handled = false; if (UnhandledException != null) { _unhandledExceptionEventArgs.Initialize(e, false); bool bSuccess = false; try { UnhandledException(this, _unhandledExceptionEventArgs); handled = _unhandledExceptionEventArgs.Handled; bSuccess = true; } finally { if (!bSuccess) handled = false; } } return(handled); } // This is called by DRT (via reflection) to see if there is a UnhandledException handler. private bool HasUnhandledExceptionHandler { get { return (UnhandledException != null); } } internal object WrappedInvoke(Delegate callback, object args, bool isSingleParameter) { return WrappedInvoke(callback, args, isSingleParameter, null); } [FriendAccessAllowed] //used by ResourceReferenceExpression in PresentationFramework internal object WrappedInvoke(Delegate callback, object args, bool isSingleParameter, Delegate catchHandler) { // Win32 considers timers to be low priority. Avalon does not, since different timers // are associated with different priorities. So we promote the timers before we // dequeue any work items. PromoteTimers(Environment.TickCount); return _exceptionWrapper.TryCatchWhen(this, callback, args, isSingleParameter, catchHandler); } private object[] CombineParameters(object arg, object[] args) { object[] parameters = new object[1 + (args == null ? 1 : args.Length)]; parameters[0] = arg; if (args != null) { Array.Copy(args, 0, parameters, 1, args.Length); } else { parameters[1] = null; } return parameters; } private const int PROCESS_NONE = 0; private const int PROCESS_BACKGROUND = 1; private const int PROCESS_FOREGROUND = 2; private static List _dispatchers; private static WeakReference _possibleDispatcher; private static object _globalLock; [ThreadStatic] private static Dispatcher _tlsDispatcher; // use TLS for ownership only private Thread _dispatcherThread; private int _frameDepth; internal bool _exitAllFrames; // used from DispatcherFrame private bool _startingShutdown; internal bool _hasShutdownStarted; // used from DispatcherFrame private SecurityCriticalDataClass _shutdownExecutionContext; internal int _disableProcessingCount; // read by DispatcherSynchronizationContext, decremented by DispatcherProcessingDisabled //private static Priority _foregroundBackgroundBorderPriority = new Priority(Priority.Min, Priority.Max, "Dispatcher.ForegroundBackgroundBorder"); //private static Priority _backgroundIdleBorderPriority = new Priority(Priority.Min, _foregroundBackgroundBorderPriority, "Dispatcher.BackgroundIdleBorder"); //private static Priority _foregroundPriority = new Priority(_foregroundBackgroundBorderPriority, Priority.Max, "Dispatcher.Foreground"); //private static Priority _backgroundPriority = new Priority(_backgroundIdleBorderPriority, _foregroundBackgroundBorderPriority, "Dispatcher.Background"); //private static Priority _idlePriority = new Priority(Priority.Min, _backgroundIdleBorderPriority, "Dispatcher.Idle"); //private static PriorityRange _foregroundPriorityRange = new PriorityRange(_foregroundBackgroundBorderPriority, false, Priority.Max, true); //private static PriorityRange _backgroundPriorityRange = new PriorityRange(_backgroundIdleBorderPriority, false, _foregroundBackgroundBorderPriority, false); //private static PriorityRange _idlePriorityRange = new PriorityRange(Priority.Min, false, _backgroundIdleBorderPriority, false); private static PriorityRange _foregroundPriorityRange = new PriorityRange(DispatcherPriority.Loaded, true, DispatcherPriority.Send, true); private static PriorityRange _backgroundPriorityRange = new PriorityRange(DispatcherPriority.Background, true, DispatcherPriority.Input, true); private static PriorityRange _idlePriorityRange = new PriorityRange(DispatcherPriority.SystemIdle, true, DispatcherPriority.ContextIdle, true); private SecurityCriticalData _window; /// /// Critical: If disclosed, would allow untrusted parties to listen to raw messages. /// [SecurityCritical] private HwndWrapperHook _hook; private int _postedProcessingType; /// /// Critical: This code gets set by RegisterWindowMessage which is under an elevation. /// [SecurityCritical] private static int _msgProcessQueue; private static ExceptionWrapper _exceptionWrapper; private static readonly object ExceptionDataKey = new object(); // Preallocated arguments for exception handling. // This helps avoid allocations in the handler code, a potential // source of secondary exceptions (i.e. in Out-Of-Memory cases). private DispatcherUnhandledExceptionEventArgs _unhandledExceptionEventArgs; /// /// Do not expose to partially trusted code. /// [SecurityCritical] private DispatcherUnhandledExceptionFilterEventHandler _unhandledExceptionFilter; private DispatcherUnhandledExceptionFilterEventArgs _exceptionFilterEventArgs; private object _reserved0; private object _reserved1; private object _reserved2; private object _reserved3; private object _reservedPtsCache; private object _reservedInputMethod; private object _reservedInputManager; internal object _instanceLock = new object(); // Also used by DispatcherOperation private PriorityQueue _queue; private List _timers = new List(); private long _timersVersion; private bool _dueTimeFound; private int _dueTimeInTicks; private bool _isWin32TimerSet; // This can be read from any thread, but only written by the dispatcher thread. // Dispatcher Thread - lock _instanceLock only on write // Non-Dispatcher Threads - lock _instanceLock on read private bool _hasShutdownFinished; // Enables/disables ITfMessagePump handshake with Text Services Framework. private bool _isTSFMessagePumpEnabled; /// /// Do not expose hooks to partial trust. /// [SecurityCritical] private DispatcherHooks _hooks; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.

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