InfoCardUIAgent.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / InfoCardUIAgent.cs / 1 / InfoCardUIAgent.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
//
// Presharp uses the c# pragma mechanism to supress its warnings. 
// These are not recognised by the base compiler so we need to explictly
// disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp 
// for details. 
//
#pragma warning disable 1634, 1691      // unknown message, unknown pragma 



namespace Microsoft.InfoCards 
{
    using System; 
    using System.Collections; 
    using System.Collections.Specialized;
    using System.ComponentModel; 
    using System.Configuration;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.Principal; 
    using System.Threading; 
    using System.Runtime.CompilerServices;
    using System.IO; 
    using Microsoft.Win32;

    using Microsoft.Win32.SafeHandles;
    using Microsoft.InfoCards.Diagnostics; 

    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; 
 
    //
    // Summary: 
    // This classes manages a UIAgent process launched to interact with the user in order manage infocards
    // or create a token.
    //
    internal class InfoCardUIAgent 
    {
        // 
        // UInt32IndexedHybridDictionary provides a typesafe call into the 
        // indexer by uint. HybridDictionary's indexer is an object, so
        // any value type passed in must be boxed. That means (uint)0 and 
        // (int)0 don't lookup to the same value. This lead to confusing
        // bugs where things that you *know* are in the collection appear
        // not to be. This wrapper will catch this kind of bug at compile time.
        // 
        private class UInt32IndexedHybridDictionary
        { 
            private HybridDictionary m_realDictionary = new HybridDictionary(); 
            public UInt32IndexedHybridDictionary() {}
 
            public int Count { get { return m_realDictionary.Count; } }
            public ICollection Values { get { return m_realDictionary.Values; } }

            public object this[uint index] 
            {
                get 
                { 
                    return m_realDictionary[index];
                } 
                set
                {
                    m_realDictionary[index] = value;
                } 
            }
 
            public void Remove(uint index) 
            {
                m_realDictionary.Remove(index); 
            }
        }

        // 
        // The name of the exe to launch.
        // 
        private const string UiAgentName = "icardagt.exe"; 

        // 
        // As per threat model mitigation, need to give exact path to agent.
        //
        public static readonly string UiAgentFullPath = Path.Combine(
                                                Environment.GetFolderPath( Environment.SpecialFolder.System ), 
                                                UiAgentName );
 
        static bool                 s_initialized; 
        static bool                 s_isShuttingDown;
        static ManualResetEvent     s_doneShuttingDownEvent = new ManualResetEvent( false ); 

        //
        // A collection of uiagents based on TS session.
        // 
        static UInt32IndexedHybridDictionary     s_sessionIdCollection = new UInt32IndexedHybridDictionary();
 
        // 
        // A collection of uiagents based on pid.
        // 
        static UInt32IndexedHybridDictionary     s_pidCollection = new UInt32IndexedHybridDictionary();

        //
        // The key under which we check for the agent sleep time ( under hklm ) 
        //
        const string IdleTimeoutKey     = @"software\microsoft\infocard"; 
        const int    IdleTimeoutDefault = 60 * 5; // in seconds 
        const string IdleTimeoutValue   = "sleep1";
 
        //
        // The time we wait for the ui agent to respond to state changes.
        //
        readonly TimeSpan AgentStateChangeTimeOut = new TimeSpan( 0, 0, 300 ); 

        // 
        // How long a uiagent should be kept waiting for more work after completing work on the last request. 
        //
        static TimeSpan             s_idleTimeout = new TimeSpan( 0, 0, IdleTimeoutDefault ); 



 
        static object               s_syncRoot = new object();
 
        ManualResetEvent            m_uiStatusRecieved;         //used by the ShowUI method to know when the ui agent has completed. 

        AutoResetEvent              m_agentGetWorkStart; 
        AutoResetEvent              m_agentGetWorkComplete;          // When set the uiagent process should call the GetWork Method
        ClientUIRequest             m_request;              // The request the uiagent is associated with if any.

        int                         m_tsSessionId;          // The TS session of this uiagent. 
        Process                     m_process;              // The uiagent process.
        EventHandler                m_processExitHandler; 
        System.Threading.Timer      m_timer; 
        string                      m_trustedUserSid;       // Logon Sid the agent is running under
        SafeNativeHandle            m_trustedUserToken;     // User token the agent and accessibility apps will run under 

