TextServicesHost.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / TextServicesHost.cs / 1305600 / TextServicesHost.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: TextServicesHost implementation. 
//
// History: 
//  02/12/2004 : yutakas - created
//
//---------------------------------------------------------------------------
 
using System;
using System.Runtime.InteropServices; 
using System.Windows.Threading; 
using System.Threading;
using System.Collections; 
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Documents; 
using MS.Win32;
using MS.Internal; 
using MS.Internal.PresentationFramework;                   // SecurityHelper 
using System.Security;
using System.Security.Permissions; 

namespace System.Windows.Documents
{
    //----------------------------------------------------- 
    //
    //  TextServicesHost class 
    // 
    //-----------------------------------------------------
 
    //
    // This class manages registration of TextStore.
    // The instance of this class is per Dispatcher and can be shared by
    // all TextStore in same Dispatcher. 
    // The registration of TextStore does:
    //    - create DocumentManger for each TextStore. 
    //    - advise ThreadFocusSink and EditSink. 
    //
    // This activate ITfThreadMgr and keep the referrence of it. 
    // When Dispatcher is finished, ITfThreadMgr is deactivated and released.
    //
    internal class TextServicesHost : DispatcherObject
    { 
        //------------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        // Creates a new TextServicesHost instance. 
        internal TextServicesHost()
        { 
        } 

        #endregion Constructors 

        //------------------------------------------------------
        //
        //  Internal Method 
        //
        //------------------------------------------------------ 
 
        // TextStore calls this to register it and advise sink.
        ///  
        ///     Critical: This code accesses DocumentMgr,Source (inside of _RegisterTextStore)
        /// 
        [SecurityCritical]
        internal void RegisterTextStore(TextStore textstore) 
        {
            // VerifyAccess(); 
 
            Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA, "OnRegisterTextStore must be called on STA thread");
 
            // Register textstore and advise sinks.
            _RegisterTextStore((TextStore)textstore);

            _thread = Thread.CurrentThread; 
        }
 
