ClientUIRequest.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 / ClientUIRequest.cs / 1 / ClientUIRequest.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.Generic;
    using System.ComponentModel; //Win32Exception 
    using System.Diagnostics;
    using System.IO; //Stream
    using System.Runtime.InteropServices;
    using System.Security.Principal; //WindowsIdentity 
    using System.Threading; //ManualResetEvent
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; 
 
    abstract class ClientUIRequest :ClientRequest
    { 
        class ProcessHandleDictionary :HandleDictionary { }

        static object s_syncRoot = new object();
        static ProcessHandleDictionary s_connectedProcesses = new ProcessHandleDictionary(); 

 
        public enum RequestResult 
        {
            Pending         = 0,            // Indicating that the results are still pending. 
            Ok              = 1,            // Indicating that the request was completed sucessfully
            Cancel          = 2,            // Indicating that the request was cancelled by the user
            Untrusted       = 3,            // Indicating that the request was cancelled by the user as the recipient was not trusted
            Error           = 4,            // Indicating that an error occured during the request processing. 
            UIFailedInitialization = 5,     // Indicating that an error occured during initialization of the Ui agent.
                                            //     for example during creation of the secure desktop. 
            UICrashed = 6,                  // Indicating that an unexpected error occurred in the agent causing it to crash 
        };
 
        //
        // Set when the uiagent is done.
        //
        ManualResetEvent m_uiAgentDone; 

        // 
        //  This connection is made on the root incoming UI request. 
        //  This should no be directly used, but is maintained to ensure
        //  that the store is not de-referenced by another call and remains loaded 
        //  throughout the entire request.
        //
        StoreConnection m_rootStoreReference;
        volatile InfoCardUIAgent m_uiAgent; 
        InfoCardUIAgent.CallMode m_uiAgentMode;
        AccessibilityApplicationManager m_atManager = new AccessibilityApplicationManager(); 
 

        // 
        // Summary:
        //  Base CTOR for client UI requests
        //
        // Arguments: 
        //  callingProcess          - The process in which the caller originated.
        //  callingIdentity         - The WindowsIdentity of the caller 
        //  uiAgent                 - The instance of the InfoCardUIAgent class that we should bind to. 
        //  rpcHandle               - The handle of the native RPC request
        //  inArgs                  - The stream to read input data from 
        //  outArgs                 - The stream to write output data to
        //
        public ClientUIRequest( Process callingProcess, WindowsIdentity callingIdentity, InfoCardUIAgent uiAgent, IntPtr rpcHandle, Stream inArgs, Stream outArgs, InfoCardUIAgent.CallMode callMode, ExceptionList recoverableExceptions )
            : base( callingProcess, callingIdentity, rpcHandle, inArgs, outArgs, recoverableExceptions ) 
        {
            m_uiAgentMode = callMode; 
            m_uiAgentDone = new ManualResetEvent( false ); 

            // 
            // Set the request, and bind to it.
            //
            m_uiAgent = uiAgent;
            m_uiAgent.SetRequest( this ); 
        }
 
 
        //
        // Summary: 
        // Creates a client rpc context handle that the client can use in a later call to the RPCDispatchClientUIRequest
        // RPC function.
        //
        // Parameters: 
        // rpcHandle   - an incoming rpc handle.
        // context     - on return contains the newly created context handle. 
        // 
        // Returns:
        // An HRESULT. 
        //
        static public int BindToService( IntPtr rpcHandle, out IntPtr context )
        {
            int status = 0; 
            context = IntPtr.Zero;
            try 
            { 

                Process callingProcess = GetCallingProcessFromRpcHandle( rpcHandle ); 
                WindowsIdentity identity =  NativeMcppMethods.CreateServiceExecutionIdentity( callingProcess );

                WindowsImpersonationContext impersonationContext = identity.Impersonate();
                try 
                {
                    int id = 0; 
 

                    lock( s_syncRoot ) 
                    {
                        try
                        {
                            // 
                            // Try to get a new handle under which to store the Process.
                            // 
                            try 
                            {
                                id = s_connectedProcesses.GetNewHandle(); 
                            }
                            catch( IndexOutOfRangeException e )
                            {
                                throw IDT.ThrowHelperError( new ServiceBusyException( SR.GetString( SR.TooManyClientUIConnections ), e ) ); 
                            }
 
                            // 
                            // Store the process and set up the context to return to the client.
                            // 
                            s_connectedProcesses[ id ] = callingProcess;
                            context = new IntPtr( id );

                            // 
                            // We are now certain of success so clear these out so that they don't get cleaned up on the way
                            // out. 
                            // 
                            id = 0;
                            callingProcess = null; 
                        }
                        finally
                        {
                            if( null != callingProcess ) 
                            {
                                callingProcess.Dispose(); 
                            } 
                            if( 0 != id )
                            { 
                                s_connectedProcesses.Remove( id );
                            }
                        }
                    } 

                } 
                finally 
                {
                    impersonationContext.Undo(); 
                }
            }
            catch( InfoCardBaseException e )
            { 
                status = e.NativeHResult;
            } 
 
            return status;
        } 

        //
        // Summary:
        // Retrieves a Process instance that this the process of the client that is bound to the context handle 
        // passed in to this method.
        // 
        // Parameters: 
        // context  - an Rpc context handle.
        // clear    - if set to true then this method will remove the entry from the HandleDictionary before returning. 
        //
        // Returns:
        // A process instance that was saved in a previous call to BindToService.
        // 
        public static Process GetContextMapping( IntPtr context, bool clear )
        { 
            int id = context.ToInt32(); 
            Process callingProcess = null;
 
            lock( s_syncRoot )
            {
                if( s_connectedProcesses.ContainsHandle( id ) )
                { 
                    callingProcess = s_connectedProcesses[ id ];
 
                    if( clear ) 
                    {
                        s_connectedProcesses.Remove( id ); 
                    }
                }
            }
 
            return callingProcess;
        } 
 
        //
        // Summary: 
        // Given an rpc context handle finds the corresponding process isntance that was created in BindToService and
        // Disposes it.
        //
        // Parameters: 
        // context  - an rpc context handle created in a previous call to BindToService.
        // 
        public static void RemoveAndDisposeContextMapping( IntPtr context ) 
        {
            Process p = GetContextMapping( context, true ); 
            if( null != p )
            {
                p.Dispose();
            } 
        }
 
        // 
        // Summary:
        //  The ultimate mode we will require in order 
        //  to complete this request.
        //
        public InfoCardUIAgent.CallMode UIAgentMode
        { 
            get { return m_uiAgentMode; }
        } 
 
        internal InfoCardUIAgent UIAgent
        { 
            get
            {
                return m_uiAgent;
            } 
        }
 
        public int UIAgentPid 
        {
            get 
            {
                return (int)UIAgent.ProcessId;
            }
        } 

        public string UIAgentLogonSid 
        { 
            get
            { 
                return UIAgent.TrustedUserSid;
            }
        }
 
        public bool UIAgentActive
        { 
            get { return null != UIAgent && UIAgent.IsActive; } 
        }
 
        protected override void OnInitializeAsUser()
        {
            base.OnInitializeAsUser();
 
            m_rootStoreReference = StoreConnection.CreateConnection();
        } 
 
        //
        // Summary: 
        //  PreProcess the request.
        //  Handle the exceptions
        //
        protected override void PreProcessRequest() 
        {
            try 
            { 
                base.PreProcessRequest();
            } 
            catch( UIAgentInitializationException )
            {
                throw;
            } 
            catch( UserCancelledException )
            { 
                throw; 
            }
            catch( UntrustedRecipientException ) 
            {
                throw;
            }
            catch( UIAgentCrashedException ) 
            {
                throw new CommunicationException( SR.GetString( SR.UIAgentCrash ) ); 
            } 
            catch( InfoCardBaseException e )
            { 
                //
                // At this point we have set the UI to initialize mode,
                //  so it is showing the progress screen, but we have
                //  encountered an error during the processing of 
                //  input arguments.  We will signal to the UI that
                //  it should show this error, and wait for the ui to close. 
                //  once closed, we will re-throw the same exception to allow it 
                //  to return to the client.
                // 
                throw ShowError( e );
            }
        }
 

        // 
        // Summary: 
        //  Process the request.
        //  Handle the exceptions 
        //
        protected override void ProcessRequest()
        {
            try 
            {
                base.ProcessRequest(); 
            } 
            catch( UntrustedRecipientException )
            { 
                throw;
            }
            catch( UIAgentInitializationException )
            { 
                throw;
            } 
            catch( UserCancelledException ) 
            {
                throw; 
            }
            catch( UIAgentCrashedException )
            {
                throw new CommunicationException( SR.GetString( SR.UIAgentCrash ) ); 
            }
            catch( InfoCardBaseException e ) 
            { 
                //
                // At this point, we have caught an error that was not 
                //  a direct result of a ui operation.  We will display
                //  this error in the error dialog, then rethrow the exception
                //
                throw ShowError( e ); 
            }
        } 
 
        //
        // Summary: 
        //  PostProcess the request.
        //  Handle the exceptions
        //
        protected override void PostProcessRequest() 
        {
            try 
            { 
                base.PostProcessRequest();
            } 
            catch( InfoCardBaseException e )
            {
                //
                // At this point, we have already selected a token or doen our 
                //  our Ui work, and we are now attempting to marshal the return
                //  arguments back to the client, but an error occurred.  If this happens, 
                //  we will show the error over the shutting down progress page, and 
                //  then rethrow the error.
                // 
                throw ShowError( e );
            }
        }
 

 
        // 
        // Summary:
        //  Tells the UI agent to show the information of the specified exception to the user. 
        //
        // Returns:
        //  The exception that should be thrown to the client.
        // 
        protected Exception ShowError( Exception ex )
        { 
 
            //
            // If the agent is in the process of shutting down, there is no UI around to 
            // show the error on.
            //
            if( m_uiAgent.IsShuttingDown )
            { 
                return ex;
            } 
            // 
            // Capture the error for the agent.
            // 
            base.ProcessingException = ex;

            //
            // Reset any results we may have already recieved from the agent, as we will 
            //  need to wait for them again.
            // 
            m_uiAgent.ResetUIResult(); 

            // 
            // Show the ui.
            //
            RequestResult result = m_uiAgent.ShowUI( InfoCardUIAgent.CallMode.Error );
 
            //
            // If the user deciced in some way that the recipient is untrusted 
            //  we will discard the current processing exception, and throw 
            //  a new exception to indicate this.
            // 
            if( RequestResult.Untrusted == result )
            {
                ex = IDT.ThrowHelperError( new UntrustedRecipientException() );
            } 

            base.ProcessingException = null; 
            return ex; 
        }
 

        //
        // Summary:
        //  Start a UI Agent if necessary and assign it this reqeust object. 
        //  Wait till the UI Agent is done (i.e. Wait till user has finished interacting with the
        //  UI that is shown to satisfy the client UI request) 
        // 
        protected void StartAndWaitForUIAgent()
        { 
            //
            // Take a local lock so that when child requests start asking for UIAgent information we have it
            // ready for them before they get a null reference exception.
            // 
            RequestResult result = m_uiAgent.ShowUI( UIAgentMode );
            switch( result ) 
            { 
                case RequestResult.Ok:
                    { 
                        ;//Nothing to do here.
                    }
                    break;
                case RequestResult.Cancel: 
                case RequestResult.Error:
                    { 
                        // 
                        // If the UI ever returns the ERROR state, that means that
                        //  the UI had to terminate due to a screensaver, desktop switch, 
                        //  or some other reason in which it needs to exit the process to
                        //  release the desktop.  In this case, we return a cancel exception
                        //  to the client.  When we tear down, we will then tell the agent
                        //  to exit gracefully. 
                        //
                        throw IDT.ThrowHelperError( new UserCancelledException() ); 
                    } 
                case RequestResult.UICrashed:
                    { 
                        //
                        // NB: UIAgentCrashedException does NOT derive from InfoCardBaseException.
                        // We'll catch this and throw CommunicationException instead in *ProcessRequest().
                        // 
                        throw IDT.ThrowHelperError( new UIAgentCrashedException() );
                    } 
                case RequestResult.Untrusted: 
                    {
                        throw IDT.ThrowHelperError( new UntrustedRecipientException() ); 
                    }
                case RequestResult.UIFailedInitialization:
                    {
                        throw IDT.ThrowHelperError( new UIAgentInitializationException() ); 
                    }
                case RequestResult.Pending: 
                default: 
                    {
                        IDT.Assert( false, "We should never get Pending or invalid state here" ); 
                    }
                    break;

            } 
        }
 
 
        //
        // Summary: 
        //   Start the accessibility applications on the InfoCard desktop.
        //  The ATApplicationFlags parameter is used to indicate if AT Application
        //  support has really been enabled or if we are in this call because
        //  InfoCard is running on TabletPC. 
        //
        //  userATApplicationFlags - If set, AT applications are enabled. 
        // 
        public void StartAccessibilityApplications( uint userATApplicationFlags )
        { 
            if( null != m_uiAgent )
            {
                IDT.DebugAssert(
                    false == String.IsNullOrEmpty( m_uiAgent.DesktopName ), 
                    "Desktop name should be non-null" );
 
                IDT.DebugAssert( 0 != CallerPid, "CallerPid should not be zero" ); 

 
                string trustedUserSid = m_uiAgent.TrustedUserSid;

                m_atManager.RestartOnInfoCardDesktop(
                    userATApplicationFlags, 
                    m_uiAgent.TrustedUserToken,
                    ref trustedUserSid, 
                    "WinSta0\\" + m_uiAgent.DesktopName, 
                    m_uiAgent.TsSessionId,
                    CallerPid, 
                    this.RequestorIdentity );
            }
        }
 
        //
        // Summary: 
        //   Stop the AT apps on default desktop and start them on user desktop. 
        // Returns a bool value, if true agent needs to start AT apps.
        // 
        public bool RestartAccessibilityApplications()
        {
            m_atManager.Stop();
            return m_atManager.RestartOnUsersDesktop( CallerPid, @"WinSta0\Default", RequestorIdentity ); 
        }
 
        // 
        // Summary:
        //   Start the accessibility applications on the InfoCard desktop 
        //
        public void StopAccessibilityApplications()
        {
            m_atManager.Stop(); 
        }
 
 
        //
        // Summary: 
        //  Signals that the user has canceled the operation before the UI results are returned.
        //  This allows for local async operations to be canceled.
        //
        public void UserCancel( bool untrusted ) 
        {
            lock( SyncRoot ) 
            { 
                base.CancelServiceAsyncOperation( untrusted );
                OnUserCancel(); 
            }
        }

        // 
        // Summary:
        //  virtual Handler for UserCancel operatiions. 
        // 
        protected virtual void OnUserCancel()
        { 

        }

        // 
        // Summary:
        //  Releases the current UI agent. 
        // 
        void ReleaseUIAgent()
        { 
            lock( SyncRoot )
            {
                //
                // Any pending async requests (e.g. GetRecipientLogosAsyncRequest) 
                // must have been already cancelled by now.
                // 
                CheckIfAllAsyncOpsCompleted(); 

                StopAccessibilityApplications(); 

                if( null != m_uiAgent )
                {
                    m_uiAgent.ReleaseUI(); 
                    m_uiAgent.ClearRequest( this );
                    m_uiAgent = null; 
                } 
            }
        } 


        protected override void OnDisposeAsUser()
        { 
            base.OnDisposeAsUser();
 
            if( null != m_rootStoreReference ) 
            {
                m_rootStoreReference.Close(); 
                m_rootStoreReference = null;
            }
        }
 
        //
        // Summary: Free any resources held by this class. 
        // Be sure to call base.OnDisposeAsSystem before returning 
        // so that the base class has an opportunity to do its cleanup
        // 
        protected override void OnDisposeAsSystem()
        {
            if( null != m_uiAgentDone )
            { 
                m_uiAgentDone.Close();
                m_uiAgentDone = null; 
            } 

            // 
            // Capture the use info for after we revert.
            //
            RemoveAndDisposeContextMapping( RpcHandle );
 
            //
            // The agent must be released before calling the base class as the base class disposes of the caller 
            // process which is needed during the SendAgentStatusRequest which may be sent while releasing the 
            // agent.
            // 
            ReleaseUIAgent();

            //
            // Always call base.OnDispose before returning 
            //
            base.OnDisposeAsSystem(); 
        } 
    }
} 

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