        string                      m_desktopName;          // Infocard secure desktop name.
        string                      m_user;                 // string sid of user for which this uiagent was created.
 
        CallMode                    m_mode;
 
 
        RpcUIAgentGetWorkCallback   m_getWorkCallback;      //Hold reference to prevent cleanup.
 
        ClientUIRequest.RequestResult   m_currentStatus;    //Holds the current status fo the UI.
        object                      m_memberSync;

 
        public enum CallMode
        { 
            Sleep      = 0,   // indicating request to let the UIAgent sleep 
            Initialize = 1,   // Show initial splash screen and OOB
            GetToken   = 2,   // When a client requests for a security token 
            Manage     = 3,   // Infocard Management mode
            Import     = 4,   // Started via Import API
            Shutdown   = 5,   // Indicating request to shutdown the UIAgent
            Crash      = 6,   // Indicates a crash on the service side. 
            Error      = 7,   // Indicates that the agent should show the last processing exception.
            Release    = 8,   // last call before state is torn down. 
        }; 

        // 
        // Summary:
        // Constructs a new UIAgent instance and starts the UI Agent process.
        //
        // Parameters: 
        //  callerPid       - The request that this UI Agent will be replaced with.
        //  userIdentity    - The identity of the user that the agent should run as 
        //  tsSessionId     - The tsSession that the process should be created for. 
        //
        private InfoCardUIAgent( int callerPid, WindowsIdentity userIdentity, int tsSessionId ) 
        {
            m_agentGetWorkStart = new AutoResetEvent( false );
            m_agentGetWorkComplete = new AutoResetEvent( false );
 
            m_uiStatusRecieved = new ManualResetEvent( false );
            m_tsSessionId = tsSessionId; 
            m_timer = null; 
            IntPtr processHandle = IntPtr.Zero;
            IntPtr trustedUserToken = IntPtr.Zero; 
            int processId = 0;
            m_mode = CallMode.Sleep;   //  We start our process state in sleep mode, so the initial initalize will get sent.
            m_currentStatus = ClientUIRequest.RequestResult.Pending;
            m_user = userIdentity.User.ToString(); 
            m_memberSync = new object();
 
 
            //
            // Verify the signature on the agent executable 
            //
            int error = NativeMcppMethods.VerifyTrust( UiAgentFullPath );

            if( 0 != error ) 
            {
                // 
                // Log and failfast. Most likely icardagt signing verification failed. 
                //
                Microsoft.InfoCards.Diagnostics.InfoCardTrace.FailFast( SR.GetString( SR.FailedToVerifySignature, error ) ); 
            }

            IntPtr jobHandle = IntPtr.Zero;
 

            // 
            // We call this method with a null handle as we do not want this 
            // process to be put in a job.
            // 
            bool fUseElevatedToken = false;
            error = ( int ) NativeMcppMethods.CreateProcessAsTrustedUserWrapper(
                                                       UiAgentFullPath,
                                                       "", 
                                                       (uint)callerPid,
                                                       @"WinSta0\Default", 
                                                       userIdentity.Name, 
                                                       (uint)m_tsSessionId,
                                                       ref trustedUserToken, 
                                                       ref processHandle,
                                                       ref processId,
                                                       jobHandle, // null handle
                                                       ref m_trustedUserSid, 
                                                       fUseElevatedToken );
 
            if( 0 != error ) 
            {
                // 
                // For other errors we'll not crash the service
                //
                throw IDT.ThrowHelperError( new FailedToStartupUIException(
                    SR.GetString( SR.CreateProcessFailed, error ), 
                    new Win32Exception( error ) ) );
            } 
 
            m_trustedUserToken = new SafeNativeHandle( trustedUserToken, true );
            IDT.TraceDebug( "UIAGENT: Trusted User Sid:" + m_trustedUserSid ); 

            using( SafeWaitHandle quickhandle = new SafeWaitHandle( processHandle, true ) )
            {
                // 
                // Get a managed process instance to hold on to and hook
                // in to the Exited event. 
                // 
                m_process = ProcessMonitor.GetProcessById( ( int ) processId );
 
                m_processExitHandler = new EventHandler( OnProcessExit );
                m_process.Exited += m_processExitHandler;

                // 
                // Make sure the process didn't exit while we were setting
                // up the managed handler. 
                // 
                Utility.ThrowIfProcessExited( quickhandle );
            } 

        }

 
        public uint ProcessId
        { 
            get { return (uint) m_process.Id; } 
        }
 