        // Free all resources associated with a TextStore. 
        /// 
        ///     Critical: This code invokes OnUnregisterTextStore which is a Critical method. 
        /// 
        [SecurityCritical]
        internal void UnregisterTextStore(TextStore textstore, bool finalizer)
        { 
            if (!finalizer)
            { 
                OnUnregisterTextStore(textstore); 
            }
            else 
            {
                // GC Finalizer is detaching TextStore and the dispatcher thread could be already
                // terminated or Dispatcher is already finished.
                if (!_isDispatcherShutdownFinished) 
                {
                    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(OnUnregisterTextStore), textstore); 
                } 
            }
        } 

        /// 
        ///    Critical: This code calls into native code.
        ///  
        [SecurityCritical]
        internal void RegisterWinEventSink(TextStore textstore) 
        { 
            // Start WinEvent hook to listen windows move/size event.
            // We need to call ITextStoreACPSink::OnLayoutChange() whenever the window is moved. 
            if (_winEvent == null)
            {
                _winEvent = new MoveSizeWinEventHandler();
                _winEvent.Start(); 
            }
 
            _winEvent.RegisterTextStore(textstore); 
        }
 
        /// 
        ///    Critical: This code calls into native code.
        /// 
        [SecurityCritical] 
        internal void UnregisterWinEventSink(TextStore textstore)
        { 
            _winEvent.UnregisterTextStore(textstore); 

            // If the registerd text store count is 0, we don't need WinEvent hook any more. 
            if (_winEvent.TextStoreCount == 0)
            {
                _winEvent.Stop();
                _winEvent.Clear(); 
                _winEvent = null;
            } 
        } 

        // Start the transitory extestion for Cicero Level1/Level2 composition window support. 
        /// 
        ///    Critical: This code calls into ITfCompartmentMgr and ItfCompartment both of which are critical
        /// 
        [SecurityCritical] 
        internal static void StartTransitoryExtension(TextStore textstore)
        { 
            Guid guid; 
            Object var;
            UnsafeNativeMethods.ITfCompartmentMgr compmgr; 
            UnsafeNativeMethods.ITfCompartment comp;
            UnsafeNativeMethods.ITfSource source;
            int transitoryExtensionSinkCookie;
 
            // Start TransitryExtension
            compmgr = textstore.DocumentManager as UnsafeNativeMethods.ITfCompartmentMgr; 
 
            // Set GUID_COMPARTMENT_TRANSITORYEXTENSION
            guid = UnsafeNativeMethods.GUID_COMPARTMENT_TRANSITORYEXTENSION; 
            compmgr.GetCompartment(ref guid, out comp);
            var = (int)2; // Use level 2
            comp.SetValue(0, ref var);
 
            // Advise TransitoryExtension Sink and store the cookie.
            guid = UnsafeNativeMethods.IID_ITfTransitoryExtensionSink; 
            source = textstore.DocumentManager as UnsafeNativeMethods.ITfSource; 
            if (source != null)
            { 
                // DocumentManager only supports ITfSource on Longhorn, XP does not support it
                source.AdviseSink(ref guid, textstore, out transitoryExtensionSinkCookie);
                textstore.TransitoryExtensionSinkCookie = transitoryExtensionSinkCookie;
            } 

            Marshal.ReleaseComObject(comp); 
        } 

        // Stop TransitoryExtesion 
        /// 
        ///    Critical: This code calls into ITfCompartmentMgr and ItfCompartment both of which are critical
        /// 
        [SecurityCritical] 
        internal static void StopTransitoryExtension(TextStore textstore)
        { 
            Guid guid; 
            Object var;
            UnsafeNativeMethods.ITfCompartmentMgr compmgr; 
            UnsafeNativeMethods.ITfCompartment comp;

            compmgr = textstore.DocumentManager as UnsafeNativeMethods.ITfCompartmentMgr;
 
            // Unadvice the transitory extension sink.
            if (textstore.TransitoryExtensionSinkCookie != UnsafeNativeMethods.TF_INVALID_COOKIE) 
            { 
                UnsafeNativeMethods.ITfSource source;
                source = textstore.DocumentManager as UnsafeNativeMethods.ITfSource; 
                if (source != null)
                {
                    // DocumentManager only supports ITfSource on Longhorn, XP does not support it
                    source.UnadviseSink(textstore.TransitoryExtensionSinkCookie); 
                }
                textstore.TransitoryExtensionSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; 
            } 

            // Reset GUID_COMPARTMENT_TRANSITORYEXTENSION 
            guid = UnsafeNativeMethods.GUID_COMPARTMENT_TRANSITORYEXTENSION;
            compmgr.GetCompartment(ref guid, out comp);
            var = (int)0;
            comp.SetValue(0, ref var); 

            Marshal.ReleaseComObject(comp); 
        } 

        //----------------------------------------------------- 
        //
        //  Internal Properties
        //
        //------------------------------------------------------ 

        // Return the text services host associated with the current Dispatcher. 
        internal static TextServicesHost Current 
        {
            get 
            {
                TextEditorThreadLocalStore threadLocalStore = TextEditor._ThreadLocalStore;

                if (threadLocalStore.TextServicesHost == null) 
                {
                    threadLocalStore.TextServicesHost = new TextServicesHost(); 
                } 

                return threadLocalStore.TextServicesHost; 
            }
        }

 
        // Return ITfThreadMgr
        ///  
        ///     Critical: UnsafeNativeMethods.ITfThreadMgr has methods with SuppressUnmanagedCodeSecurity. 
        /// 
        internal UnsafeNativeMethods.ITfThreadMgr ThreadManager 
        {
            [SecurityCritical]
            get
            { 
                if (_threadManager == null)
                { 
                    return null; 
                }
 
                return _threadManager.Value;
            }
        }
 
        //-----------------------------------------------------
        // 
        //  Private Method 
        //
        //----------------------------------------------------- 

        #region Private Method

        // This is a callback in the dispacher thread to unregister TextStore. 
        /// 
        /// Critical - As this calls methods on ITfContext, ItfSource and ITfDocumentMgr 
        ///            under elevation to unregister the text source. 
        /// 
        [SecurityCritical] 
        private object OnUnregisterTextStore(object arg)
        {
            UnsafeNativeMethods.ITfContext context;
            UnsafeNativeMethods.ITfSource source; 

            if ((_threadManager == null) || (_threadManager.Value == null)) 
            { 
                return null;
            } 

            SecurityPermission secperm = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
            TextStore textstore = (TextStore)arg;
 
            // We don't have to release Dispatcher.
            // These Cicero COM calls could be marshalled when UnregisterTextStore is called from 
            // TextEditor's Finalizer through TextStore.OnDetach. GC Thread does not take Dispatcher. 
            if (textstore.ThreadFocusCookie != UnsafeNativeMethods.TF_INVALID_COOKIE)
            { 
                source = _threadManager.Value as UnsafeNativeMethods.ITfSource;
                source.UnadviseSink(textstore.ThreadFocusCookie);
                textstore.ThreadFocusCookie = UnsafeNativeMethods.TF_INVALID_COOKIE;
            } 

            textstore.DocumentManager.GetBase(out context); 
            if (context != null) 
            {
                if (textstore.EditSinkCookie != UnsafeNativeMethods.TF_INVALID_COOKIE) 
                {
                    source = context as UnsafeNativeMethods.ITfSource;
                    source.UnadviseSink(textstore.EditSinkCookie);
                    textstore.EditSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; 
                }
                Marshal.ReleaseComObject(context); 
            } 

            secperm.Assert(); 
            try
            {
                textstore.DocumentManager.Pop(UnsafeNativeMethods.PopFlags.TF_POPF_ALL);
            } 
            finally
            { 
                SecurityPermission.RevertAssert(); 
            }
            Marshal.ReleaseComObject(textstore.DocumentManager); 
            textstore.DocumentManager = null;

            Debug.Assert(_registeredtextstorecount > 0, "Overrelease TextStore!");
            _registeredtextstorecount--; 

            // If Dispatcher is finished and the last textstore 
            // is unregistered, we don't need ThreadManager any more. Deactivate and release it. 
            // We keep ThreadManager active as long as Dispatcher is alive even if
            // _registeredtextstorecount is 0. 
            if (_isDispatcherShutdownFinished && (_registeredtextstorecount == 0))
            {
                DeactivateThreadManager();
            } 

            return null; 
        } 

        // This is a callback when Dispatcher is finished. 
        /// 
        ///     Critical: This code diactivate thread manager.
        /// 
        [SecurityCritical] 
        private void OnDispatcherShutdownFinished(object sender, EventArgs args)
        { 
            Debug.Assert(CheckAccess(), "OnDispatcherShutdownFinished called on bad thread!"); 
            Debug.Assert(_isDispatcherShutdownFinished == false, "Was this dispather finished???");
 
            // Remove the callback.
            Dispatcher.ShutdownFinished -= new EventHandler(OnDispatcherShutdownFinished);

            // Deactivate and release the ThreadManager if no more TextStore is registered. 
            if (_registeredtextstorecount == 0)
            { 
                DeactivateThreadManager(); 
            }
 
            // We keep _dispatcherThread even Dispatcher is being finished. Because
            // this TextServicesHost won't be reused and we want to check if the thread is alive.
            _isDispatcherShutdownFinished = true;
        } 

        // Activate TIM if it is not activated yet by this TextServicesHost. 
        // And advise sinks for the given textstore. 
        /// 
        ///     Critical: This code accesses DocumentMgr,Source 
        /// 
        [SecurityCritical]
        private void _RegisterTextStore(TextStore textstore)
        { 
            UnsafeNativeMethods.ITfDocumentMgr doc;
            UnsafeNativeMethods.ITfContext context; 
            UnsafeNativeMethods.ITfSource source; 
            int editCookie = UnsafeNativeMethods.TF_INVALID_COOKIE;
            int threadFocusCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; 
            int editSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE;
            Guid guid;

            Debug.Assert(CheckAccess(), "RegisterTextStore called on bad thread!"); 

            // Get ITfThreadMgr 
            if (_threadManager == null) 
            {
                Debug.Assert(_isDispatcherShutdownFinished == false, "Was this dispather finished?"); 
                Debug.Assert(_registeredtextstorecount == 0, "TextStore was registered without ThreadMgr?");

                // TextServicesLoader.Load() might return null if no text services are installed or enabled.
                _threadManager = new SecurityCriticalDataClass(TextServicesLoader.Load()); 

                if (_threadManager.Value == null) 
                { 
                    _threadManager = null;
                    return; 
                }

                // Activate TSF on this thread if this is the first TextStore.
                int clientIdTemp; 
                _threadManager.Value.Activate(out clientIdTemp);
                _clientId = new SecurityCriticalData(clientIdTemp); 
 
                // We want to get the notification when Dispatcher is finished.
                Dispatcher.ShutdownFinished += new EventHandler(OnDispatcherShutdownFinished); 
            }

            // Create a TSF document.
            _threadManager.Value.CreateDocumentMgr(out doc); 
            doc.CreateContext(_clientId.Value, 0 /* flags */, textstore, out context, out editCookie);
            doc.Push(context); 
 
            // Attach a thread focus sink.
            if (textstore is UnsafeNativeMethods.ITfThreadFocusSink) 
            {
                guid = UnsafeNativeMethods.IID_ITfThreadFocusSink;
                source = _threadManager.Value as UnsafeNativeMethods.ITfSource;
                source.AdviseSink(ref guid, textstore, out threadFocusCookie); 
            }
 
            // Attach an edit sink. 
            if (textstore is UnsafeNativeMethods.ITfTextEditSink)
            { 
                guid = UnsafeNativeMethods.IID_ITfTextEditSink;
                source = context as UnsafeNativeMethods.ITfSource;
                source.AdviseSink(ref guid, textstore, out editSinkCookie);
            } 

            // Release any native resources we're done with. 
            Marshal.ReleaseComObject(context); 

            textstore.DocumentManager = doc; 
            textstore.ThreadFocusCookie = threadFocusCookie;
            textstore.EditSinkCookie = editSinkCookie;
            textstore.EditCookie = editCookie;
 
            // If Scope of this textstore already has a focus, we need to call SetFocus()
            // in order to put this DIM on Cicero's focus. TextStore.OnGotFocus() calls 
            // ITfThreadMgr::SetFocus(); 
            if (textstore.UiScope.IsKeyboardFocused)
            { 
                textstore.OnGotFocus();
            }

            _registeredtextstorecount++; 
        }
 
        // Deactivate and release ThreadManager. 
        /// 
        ///     Critical: This code deactivate ThreadManager by accessing ITfThreadMgr 
        /// 
        [SecurityCritical]
        private void DeactivateThreadManager()
        { 
            if (_threadManager != null)
            { 
                if (_threadManager.Value != null) 
                {
                    // On XP, if we're called on a worker thread (during AppDomain shutdown) 
                    // we can't call call any methods on _threadManager.  The problem is
                    // that there's no proxy registered for ITfThreadMgr on OS versions
                    // previous to Vista.  Not calling Deactivate will leak the IMEs, but
                    // in practice (1) they're singletons, so it's not unbounded; and (2) 
                    // most applications will share the thread with other AppDomains that
                    // have a UI, in which case the IME won't be released until the process 
                    // shuts down in any case.  In theory we could also work around this 
                    // problem by creating our own XP proxy/stub implementation, which would
                    // be added to WPF setup.... 
                    if (_thread == Thread.CurrentThread || System.Environment.OSVersion.Version.Major >= 6)
                    {
                        _threadManager.Value.Deactivate();
                    } 
                    Marshal.ReleaseComObject(_threadManager.Value);
                } 
                _threadManager = null; 
            }
 
            // ThreadManager was deactivated. It is time to release this TextServicesHost.
            TextEditorThreadLocalStore threadLocalStore = TextEditor._ThreadLocalStore;
            threadLocalStore.TextServicesHost = null;
 
        }
 
        #endregion Private Method 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //------------------------------------------------------ 

        #region Private Fields 
 
        // Number of the registered TextStore.
        private int _registeredtextstorecount; 

        // TSF ClientId from Activate call.
        /// 
        ///     Critical: _clientId is an identifier for Cicero. 
        /// 
        private SecurityCriticalData _clientId; 
 
        // The root TSF object, created on demand.
        ///  
        ///     Critical: UnsafeNativeMethods.ITfThreadMgr has methods with SuppressUnmanagedCodeSecurity.
        /// 
        private SecurityCriticalDataClass _threadManager;
 
        // This is true if Dispatcher is finished.
        private bool _isDispatcherShutdownFinished; 
 
        // WinEvent handler for windows move/size.
        private MoveSizeWinEventHandler _winEvent; 

        // Thread this host has affinity for.
        private Thread _thread;
 
        #endregion Private Fields
 
    } 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: TextServicesHost implementation. 