        public string DesktopName
        {
            get { return m_desktopName; }
        } 

        private ClientUIRequest Request 
        { 
            get { return m_request; }
        } 

        public int TsSessionId
        {
            get { return m_tsSessionId; } 
        }
 
        public bool IsActive 
        {
            get 
            {
                switch( m_mode )
                {
                    case CallMode.GetToken: 
                    case CallMode.Manage:
                    case CallMode.Import: 
                    case CallMode.Error: 
                        return true;
                    default: 
                        return false;
                }
            }
        } 

        public bool IsShuttingDown 
        { 
            get { return m_mode == CallMode.Shutdown; }
        } 

        public SafeNativeHandle TrustedUserToken
        {
            get 
            {
                return m_trustedUserToken; 
            } 
        }
 
        public string TrustedUserSid
        {
            get
            { 
                return m_trustedUserSid;
            } 
        } 

        public string User 
        {
            get { return m_user; }
        }
 
        //
        // Summary: 
        //   See if the default idleTimeout has been overridden and set it if necessary 
        //
        static private void InitializeIfNecessary() 
        {
            if( s_initialized )
            {
                return; 
            }
 
            lock( s_syncRoot ) 
            {
                if( !s_initialized ) 
                {

                    using( RegistryKey rk = Registry.LocalMachine.OpenSubKey( IdleTimeoutKey, false ) )
                    { 
                        if( null != rk )
                        { 
                            object sleepTime = rk.GetValue( IdleTimeoutValue, IdleTimeoutDefault ); 
                            if( sleepTime is int && (int)sleepTime > 0  )
                            { 
                                s_idleTimeout = new TimeSpan( 0,0,(int)sleepTime );
                            }
                        }
                    } 

                    s_initialized = true; 
                } 
            }
        } 

        //
        // Summary:
        // Called by InfoCardRequest when it needs a UIAgent.  This method checks to see whether there 
        // are any already existing UIAgents that are just waiting to serve another request or whether it
        // needs to create a new one altogether, and does the appropriate thing. 
        // 
        // Parameters:
        //  callerPid       - The request that this UI Agent will be replaced with. 
        //  userIdentity    - The identity of the user that the agent should run as
        //  tsSessionId     - The tsSession that the process should be created for.
        //
        static public InfoCardUIAgent Create( int callerPid, WindowsIdentity callerIdentity, int tsSessionId ) 
        {
            InitializeIfNecessary(); 
 
            InfoCardUIAgent uiagent = null;
 
            lock( s_syncRoot )
            {
                ThrowIfShuttingDown();
 
                uiagent = ( InfoCardUIAgent ) s_sessionIdCollection[ (uint)tsSessionId ];
 
                if( null != uiagent ) 
                {
                    if( uiagent.IsShuttingDown ) 
                    {
                        //
                        // This one is already going away, we'll need a new one.
                        // 
                        uiagent = null;
                    } 
                    else if( null != uiagent.Request ) 
                    {
                        throw IDT.ThrowHelperError( new ServiceBusyException() ); 
                    }
                    else if( uiagent.User != callerIdentity.User.ToString() )
                    {
                        // 
                        // We can't use the existing agent since it's for a different user.  Shutdown the existing
                        // agent. 
                        // 
                        uiagent.Shutdown();
                        uiagent = null; 
                    }
                    else
                    {
                        // 
                        // Fall through.
                        // 
                    } 
                }
 
                if( null == uiagent )
                {
                    //
                    // Start a new UI Agent. 
                    //
                    uiagent = new InfoCardUIAgent( callerPid, callerIdentity, tsSessionId ); 
 
                    //
                    // Add it to the static lists. 
                    //
                    s_pidCollection[ uiagent.ProcessId ] = uiagent;
                    s_sessionIdCollection[ (uint)tsSessionId ] = uiagent;
                } 
            }
            return uiagent; 
        } 

 
        public RpcUIAgentGetWorkCallback Bind(
                                            string desktopName,
                                            out SecurityIdentifier userSid,
                                            out SafeWaitHandle hStartEvent, 
                                            out SafeWaitHandle hCompleteEvent )
        { 
            lock( m_memberSync ) 
            {
                userSid = new SecurityIdentifier( m_trustedUserSid ); 


                hStartEvent = Utility.GetRemoteHandleFromLocalHandle(
                                                            m_agentGetWorkStart.SafeWaitHandle, 
                                                            m_process );
 
                hCompleteEvent = Utility.GetRemoteHandleFromLocalHandle( 
                                                            m_agentGetWorkComplete.SafeWaitHandle,
                                                            m_process ); 
                m_desktopName = desktopName;
                return ( m_getWorkCallback = new RpcUIAgentGetWorkCallback( GetWork ) );
            }
        } 

 
        // 
        // Summary:
        //  Resets the current status to pending, and resets the sync handle. 
        //
        public void ResetUIResult()
        {
            m_currentStatus = ClientUIRequest.RequestResult.Pending; 
            m_uiStatusRecieved.Reset();
        } 
 
        //
        // Summary: 
        //  Show the UI
        //
        public ClientUIRequest.RequestResult ShowUI( CallMode mode )
        { 
            //
            // if we have not yet recieved a status 
            //  In some cases we may have recieved a cancel/error durring the 
            //  the splash screen/oobe, which would set the m_currentStatus to cancel/error
            // 
            if( ClientUIRequest.RequestResult.Pending == m_currentStatus )
            {
                bool waitForChange = false;
 
                lock( m_memberSync )
                { 
                    if( ClientUIRequest.RequestResult.Pending == m_currentStatus ) 
                    {
                        // 
                        // Signal the agent to pick up the new mode.
                        //
                        switch( mode )
                        { 
                            case CallMode.GetToken:
                            case CallMode.Manage: 
                            case CallMode.Import: 
                            case CallMode.Error:
                                if( SetMode( mode ) ) 
                                {
                                    waitForChange = true;
                                }
                                break; 
                            default:
                                IDT.ThrowInvalidArgumentConditional( true, "mode" ); 
                                break; 
                        }
                    } 
                }
                //
                // Always wait for change outside the lock.
                // 
                if( waitForChange )
                { 
                    WaitForModeChange(); 
                }
 
                //
                // Wait for the agent to signal to us that the ui has send a result
                //
                m_uiStatusRecieved.WaitOne(); 
            }
            return m_currentStatus; 
        } 

        // 
        // Summary:
        //  updates the UI Status info
        //
        public void SetUIStatus( ClientUIRequest.RequestResult status ) 
        {
            lock( m_memberSync ) 
            { 
                //
                // update the status 
                //
                m_currentStatus = status;

                // 
                // Before we signal the primary thread that the results are ready,
                //  we will tell the parent request that a cancel occured to allow it 
                //  to clean up an local long lived operations. 
                //
                if( null != m_request 
                    && ( ClientUIRequest.RequestResult.Cancel == m_currentStatus
                        || ClientUIRequest.RequestResult.Untrusted == m_currentStatus
                        || ClientUIRequest.RequestResult.Error == m_currentStatus ) )
                { 
                    m_request.UserCancel( ClientUIRequest.RequestResult.Untrusted == m_currentStatus );
                } 
 
                //
                // signal to any waiting threads that the results are ready 
                //
                m_uiStatusRecieved.Set();
            }
        } 

        public void SetRequest( ClientUIRequest request ) 
        { 
            IDT.Assert( null != request, "Request should not be null" );
            bool waitForChange = false; 

            //
            // Take the global lock.
            //  This method interacts with globally checked resources (m_request), 
            //  so it must use the static lock
            // 
            lock( s_syncRoot ) 
            {
                // 
                // We have taken the s_syncRoot lock already.
                //

                if( null != m_timer ) 
                {
                    m_timer.Dispose(); 
                    m_timer = null; 
                }
 
                m_request = request;

                if( SetMode( CallMode.Initialize ) )
                { 
                    waitForChange = true;
                } 
 
                //
                // reset the ui status event and the last status. 
                //
                m_currentStatus = ClientUIRequest.RequestResult.Pending;
                m_uiStatusRecieved.Reset();
            } 
            //
            // Always wait for change outside the lock. 
            // 
            if( waitForChange )
            { 
                WaitForModeChange();
            }
        }
 