//
// History: 
//  02/12/2004 : yutakas - created
//
//---------------------------------------------------------------------------
 
using System;
using System.Runtime.InteropServices; 
using System.Windows.Threading; 
using System.Threading;
using System.Collections; 
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Documents; 
using MS.Win32;
using MS.Internal; 
using MS.Internal.PresentationFramework;                   // SecurityHelper 
using System.Security;
using System.Security.Permissions; 

namespace System.Windows.Documents
{
    //----------------------------------------------------- 
    //
    //  TextServicesHost class 
    // 
    //-----------------------------------------------------
 
    //
    // This class manages registration of TextStore.
    // The instance of this class is per Dispatcher and can be shared by
    // all TextStore in same Dispatcher. 
    // The registration of TextStore does:
    //    - create DocumentManger for each TextStore. 
    //    - advise ThreadFocusSink and EditSink. 
    //
    // This activate ITfThreadMgr and keep the referrence of it. 
    // When Dispatcher is finished, ITfThreadMgr is deactivated and released.
    //
    internal class TextServicesHost : DispatcherObject
    { 
        //------------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        // Creates a new TextServicesHost instance. 
        internal TextServicesHost()
        { 
        } 

        #endregion Constructors 

        //------------------------------------------------------
        //
        //  Internal Method 
        //
        //------------------------------------------------------ 
 