        bool SetMode( CallMode mode )
        { 
            bool bChangedMode = false; 
            lock( m_memberSync )
            { 
                if( CallMode.Shutdown != m_mode && m_mode != mode )
                {
                    switch( mode )
                    { 
                        case CallMode.Sleep:
                            IDT.ThrowInvalidArgumentConditional( m_mode != CallMode.Release, "mode" ); 
                            break; 
                        case CallMode.Release:
                            switch( m_mode ) 
                            {
                                case CallMode.Initialize:
                                case CallMode.GetToken:
                                case CallMode.Manage: 
                                case CallMode.Import:
                                case CallMode.Error: 
                                    break; 
                                default:
                                    IDT.ThrowInvalidArgumentConditional( true, "mode" ); 
                                    break;
                            }
                            break;
                        case CallMode.Shutdown: 

                            break; 
                        case CallMode.GetToken: 
                        case CallMode.Manage:
                        case CallMode.Import: 
                        case CallMode.Error:
                            //
                            // Throw if current mode isn't initialize mode.
                            // 
                            IDT.ThrowInvalidArgumentConditional( m_mode != CallMode.Initialize, "mode" );
                            break; 
                        case CallMode.Initialize: 
                            //
                            // Throw if current mode isn't sleep mode. 
                            //
                            IDT.ThrowInvalidArgumentConditional( m_mode != CallMode.Sleep, "mode" );
                            break;
                        default: 
                            IDT.ThrowInvalidArgumentConditional( true, "mode" );
                            break; 
                    } 

                    m_mode = mode; 
                    bChangedMode = true;
                }
            }
            return bChangedMode; 
        }
 
        public void ReleaseUI() 
        {
           if( IsActive || CallMode.Initialize == m_mode ) 
           {
                if( SetMode( CallMode.Release ) )
                {
                    WaitForModeChange(); 
                }
            } 
        } 

        void WaitForModeChange() 
        {
            m_agentGetWorkStart.Set();
            //
            // This is added to prevent unbounded waits. Some scenarios like intensive disk IO can cause long delays 
            // and thus the time out has been set to 5 minutes.
            // Some services like Human Interface devices and utilman can hold 
            // on to a desktop handle for the secure desktop. In such instances there is no way to switch 
            // back from the infocard UI.
            // 
            if( false == m_agentGetWorkComplete.WaitOne(
                                AgentStateChangeTimeOut ,
                                false  ) )
            { 
                Utility.KillHelper( m_process );
                throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.UIAgentCrash ) ) ); 
            } 

        } 


        //
        // Summary: 
        // Called by the UI Agent process whenever the event passed in to GetByPid is signalled and right after calling
        // GetByPid in order to get work and connect the UI Agent directly to the relevant request object. 
        // 
        // Parameters:
        // mode      - returns the mode in which the UI Agent should start in. 
        // requestHandle  - handle to client request
        //
        void GetWork( out InfoCardUIAgent.CallMode mode, out int requestHandle )
        { 
            //
            // Take the global lock. 
            //  This method interacts with globally checked resources (IsShuttingDown), 
            //  so it must use the static lock
            // 

            lock ( m_memberSync )
            {
                mode = CallMode.Shutdown; 
                requestHandle = 0;
                try 
                { 
                    mode = m_mode;
 
                    if( null != m_request )
                    {
                        requestHandle = m_request.RequestHandle;
                    } 

                    if( mode == CallMode.Sleep ) 
                    { 
                        //
                        // Returning a new sleep mode, start the kill timer. 
                        //
                        m_timer = new System.Threading.Timer(IDT.ThunkCallback(new TimerCallback(OnTimeout)),
                                                              null,                              // no state
                                                              s_idleTimeout, 
                                                              new TimeSpan( 0, 0, 0, 0, -1 ) );  // not a periodic timer.
 
                    } 
                }
#pragma warning disable 56500       // do not catch non-recoverable exceptions 
                catch ( Exception e )
                {
                    if ( IDT.IsFatal( e ) )
                    { 
                        InfoCardService.Crash( e );
                    } 
                    IDT.TraceDebug( "An exception was generated: \n{0}", e.ToString() ); 

                    ClientUIRequest request = this.Request; 
                    if ( null != request )
                    {
                        request.ProcessingException = e;
                    } 
                }
#pragma warning restore 56500 
            } 
        }
 
        //
        // Summary:
        // Disassociates this UI Agent with the request passed in.
        // 
        // Parameters:
        // request - the request to disassociate this uiagent from 
        // 
        public void ClearRequest( ClientUIRequest request )
        { 
            //
            // Take the global lock.
            //  This method interacts with globally checked resources (m_request),
            //  so it must use the static lock 
            //
            bool bWaitForChange = false; 
            lock( s_syncRoot ) 
            {
                if( m_request == request ) 
                {
                    //
                    // Once the request is cleared,
                    //  tell the UI to go to sleep. 
                    //
                    if( SetMode( CallMode.Sleep ) ) 
                    { 
                        bWaitForChange = true;
                    } 

                    m_request = null;
                }
            } 

            // 
            // Always wait for change outside the lock. 
            //
            if( bWaitForChange ) 
            {
                WaitForModeChange();

                // 
                // After we set the UI Agent to sleep, if it indicated
                //  to us (by returning and Error result) that it needs 
                //  to terminate gracefully, we send the shutdown command 
                //  to terminate the process.
                // 
                if( ClientUIRequest.RequestResult.Error == m_currentStatus )
                {
                    Shutdown();
                } 
            }
        } 
 
        //
        // Summary: 
        //  Fires when m_timer fires.  Used to control how long a UI Agent process sleeps waiting for another
        //  request.
        //
        // Parameters: 
        //  state - ignored
        // 
        private void OnTimeout( object state ) 
        {
            lock( s_syncRoot ) 
            {
                if( null == m_request && !IsShuttingDown )
                {
                    Shutdown(); 
                }
            } 
        } 

        // 
        // Summary:
        //   Handler for UI Agent process exit cleanup
        //
        private void OnProcessExit( int exitCode ) 
        {
            lock( s_syncRoot ) 
            { 
                //
                // Set shutdown mode. 
                //
                m_mode = CallMode.Shutdown;

                s_pidCollection.Remove( (uint)this.ProcessId ); 
                s_sessionIdCollection.Remove( (uint)this.TsSessionId );
 
                if( null != m_request ) 
                {
 

                    //
                    // The only states where pending IO can still be going, or the actual
                    //  error has not already been received, we use the exit code to determine 
                    //  the exit result, and modify the result accordingly.
                    //  Pending state means we have not received the result yet. 
                    //  Ok state means that we were given the go-ahead to continue processing 
                    //      so there may be outstanding IO we need to cancel.
                    // 
                    if(     ClientUIRequest.RequestResult.Pending == m_currentStatus
                        ||  ClientUIRequest.RequestResult.Ok == m_currentStatus )
                    {
                        EventCode exitEventCode = ( EventCode ) exitCode; 

                        // 
                        // NOTE: We manually set the result to error and single 
                        //  the handle in this case.  This prevents us from taking
                        //  the member lock that could be held by the ShowUI method during 
                        //  the change mode call and dead locking.
                        //
                        switch( exitEventCode )
                        { 
                            //
                            // Results when UI exits from cancel on the final progress page. 
                            // Example: It could be a milicious resource STS (an STS that returns HTTP100 continue messages 
                            // for ever, and never lets the soap call return)in the browser case,
                            // and that happens after send the UIEnd result of Ok. 
                            // So the only way for us to tell the service that the user wants to cancel, is to kill the process
                            // because thats the only thread left listening to the agent process
                            //
                            case EventCode.E_ICARD_USERCANCELLED: 
                                m_request.UserCancel( false );
                                m_currentStatus = ClientUIRequest.RequestResult.Cancel; 
                                break; 

                            // 
                            // Results when UI exits from user choosing "Exit to safe site" on last page
                            //
                            case EventCode.E_ICARD_UNTRUSTED:
                                m_request.UserCancel( true ); 
                                m_currentStatus = ClientUIRequest.RequestResult.Untrusted;
                                break; 
 
                            //
                            // Results if the UI exits due to an unhandled InfoCardException 
                            // being thrown. Example: Out of memory error during
                            // creation of the private desktop.
                            //
                            case EventCode.E_ICARD_UI_INITIALIZATION: 
                                m_request.UserCancel( false );
                                m_currentStatus = ClientUIRequest.RequestResult.UIFailedInitialization; 
                                break; 

                            // 
                            // Results if the UI exits due to an unexpected error condition
                            //
                            default:
                                m_request.UserCancel( false ); 
                                m_currentStatus = ClientUIRequest.RequestResult.UICrashed;
                                break; 
                        } 
                        m_uiStatusRecieved.Set();
                    } 

                }

                // 
                // Ensure that this is set, to allow any pending threads
                //  that are currently waiting for the mode change signal 
                //  from the agent to continue. 
                //
                m_agentGetWorkComplete.Set(); 

                if( s_isShuttingDown )
                {
                    if( 0 == s_pidCollection.Count ) 
                    {
                        // 
                        // The system is shutting down and this was the last uiagent to quite.  Signal 
                        // the DoShutdown method that we are done shutting down.
                        // 
                        s_doneShuttingDownEvent.Set();
                    }
                }
 
                if( null != m_timer )
                { 
                    m_timer.Dispose(); 
                    m_timer = null;
                } 

                if( null != m_trustedUserToken )
                {
                    m_trustedUserToken.Dispose(); 
                    m_trustedUserToken = null;
                } 
            } 
        }
 
        //
        // Summary:
        //   Handle event that fires when the UI Agent process exits
        // 
        // Args:
        //   sender - ignored 
        //   e      - ignored 
        //
        private void OnProcessExit( object sender, EventArgs e ) 
        {
            m_process.Exited -= m_processExitHandler;

            Process agentExited = sender as Process; 

            IDT.Assert( null != agentExited, "Should be of type process." ); 
            IDT.Assert( agentExited.ExitCode == m_process.ExitCode, "Should be the same!" ); 

            OnProcessExit( agentExited.ExitCode ); 

        }

        private static void ThrowIfShuttingDown() 
        {
            if( s_isShuttingDown ) 
            { 
                throw IDT.ThrowHelperError( new SystemShuttingDownException() );
            } 
        }

        //
        // Summary: 
        //  Alerts the UI Agent process that it should shut down.
        // 
        private void Shutdown() 
        {
            if( SetMode( CallMode.Shutdown ) ) 
            {
                WaitForModeChange();
            }
        } 

        private void Kill() 
        { 
            Utility.KillHelper( m_process );
        } 

        //
        // Summary:
        //  Whenever a logout occurs on the system we need to see if we have an agent up, and if so 
        //  kill it.
        // 
        public static void OnLogout( uint sessionId ) 
        {
            if( !s_initialized ) 
            {
                return;
            }
 
            InfoCardUIAgent agent = null;
 
            lock( s_syncRoot ) 
            {
                agent = (InfoCardUIAgent)s_sessionIdCollection[ sessionId ]; 

                if( null != agent )
                {
                    agent.Shutdown(); 
                }
            } 
 
            return;
        } 

        public static void DoShutdown()
        {
            bool needToWait = false; 
            if( !s_initialized )
            { 
                return; 
            }
 
            lock( s_syncRoot )
            {
                s_isShuttingDown = true;
 
                foreach( InfoCardUIAgent agent in s_sessionIdCollection.Values )
                { 
                    needToWait = true; 
                    agent.Shutdown();
                } 
            }

            if( needToWait )
            { 
                bool signaled = s_doneShuttingDownEvent.WaitOne( new TimeSpan( 0, 0, 15 ), false );
 
                if( !signaled ) 
                {
                    lock( s_syncRoot ) 
                    {
                        foreach( InfoCardUIAgent agent in s_sessionIdCollection.Values )
                        {
                            IDT.TraceDebug( "Have to kill the agent for some reason."); 
                            agent.Kill();
                        } 
                    } 
                }
            } 
        }

        //
        // Summary: 
        // Return the InfoCardUIAgent based on pid passed in
        // 
        // Args: 
        // pid - the pid of the UI Agent object that is requested
        // 
        public static InfoCardUIAgent FindByPid( uint pid )
        {
            lock ( s_syncRoot )
            { 
                return ( InfoCardUIAgent ) s_pidCollection[ pid ];
            } 
        } 

 
    }
}

// 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