        // TextStore calls this to register it and advise sink.
        ///  
        ///     Critical: This code accesses DocumentMgr,Source (inside of _RegisterTextStore)
        /// 
        [SecurityCritical]
        internal void RegisterTextStore(TextStore textstore) 
        {
            // VerifyAccess(); 
 
            Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA, "OnRegisterTextStore must be called on STA thread");
 
            // Register textstore and advise sinks.
            _RegisterTextStore((TextStore)textstore);

            _thread = Thread.CurrentThread; 
        }
 
        // Free all resources associated with a TextStore. 
        /// 
        ///     Critical: This code invokes OnUnregisterTextStore which is a Critical method. 
        /// 
        [SecurityCritical]
        internal void UnregisterTextStore(TextStore textstore, bool finalizer)
        { 
            if (!finalizer)
            { 
                OnUnregisterTextStore(textstore); 
            }
            else 
            {
                // GC Finalizer is detaching TextStore and the dispatcher thread could be already
                // terminated or Dispatcher is already finished.
                if (!_isDispatcherShutdownFinished) 
                {
                    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(OnUnregisterTextStore), textstore); 
                } 
            }
        } 

        /// 
        ///    Critical: This code calls into native code.
        ///  
        [SecurityCritical]
        internal void RegisterWinEventSink(TextStore textstore) 
        { 
            // Start WinEvent hook to listen windows move/size event.
            // We need to call ITextStoreACPSink::OnLayoutChange() whenever the window is moved. 
            if (_winEvent == null)
            {
                _winEvent = new MoveSizeWinEventHandler();
                _winEvent.Start(); 
            }
 
            _winEvent.RegisterTextStore(textstore); 
        }
 
        /// 
        ///    Critical: This code calls into native code.
        /// 
        [SecurityCritical] 
        internal void UnregisterWinEventSink(TextStore textstore)
        { 
            _winEvent.UnregisterTextStore(textstore); 

            // If the registerd text store count is 0, we don't need WinEvent hook any more. 
            if (_winEvent.TextStoreCount == 0)
            {
                _winEvent.Stop();
                _winEvent.Clear(); 
                _winEvent = null;
            } 
        } 

        // Start the transitory extestion for Cicero Level1/Level2 composition window support. 
        /// 
        ///    Critical: This code calls into ITfCompartmentMgr and ItfCompartment both of which are critical
        /// 
        [SecurityCritical] 
        internal static void StartTransitoryExtension(TextStore textstore)
        { 
            Guid guid; 
            Object var;
            UnsafeNativeMethods.ITfCompartmentMgr compmgr; 
            UnsafeNativeMethods.ITfCompartment comp;
            UnsafeNativeMethods.ITfSource source;
            int transitoryExtensionSinkCookie;
 
            // Start TransitryExtension
            compmgr = textstore.DocumentManager as UnsafeNativeMethods.ITfCompartmentMgr; 
 
            // Set GUID_COMPARTMENT_TRANSITORYEXTENSION
            guid = UnsafeNativeMethods.GUID_COMPARTMENT_TRANSITORYEXTENSION; 
            compmgr.GetCompartment(ref guid, out comp);
            var = (int)2; // Use level 2
            comp.SetValue(0, ref var);
 
            // Advise TransitoryExtension Sink and store the cookie.
            guid = UnsafeNativeMethods.IID_ITfTransitoryExtensionSink; 
            source = textstore.DocumentManager as UnsafeNativeMethods.ITfSource; 
            if (source != null)
            { 
                // DocumentManager only supports ITfSource on Longhorn, XP does not support it
                source.AdviseSink(ref guid, textstore, out transitoryExtensionSinkCookie);
                textstore.TransitoryExtensionSinkCookie = transitoryExtensionSinkCookie;
            } 

            Marshal.ReleaseComObject(comp); 
        } 

        // Stop TransitoryExtesion 
        /// 
        ///    Critical: This code calls into ITfCompartmentMgr and ItfCompartment both of which are critical
        /// 
        [SecurityCritical] 
        internal static void StopTransitoryExtension(TextStore textstore)
        { 
            Guid guid; 
            Object var;
            UnsafeNativeMethods.ITfCompartmentMgr compmgr; 
            UnsafeNativeMethods.ITfCompartment comp;

            compmgr = textstore.DocumentManager as UnsafeNativeMethods.ITfCompartmentMgr;
 
            // Unadvice the transitory extension sink.
            if (textstore.TransitoryExtensionSinkCookie != UnsafeNativeMethods.TF_INVALID_COOKIE) 
            { 
                UnsafeNativeMethods.ITfSource source;
                source = textstore.DocumentManager as UnsafeNativeMethods.ITfSource; 
                if (source != null)
                {
                    // DocumentManager only supports ITfSource on Longhorn, XP does not support it
                    source.UnadviseSink(textstore.TransitoryExtensionSinkCookie); 
                }
                textstore.TransitoryExtensionSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; 
            } 

            // Reset GUID_COMPARTMENT_TRANSITORYEXTENSION 
            guid = UnsafeNativeMethods.GUID_COMPARTMENT_TRANSITORYEXTENSION;
            compmgr.GetCompartment(ref guid, out comp);
            var = (int)0;
            comp.SetValue(0, ref var); 

            Marshal.ReleaseComObject(comp); 
        } 

        //----------------------------------------------------- 
        //
        //  Internal Properties
        //
        //------------------------------------------------------ 

        // Return the text services host associated with the current Dispatcher. 
        internal static TextServicesHost Current 
        {
            get 
            {
                TextEditorThreadLocalStore threadLocalStore = TextEditor._ThreadLocalStore;

                if (threadLocalStore.TextServicesHost == null) 
                {
                    threadLocalStore.TextServicesHost = new TextServicesHost(); 
                } 

                return threadLocalStore.TextServicesHost; 
            }
        }

 
        // Return ITfThreadMgr
        ///  
        ///     Critical: UnsafeNativeMethods.ITfThreadMgr has methods with SuppressUnmanagedCodeSecurity. 
        /// 
        internal UnsafeNativeMethods.ITfThreadMgr ThreadManager 
        {
            [SecurityCritical]
            get
            { 
                if (_threadManager == null)
                { 
                    return null; 
                }
 
                return _threadManager.Value;
            }
        }
 
        //-----------------------------------------------------
        // 
        //  Private Method 
        //
        //----------------------------------------------------- 

        #region Private Method

        // This is a callback in the dispacher thread to unregister TextStore. 
        /// 
        /// Critical - As this calls methods on ITfContext, ItfSource and ITfDocumentMgr 
        ///            under elevation to unregister the text source. 
        /// 
        [SecurityCritical] 
        private object OnUnregisterTextStore(object arg)
        {
            UnsafeNativeMethods.ITfContext context;
            UnsafeNativeMethods.ITfSource source; 

            if ((_threadManager == null) || (_threadManager.Value == null)) 
            { 
                return null;
            } 

            SecurityPermission secperm = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
            TextStore textstore = (TextStore)arg;
 
            // We don't have to release Dispatcher.
            // These Cicero COM calls could be marshalled when UnregisterTextStore is called from 
            // TextEditor's Finalizer through TextStore.OnDetach. GC Thread does not take Dispatcher. 
            if (textstore.ThreadFocusCookie != UnsafeNativeMethods.TF_INVALID_COOKIE)
            { 
                source = _threadManager.Value as UnsafeNativeMethods.ITfSource;
                source.UnadviseSink(textstore.ThreadFocusCookie);
                textstore.ThreadFocusCookie = UnsafeNativeMethods.TF_INVALID_COOKIE;
            } 

            textstore.DocumentManager.GetBase(out context); 
            if (context != null) 
            {
                if (textstore.EditSinkCookie != UnsafeNativeMethods.TF_INVALID_COOKIE) 
                {
                    source = context as UnsafeNativeMethods.ITfSource;
                    source.UnadviseSink(textstore.EditSinkCookie);
                    textstore.EditSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; 
                }
                Marshal.ReleaseComObject(context); 
            } 

            secperm.Assert(); 
            try
            {
                textstore.DocumentManager.Pop(UnsafeNativeMethods.PopFlags.TF_POPF_ALL);
            } 
            finally
            { 
                SecurityPermission.RevertAssert(); 
            }
            Marshal.ReleaseComObject(textstore.DocumentManager); 
            textstore.DocumentManager = null;

            Debug.Assert(_registeredtextstorecount > 0, "Overrelease TextStore!");
            _registeredtextstorecount--; 

            // If Dispatcher is finished and the last textstore 
            // is unregistered, we don't need ThreadManager any more. Deactivate and release it. 
            // We keep ThreadManager active as long as Dispatcher is alive even if
            // _registeredtextstorecount is 0. 
            if (_isDispatcherShutdownFinished && (_registeredtextstorecount == 0))
            {
                DeactivateThreadManager();
            } 

            return null; 
        } 

        // This is a callback when Dispatcher is finished. 
        /// 
        ///     Critical: This code diactivate thread manager.
        /// 
        [SecurityCritical] 
        private void OnDispatcherShutdownFinished(object sender, EventArgs args)
        { 
            Debug.Assert(CheckAccess(), "OnDispatcherShutdownFinished called on bad thread!"); 
            Debug.Assert(_isDispatcherShutdownFinished == false, "Was this dispather finished???");
 
            // Remove the callback.
            Dispatcher.ShutdownFinished -= new EventHandler(OnDispatcherShutdownFinished);

            // Deactivate and release the ThreadManager if no more TextStore is registered. 
            if (_registeredtextstorecount == 0)
            { 
                DeactivateThreadManager(); 
            }
 
            // We keep _dispatcherThread even Dispatcher is being finished. Because
            // this TextServicesHost won't be reused and we want to check if the thread is alive.
            _isDispatcherShutdownFinished = true;
        } 

        // Activate TIM if it is not activated yet by this TextServicesHost. 
        // And advise sinks for the given textstore. 
        /// 
        ///     Critical: This code accesses DocumentMgr,Source 
        /// 
        [SecurityCritical]
        private void _RegisterTextStore(TextStore textstore)
        { 
            UnsafeNativeMethods.ITfDocumentMgr doc;
            UnsafeNativeMethods.ITfContext context; 
            UnsafeNativeMethods.ITfSource source; 
            int editCookie = UnsafeNativeMethods.TF_INVALID_COOKIE;
            int threadFocusCookie = UnsafeNativeMethods.TF_INVALID_COOKIE; 
            int editSinkCookie = UnsafeNativeMethods.TF_INVALID_COOKIE;
            Guid guid;

            Debug.Assert(CheckAccess(), "RegisterTextStore called on bad thread!"); 

            // Get ITfThreadMgr 
            if (_threadManager == null) 
            {
                Debug.Assert(_isDispatcherShutdownFinished == false, "Was this dispather finished?"); 
                Debug.Assert(_registeredtextstorecount == 0, "TextStore was registered without ThreadMgr?");

                // TextServicesLoader.Load() might return null if no text services are installed or enabled.
                _threadManager = new SecurityCriticalDataClass(TextServicesLoader.Load()); 

                if (_threadManager.Value == null) 
                { 
                    _threadManager = null;
                    return; 
                }

                // Activate TSF on this thread if this is the first TextStore.
                int clientIdTemp; 
                _threadManager.Value.Activate(out clientIdTemp);
                _clientId = new SecurityCriticalData(clientIdTemp); 
 
                // We want to get the notification when Dispatcher is finished.
                Dispatcher.ShutdownFinished += new EventHandler(OnDispatcherShutdownFinished); 
            }

            // Create a TSF document.
            _threadManager.Value.CreateDocumentMgr(out doc); 
            doc.CreateContext(_clientId.Value, 0 /* flags */, textstore, out context, out editCookie);
            doc.Push(context); 
 
            // Attach a thread focus sink.
            if (textstore is UnsafeNativeMethods.ITfThreadFocusSink) 
            {
                guid = UnsafeNativeMethods.IID_ITfThreadFocusSink;
                source = _threadManager.Value as UnsafeNativeMethods.ITfSource;
                source.AdviseSink(ref guid, textstore, out threadFocusCookie); 
            }
 
            // Attach an edit sink. 
            if (textstore is UnsafeNativeMethods.ITfTextEditSink)
            { 
                guid = UnsafeNativeMethods.IID_ITfTextEditSink;
                source = context as UnsafeNativeMethods.ITfSource;
                source.AdviseSink(ref guid, textstore, out editSinkCookie);
            } 

            // Release any native resources we're done with. 
            Marshal.ReleaseComObject(context); 

            textstore.DocumentManager = doc; 
            textstore.ThreadFocusCookie = threadFocusCookie;
            textstore.EditSinkCookie = editSinkCookie;
            textstore.EditCookie = editCookie;
 
            // If Scope of this textstore already has a focus, we need to call SetFocus()
            // in order to put this DIM on Cicero's focus. TextStore.OnGotFocus() calls 
            // ITfThreadMgr::SetFocus(); 
            if (textstore.UiScope.IsKeyboardFocused)
            { 
                textstore.OnGotFocus();
            }

            _registeredtextstorecount++; 
        }
 
        // Deactivate and release ThreadManager. 
        /// 
        ///     Critical: This code deactivate ThreadManager by accessing ITfThreadMgr 
        /// 
        [SecurityCritical]
        private void DeactivateThreadManager()
        { 
            if (_threadManager != null)
            { 
                if (_threadManager.Value != null) 
                {
                    // On XP, if we're called on a worker thread (during AppDomain shutdown) 
                    // we can't call call any methods on _threadManager.  The problem is
                    // that there's no proxy registered for ITfThreadMgr on OS versions
                    // previous to Vista.  Not calling Deactivate will leak the IMEs, but
                    // in practice (1) they're singletons, so it's not unbounded; and (2) 
                    // most applications will share the thread with other AppDomains that
                    // have a UI, in which case the IME won't be released until the process 
                    // shuts down in any case.  In theory we could also work around this 
                    // problem by creating our own XP proxy/stub implementation, which would
                    // be added to WPF setup.... 
                    if (_thread == Thread.CurrentThread || System.Environment.OSVersion.Version.Major >= 6)
                    {
                        _threadManager.Value.Deactivate();
                    } 
                    Marshal.ReleaseComObject(_threadManager.Value);
                } 
                _threadManager = null; 
            }
 
            // ThreadManager was deactivated. It is time to release this TextServicesHost.
            TextEditorThreadLocalStore threadLocalStore = TextEditor._ThreadLocalStore;
            threadLocalStore.TextServicesHost = null;
 
        }
 
        #endregion Private Method 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //------------------------------------------------------ 

        #region Private Fields 
 
        // Number of the registered TextStore.
        private int _registeredtextstorecount; 

        // TSF ClientId from Activate call.
        /// 
        ///     Critical: _clientId is an identifier for Cicero. 
        /// 
        private SecurityCriticalData _clientId; 
 
        // The root TSF object, created on demand.
        ///  
        ///     Critical: UnsafeNativeMethods.ITfThreadMgr has methods with SuppressUnmanagedCodeSecurity.
        /// 
        private SecurityCriticalDataClass _threadManager;
 
        // This is true if Dispatcher is finished.
        private bool _isDispatcherShutdownFinished; 
 
        // WinEvent handler for windows move/size.
        private MoveSizeWinEventHandler _winEvent; 

        // Thread this host has affinity for.
        private Thread _thread;
 
        #endregion Private Fields
 
    } 

} 

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