Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / PtsHost / PtsContext.cs / 1 / PtsContext.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: PtsContext.cs // // Description: Context used to communicate with PTS component. // //--------------------------------------------------------------------------- using System; // IntPtr, IDisposable, ... using System.Collections; // ArrayList using System.Collections.Generic; // Listusing System.Security; // SecurityCritical, SecurityTreatAsSafe using System.Threading; // Interlocked using System.Windows.Media.TextFormatting; // TextFormatter using System.Windows.Threading; // DispatcherObject using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS namespace MS.Internal.PtsHost { /// /// Context used to communicate with PTS component. /// Context keeps track of all unmanaged resources created by PTS. /// It also maps an instance of Object into an identity that can be used /// in unmanaged world. This identity can by easily mapped back into /// original instance of Object. /// internal sealed class PtsContext : DispatcherObject, IDisposable { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Constructor. /// ////// The array of entries initially can store up to 16 entries. Upon /// adding elements the capacity increased in multiples of two as /// required. The first element always contains index to the next /// free entry. All free entries are forming a linked list. /// ////// Critical, because allocates Critical collections: _pages, and _pageBreakRecords. /// Safe, because creating empty collections is safe. /// [SecurityCritical, SecurityTreatAsSafe] internal PtsContext(bool isOptimalParagraphEnabled) { _pages = new ArrayList(1); _pageBreakRecords = new ArrayList(1); _unmanagedHandles = new HandleIndex[_defaultHandlesCapacity]; // Limit initial size _isOptimalParagraphEnabled = isOptimalParagraphEnabled; BuildFreeList(1); // 1 is the first free index in UnmanagedHandles array // Acquire PTS Context _ptsHost = PtsCache.AcquireContext(this); } #endregion Constructors //-------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Destroy all unmanaged resources associated with the PtsContext. /// ////// Critical, because calls Critical functions PTS.FsDestroyPageBreakRecord /// and PTS.FsDestroyPage. /// Safe, because parameters passed to PTS.FsDestroyPageBreakRecord /// and PTS.FsDestroyPage are Critical for set, so cannot have /// randomly assigned value. /// [SecurityCritical, SecurityTreatAsSafe] public void Dispose() { int index; // Do actual dispose only once. if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 0) { // Destroy all page break records. The collection is allocated during creation // of the context, and can be only destroyed during dispose process. // It is necessary to enter PTS Context when executing any PTS methods. try { Enter(); for (index = 0; index < _pageBreakRecords.Count; index++) { Invariant.Assert(((IntPtr)_pageBreakRecords[index]) != IntPtr.Zero, "Invalid break record object"); PTS.Validate(PTS.FsDestroyPageBreakRecord(_ptsHost.Context, (IntPtr)_pageBreakRecords[index])); } } finally { Leave(); _pageBreakRecords = null; } // Destroy all pages. The collection is allocated during creation // of the context, and can be only destroyed during dispose process. // It is necessary to enter PTS Context when executing any PTS methods. try { Enter(); for (index = 0; index < _pages.Count; index++) { Invariant.Assert(((IntPtr)_pages[index]) != IntPtr.Zero, "Invalid break record object"); PTS.Validate(PTS.FsDestroyPage(_ptsHost.Context, (IntPtr)_pages[index])); } } finally { Leave(); _pages = null; } if (Invariant.Strict && _unmanagedHandles != null) { // Verify that PtsContext does not contain any reference to objects. // Because order of finalizers is not deterministic, only objects // that can be part of the NameTable are allowed here. for (index = 0; index < _unmanagedHandles.Length; ++index) { Object obj = _unmanagedHandles[index].Obj; if (obj != null) { Invariant.Assert( obj is BaseParagraph || obj is Section || obj is MS.Internal.PtsHost.LineBreakRecord, // Suppress line break record leak, looks like a PTS issue but we cannot // get a firm repro for now. Workaround for bug #1294210. "One of PTS Client objects is not properly disposed."); #if DEBUG // Make sure that FigureParagraphs are only used by TextParagraph if (obj is FigureParagraph || obj is FloaterParagraph) { bool found = false; for (int i = 0; i < _unmanagedHandles.Length; ++i) { Object objDbg = _unmanagedHandles[i].Obj; if (objDbg is TextParagraph) { ListattachedObjects = ((TextParagraph)objDbg).AttachedObjectDbg; if (attachedObjects != null) { foreach (AttachedObject attachedObject in attachedObjects) { if (attachedObject.Para == obj) { found = true; break; } } } if (found) { break; } } } Invariant.Assert(found, "FigureParagraph is not properly disposed."); } #endif } } } _ptsHost = null; _unmanagedHandles = null; _callbackException = null; _disposeCompleted = true; } } /// /// Inserts the object into reference array and returns its handle. /// /// Object to be mapped to an unmanaged handle. ///Unmanaged handle associated with the object. ////// Thread safe, see facts for the class description. /// internal IntPtr CreateHandle(object obj) { Invariant.Assert(obj != null, "Cannot create handle for non-existing object."); Invariant.Assert(!this.Disposed, "PtsContext is already disposed."); // Ensure the size of handle array. The first item of the // array contains index of the next free position. If this // index is 0, it means that the array is full and needs to // be resized. if (_unmanagedHandles[0].Index == 0) { Resize(); } // Assign a handle to the Object and adjust free index. int handle = _unmanagedHandles[0].Index; _unmanagedHandles[0].Index = _unmanagedHandles[handle].Index; _unmanagedHandles[handle].Obj = obj; _unmanagedHandles[handle].Index = 0; return (IntPtr)handle; } ////// Removes reference to the object pointed by handle and release /// the entry associated with it. /// /// Handle of an Object being removed. ////// Thread safe, see facts for the class description. /// internal void ReleaseHandle(IntPtr handle) { int handleInt = (int)handle; Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. Invariant.Assert(handleInt > 0 && handleInt < _unmanagedHandles.Length, "Invalid object handle."); Invariant.Assert(_unmanagedHandles[handleInt].IsHandle(), "Handle has been already released."); _unmanagedHandles[handleInt].Obj = null; _unmanagedHandles[handleInt].Index = _unmanagedHandles[0].Index; _unmanagedHandles[0].Index = handleInt; } ////// Returns true if IntPtr is a handle /// /// Handle of an Object. ////// Thread safe, see facts for the class description. /// internal bool IsValidHandle(IntPtr handle) { int handleInt = (int)handle; Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. if (handleInt < 0 || handleInt >= _unmanagedHandles.Length) { return false; } return _unmanagedHandles[handleInt].IsHandle(); } ////// Maps handle to an Object. /// /// Handle of an Object. ///Reference to an Object. ////// Thread safe, see facts for the class description. /// internal object HandleToObject(IntPtr handle) { int handleInt = (int)handle; Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. Invariant.Assert(handleInt > 0 && handleInt < _unmanagedHandles.Length, "Invalid object handle."); Invariant.Assert(_unmanagedHandles[handleInt].IsHandle(), "Handle has been already released."); return _unmanagedHandles[handleInt].Obj; } ////// Enters the PTS context. Called before executing PTS methods. /// ////// Thread safe, see facts for the class description. /// internal void Enter() { Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. _ptsHost.EnterContext(this); } ////// Leaves the PTS context. Called after executing PTS methods. /// ////// Thread safe, see facts for the class description. /// internal void Leave() { Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. _ptsHost.LeaveContext(this); } ////// Keeps track of created pages (unmanaged resource). /// When page is created, add it to the list. /// /// PTS Page object that was just created. ////// Critical, because adds new entry to Critical collection _pages. /// Safe, because ptsPage parameter is Critical for set, so cannot have /// randomly assigned value. /// [SecurityCritical, SecurityTreatAsSafe] internal void OnPageCreated(SecurityCriticalDataForSetptsPage) { Invariant.Assert(ptsPage.Value != IntPtr.Zero, "Invalid page object."); Invariant.Assert(!this.Disposed, "PtsContext is already disposed."); Invariant.Assert(!_pages.Contains(ptsPage.Value), "Page already exists."); _pages.Add(ptsPage.Value); } /// /// Destroys PTS page. /// /// Pointer to PTS Page object that should be destroyed. /// Whether dispose is caused by explicit call to Dispose. /// Whether needs to enter PtsContext or not (during layout it is not needed). internal void OnPageDisposed(SecurityCriticalDataForSetptsPage, bool disposing, bool enterContext) { Invariant.Assert(ptsPage.Value != IntPtr.Zero, "Invalid page object."); // If explicitly disposing (not called during finalization), synchronously // destroy the page. if (disposing) { OnDestroyPage(ptsPage, enterContext); } else { // If PtsContext has been already disposed, ignore this call. if (!this.Disposed && !this.Dispatcher.HasShutdownStarted) { // Schedule background operation to destroy the page. this.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(OnDestroyPage), ptsPage); } } } /// /// Keeps track of created page BreakRecords (unmanaged resource). /// When PageBreakRecord is created, add it to the list. /// /// PTS Page BR object that was just created. ////// Critical, because adds new entry to Critical collection _pageBreakRecords. /// Safe, because br parameter is Critical for set, so cannot have randomly assigned value. /// [SecurityCritical, SecurityTreatAsSafe] internal void OnPageBreakRecordCreated(SecurityCriticalDataForSetbr) { Invariant.Assert(br.Value != IntPtr.Zero, "Invalid break record object."); Invariant.Assert(!this.Disposed, "PtsContext is already disposed."); Invariant.Assert(!_pageBreakRecords.Contains(br.Value), "Break record already exists."); _pageBreakRecords.Add(br.Value); } /// /// Destroys PTS break record. /// /// Pointer to PTS Page BR object that should be destroyed. /// Whether dispose is caused by explicit call to Dispose. internal void OnPageBreakRecordDisposed(SecurityCriticalDataForSetbr, bool disposing) { Invariant.Assert(br.Value != IntPtr.Zero, "Invalid break record object."); // If explicitly disposing (not called during finalization), synchronously // destroy the page break record. if (disposing) { OnDestroyBreakRecord((object)br); } else { // If PtsContext has been already disposed, ignore this call. if (!this.Disposed && !this.Dispatcher.HasShutdownStarted) { // Schedule background operation to destroy the page. this.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(OnDestroyBreakRecord), br); } } } #endregion Internal Methods //-------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties /// /// Whether object is already disposed. /// internal bool Disposed { get { return (_disposed != 0); } } ////// Context Id used to communicate with PTS. /// internal IntPtr Context { get { return _ptsHost.Context; } } ////// Whether optimal paragraph is enabled /// internal bool IsOptimalParagraphEnabled { get { return _isOptimalParagraphEnabled; } } ////// Text formatter context for this pts context /// internal TextFormatter TextFormatter { get { return _textFormatter; } set { _textFormatter = value; } } ////// Exception caught during callback execution. Those exceptions are /// converted into error codes and passed to PTS to provide appropriate /// clenaup. Later this exception is re-thrown. /// internal Exception CallbackException { get { return _callbackException; } set { _callbackException = value; } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------- #region Private Methods ////// Rebuilds list of free entries starting from specified index. /// /// Index to start from. private void BuildFreeList(int freeIndex) { // Point to the first empty slot _unmanagedHandles[0].Index = freeIndex; // Link all entries starting from freeIndex while (freeIndex < _unmanagedHandles.Length) { _unmanagedHandles[freeIndex].Index = ++freeIndex; } // End of free entries list _unmanagedHandles[freeIndex - 1].Index = 0; } ////// Increases the capacity of the handle array. /// new size = current size * 2 /// private void Resize() { int freeIndex = _unmanagedHandles.Length; // Allocate new array and copy all existing entries into it HandleIndex[] newItems = new HandleIndex[_unmanagedHandles.Length * 2]; Array.Copy(_unmanagedHandles, newItems, _unmanagedHandles.Length); _unmanagedHandles = newItems; // Build list of free entries BuildFreeList(freeIndex); } ////// Destroys PTS page. /// /// Pointer to PTS Page object that should be destroyed. private object OnDestroyPage(object args) { SecurityCriticalDataForSetptsPage = (SecurityCriticalDataForSet )args; OnDestroyPage(ptsPage, true); return null; } /// /// Destroys PTS page. /// /// Pointer to PTS Page object that should be destroyed. /// Whether needs to enter PTS Context. ////// Critical, because: /// a) calls Critical functions PTS.FsDestroyPage, /// b) modifies Critical collection _pages /// Safe, because: /// a) parameter passed to PTS.FsDestroyPage is Critical /// for set, so cannot have randomly assigned value. /// b) removing from Critical collection is safe operation. /// [SecurityCritical, SecurityTreatAsSafe] private void OnDestroyPage(SecurityCriticalDataForSetptsPage, bool enterContext) { Invariant.Assert(ptsPage.Value != IntPtr.Zero, "Invalid page object."); // Dispatcher may invoke this operation when PtsContext is already explicitly // disposed. if (!this.Disposed) { Invariant.Assert(_pages != null, "Collection of pages does not exist."); Invariant.Assert(_pages.Contains(ptsPage.Value), "Page does not exist."); // Destroy given page. // It is necessary to enter PTS Context when executing any PTS methods. try { if (enterContext) { Enter(); } PTS.Validate(PTS.FsDestroyPage(_ptsHost.Context, ptsPage.Value)); } finally { if (enterContext) { Leave(); } _pages.Remove(ptsPage.Value); } } } /// /// Destroys PTS page break record. /// /// Pointer to PTS Page BreakRecord object that should be destroyed. ////// Critical, because: /// a) calls Critical functions PTS.FsDestroyPageBreakRecord, /// b) modifies Critical collection _pageBreakRecords /// Safe, because: /// a) parameter passed to PTS.FsDestroyPageBreakRecord is Critical /// for set, so cannot have randomly assigned value. /// b) removing from Critical collection is safe operation. /// [SecurityCritical, SecurityTreatAsSafe] private object OnDestroyBreakRecord(object args) { SecurityCriticalDataForSetbr = (SecurityCriticalDataForSet )args; Invariant.Assert(br.Value != IntPtr.Zero, "Invalid break record object."); // Dispatcher may invoke this operation when PtsContext is already explicitly // disposed. if (!this.Disposed) { Invariant.Assert(_pageBreakRecords != null, "Collection of break records does not exist."); Invariant.Assert(_pageBreakRecords.Contains(br.Value), "Break record does not exist."); // Destroy given page break record. // It is necessary to enter PTS Context when executing any PTS methods. try { Enter(); PTS.Validate(PTS.FsDestroyPageBreakRecord(_ptsHost.Context, br.Value)); } finally { Leave(); _pageBreakRecords.Remove(br.Value); } } return null; } #endregion Private Methods //------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields /// /// Array of HandleIndex. This array stores 2 kind of information: /// {1) reference to Object; array index is a handle of the Object, /// (2) linked list of free entries; the first element (0) is always used /// to point to the next free entry. /// ////// See: http://blogs.msdn.com/[....]/archive/2004/02/20/77460.aspx /// According to this article the entire reachable graph from /// a finalizable object is promoted, and it is safe to access its /// members if they do not have their own finalizers. /// Hence it is OK to access this array during finalization. /// private HandleIndex[] _unmanagedHandles; ////// List of created PTS pages. Those are unmanaged resources and /// have to be disposed. /// ////// See: http://blogs.msdn.com/[....]/archive/2004/02/20/77460.aspx /// According to this article the entire reachable graph from /// a finalizable object is promoted, and it is safe to access its /// members if they do not have their own finalizers. /// Hence it is OK to access this array during finalization. /// ////// Members of this list are pointers that are passed to Critical functions /// that'll write to the memory directly in unmanaged code. /// [SecurityCritical] private ArrayList _pages; ////// List of created PTS BreakRecords. Those are unmanaged resources and /// have to be disposed. /// ////// See: http://blogs.msdn.com/[....]/archive/2004/02/20/77460.aspx /// According to this article the entire reachable graph from /// a finalizable object is promoted, and it is safe to access its /// members if they do not have their own finalizers. /// Hence it is OK to access this array during finalization. /// ////// Members of this list are pointers that are passed to Critical functions /// that'll write to the memory directly in unmanaged code. /// [SecurityCritical] private ArrayList _pageBreakRecords; ////// Exception caught during callback execution. Those exceptions are /// converted into error codes and passed to PTS to provide appropriate /// clenaup. Later this exception is re-thrown. /// private Exception _callbackException; ////// PTS Host: all PTS callbacks are defined here. /// private PtsHost _ptsHost; ////// Whether optimal paragraph is enabled for this ptscontext /// private bool _isOptimalParagraphEnabled; ////// TextFormatter - Used only in optimal mode /// private TextFormatter _textFormatter; ////// Whether object is already disposed. /// private int _disposed; ////// Whether Dispose has been completed. It may be set to 'false' even when /// _disposed is set to 'true'. It may happen during Dispose execution. /// This flag is used for verification only. /// private bool _disposeCompleted; ////// Default capacity of the UnmanagedHandles array. The array capacity /// is always increased in multiples of two as required: 16*(2^N). /// private const int _defaultHandlesCapacity = 16; #endregion Private Fields //------------------------------------------------------------------- // // Private Types // //-------------------------------------------------------------------- #region Private Types ////// HandleIndex can store one of following information: /// {1) reference to Object /// (2) index of the next free entry /// private struct HandleIndex { internal int Index; internal object Obj; internal bool IsHandle() { return (Obj != null && Index == 0); } } #endregion Private Types } } // 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. // // File: PtsContext.cs // // Description: Context used to communicate with PTS component. // //--------------------------------------------------------------------------- using System; // IntPtr, IDisposable, ... using System.Collections; // ArrayList using System.Collections.Generic; // Listusing System.Security; // SecurityCritical, SecurityTreatAsSafe using System.Threading; // Interlocked using System.Windows.Media.TextFormatting; // TextFormatter using System.Windows.Threading; // DispatcherObject using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS namespace MS.Internal.PtsHost { /// /// Context used to communicate with PTS component. /// Context keeps track of all unmanaged resources created by PTS. /// It also maps an instance of Object into an identity that can be used /// in unmanaged world. This identity can by easily mapped back into /// original instance of Object. /// internal sealed class PtsContext : DispatcherObject, IDisposable { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Constructor. /// ////// The array of entries initially can store up to 16 entries. Upon /// adding elements the capacity increased in multiples of two as /// required. The first element always contains index to the next /// free entry. All free entries are forming a linked list. /// ////// Critical, because allocates Critical collections: _pages, and _pageBreakRecords. /// Safe, because creating empty collections is safe. /// [SecurityCritical, SecurityTreatAsSafe] internal PtsContext(bool isOptimalParagraphEnabled) { _pages = new ArrayList(1); _pageBreakRecords = new ArrayList(1); _unmanagedHandles = new HandleIndex[_defaultHandlesCapacity]; // Limit initial size _isOptimalParagraphEnabled = isOptimalParagraphEnabled; BuildFreeList(1); // 1 is the first free index in UnmanagedHandles array // Acquire PTS Context _ptsHost = PtsCache.AcquireContext(this); } #endregion Constructors //-------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods ////// Destroy all unmanaged resources associated with the PtsContext. /// ////// Critical, because calls Critical functions PTS.FsDestroyPageBreakRecord /// and PTS.FsDestroyPage. /// Safe, because parameters passed to PTS.FsDestroyPageBreakRecord /// and PTS.FsDestroyPage are Critical for set, so cannot have /// randomly assigned value. /// [SecurityCritical, SecurityTreatAsSafe] public void Dispose() { int index; // Do actual dispose only once. if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 0) { // Destroy all page break records. The collection is allocated during creation // of the context, and can be only destroyed during dispose process. // It is necessary to enter PTS Context when executing any PTS methods. try { Enter(); for (index = 0; index < _pageBreakRecords.Count; index++) { Invariant.Assert(((IntPtr)_pageBreakRecords[index]) != IntPtr.Zero, "Invalid break record object"); PTS.Validate(PTS.FsDestroyPageBreakRecord(_ptsHost.Context, (IntPtr)_pageBreakRecords[index])); } } finally { Leave(); _pageBreakRecords = null; } // Destroy all pages. The collection is allocated during creation // of the context, and can be only destroyed during dispose process. // It is necessary to enter PTS Context when executing any PTS methods. try { Enter(); for (index = 0; index < _pages.Count; index++) { Invariant.Assert(((IntPtr)_pages[index]) != IntPtr.Zero, "Invalid break record object"); PTS.Validate(PTS.FsDestroyPage(_ptsHost.Context, (IntPtr)_pages[index])); } } finally { Leave(); _pages = null; } if (Invariant.Strict && _unmanagedHandles != null) { // Verify that PtsContext does not contain any reference to objects. // Because order of finalizers is not deterministic, only objects // that can be part of the NameTable are allowed here. for (index = 0; index < _unmanagedHandles.Length; ++index) { Object obj = _unmanagedHandles[index].Obj; if (obj != null) { Invariant.Assert( obj is BaseParagraph || obj is Section || obj is MS.Internal.PtsHost.LineBreakRecord, // Suppress line break record leak, looks like a PTS issue but we cannot // get a firm repro for now. Workaround for bug #1294210. "One of PTS Client objects is not properly disposed."); #if DEBUG // Make sure that FigureParagraphs are only used by TextParagraph if (obj is FigureParagraph || obj is FloaterParagraph) { bool found = false; for (int i = 0; i < _unmanagedHandles.Length; ++i) { Object objDbg = _unmanagedHandles[i].Obj; if (objDbg is TextParagraph) { ListattachedObjects = ((TextParagraph)objDbg).AttachedObjectDbg; if (attachedObjects != null) { foreach (AttachedObject attachedObject in attachedObjects) { if (attachedObject.Para == obj) { found = true; break; } } } if (found) { break; } } } Invariant.Assert(found, "FigureParagraph is not properly disposed."); } #endif } } } _ptsHost = null; _unmanagedHandles = null; _callbackException = null; _disposeCompleted = true; } } /// /// Inserts the object into reference array and returns its handle. /// /// Object to be mapped to an unmanaged handle. ///Unmanaged handle associated with the object. ////// Thread safe, see facts for the class description. /// internal IntPtr CreateHandle(object obj) { Invariant.Assert(obj != null, "Cannot create handle for non-existing object."); Invariant.Assert(!this.Disposed, "PtsContext is already disposed."); // Ensure the size of handle array. The first item of the // array contains index of the next free position. If this // index is 0, it means that the array is full and needs to // be resized. if (_unmanagedHandles[0].Index == 0) { Resize(); } // Assign a handle to the Object and adjust free index. int handle = _unmanagedHandles[0].Index; _unmanagedHandles[0].Index = _unmanagedHandles[handle].Index; _unmanagedHandles[handle].Obj = obj; _unmanagedHandles[handle].Index = 0; return (IntPtr)handle; } ////// Removes reference to the object pointed by handle and release /// the entry associated with it. /// /// Handle of an Object being removed. ////// Thread safe, see facts for the class description. /// internal void ReleaseHandle(IntPtr handle) { int handleInt = (int)handle; Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. Invariant.Assert(handleInt > 0 && handleInt < _unmanagedHandles.Length, "Invalid object handle."); Invariant.Assert(_unmanagedHandles[handleInt].IsHandle(), "Handle has been already released."); _unmanagedHandles[handleInt].Obj = null; _unmanagedHandles[handleInt].Index = _unmanagedHandles[0].Index; _unmanagedHandles[0].Index = handleInt; } ////// Returns true if IntPtr is a handle /// /// Handle of an Object. ////// Thread safe, see facts for the class description. /// internal bool IsValidHandle(IntPtr handle) { int handleInt = (int)handle; Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. if (handleInt < 0 || handleInt >= _unmanagedHandles.Length) { return false; } return _unmanagedHandles[handleInt].IsHandle(); } ////// Maps handle to an Object. /// /// Handle of an Object. ///Reference to an Object. ////// Thread safe, see facts for the class description. /// internal object HandleToObject(IntPtr handle) { int handleInt = (int)handle; Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. Invariant.Assert(handleInt > 0 && handleInt < _unmanagedHandles.Length, "Invalid object handle."); Invariant.Assert(_unmanagedHandles[handleInt].IsHandle(), "Handle has been already released."); return _unmanagedHandles[handleInt].Obj; } ////// Enters the PTS context. Called before executing PTS methods. /// ////// Thread safe, see facts for the class description. /// internal void Enter() { Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. _ptsHost.EnterContext(this); } ////// Leaves the PTS context. Called after executing PTS methods. /// ////// Thread safe, see facts for the class description. /// internal void Leave() { Invariant.Assert(!_disposeCompleted, "PtsContext is already disposed."); // May be called from Dispose. _ptsHost.LeaveContext(this); } ////// Keeps track of created pages (unmanaged resource). /// When page is created, add it to the list. /// /// PTS Page object that was just created. ////// Critical, because adds new entry to Critical collection _pages. /// Safe, because ptsPage parameter is Critical for set, so cannot have /// randomly assigned value. /// [SecurityCritical, SecurityTreatAsSafe] internal void OnPageCreated(SecurityCriticalDataForSetptsPage) { Invariant.Assert(ptsPage.Value != IntPtr.Zero, "Invalid page object."); Invariant.Assert(!this.Disposed, "PtsContext is already disposed."); Invariant.Assert(!_pages.Contains(ptsPage.Value), "Page already exists."); _pages.Add(ptsPage.Value); } /// /// Destroys PTS page. /// /// Pointer to PTS Page object that should be destroyed. /// Whether dispose is caused by explicit call to Dispose. /// Whether needs to enter PtsContext or not (during layout it is not needed). internal void OnPageDisposed(SecurityCriticalDataForSetptsPage, bool disposing, bool enterContext) { Invariant.Assert(ptsPage.Value != IntPtr.Zero, "Invalid page object."); // If explicitly disposing (not called during finalization), synchronously // destroy the page. if (disposing) { OnDestroyPage(ptsPage, enterContext); } else { // If PtsContext has been already disposed, ignore this call. if (!this.Disposed && !this.Dispatcher.HasShutdownStarted) { // Schedule background operation to destroy the page. this.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(OnDestroyPage), ptsPage); } } } /// /// Keeps track of created page BreakRecords (unmanaged resource). /// When PageBreakRecord is created, add it to the list. /// /// PTS Page BR object that was just created. ////// Critical, because adds new entry to Critical collection _pageBreakRecords. /// Safe, because br parameter is Critical for set, so cannot have randomly assigned value. /// [SecurityCritical, SecurityTreatAsSafe] internal void OnPageBreakRecordCreated(SecurityCriticalDataForSetbr) { Invariant.Assert(br.Value != IntPtr.Zero, "Invalid break record object."); Invariant.Assert(!this.Disposed, "PtsContext is already disposed."); Invariant.Assert(!_pageBreakRecords.Contains(br.Value), "Break record already exists."); _pageBreakRecords.Add(br.Value); } /// /// Destroys PTS break record. /// /// Pointer to PTS Page BR object that should be destroyed. /// Whether dispose is caused by explicit call to Dispose. internal void OnPageBreakRecordDisposed(SecurityCriticalDataForSetbr, bool disposing) { Invariant.Assert(br.Value != IntPtr.Zero, "Invalid break record object."); // If explicitly disposing (not called during finalization), synchronously // destroy the page break record. if (disposing) { OnDestroyBreakRecord((object)br); } else { // If PtsContext has been already disposed, ignore this call. if (!this.Disposed && !this.Dispatcher.HasShutdownStarted) { // Schedule background operation to destroy the page. this.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(OnDestroyBreakRecord), br); } } } #endregion Internal Methods //-------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties /// /// Whether object is already disposed. /// internal bool Disposed { get { return (_disposed != 0); } } ////// Context Id used to communicate with PTS. /// internal IntPtr Context { get { return _ptsHost.Context; } } ////// Whether optimal paragraph is enabled /// internal bool IsOptimalParagraphEnabled { get { return _isOptimalParagraphEnabled; } } ////// Text formatter context for this pts context /// internal TextFormatter TextFormatter { get { return _textFormatter; } set { _textFormatter = value; } } ////// Exception caught during callback execution. Those exceptions are /// converted into error codes and passed to PTS to provide appropriate /// clenaup. Later this exception is re-thrown. /// internal Exception CallbackException { get { return _callbackException; } set { _callbackException = value; } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------- #region Private Methods ////// Rebuilds list of free entries starting from specified index. /// /// Index to start from. private void BuildFreeList(int freeIndex) { // Point to the first empty slot _unmanagedHandles[0].Index = freeIndex; // Link all entries starting from freeIndex while (freeIndex < _unmanagedHandles.Length) { _unmanagedHandles[freeIndex].Index = ++freeIndex; } // End of free entries list _unmanagedHandles[freeIndex - 1].Index = 0; } ////// Increases the capacity of the handle array. /// new size = current size * 2 /// private void Resize() { int freeIndex = _unmanagedHandles.Length; // Allocate new array and copy all existing entries into it HandleIndex[] newItems = new HandleIndex[_unmanagedHandles.Length * 2]; Array.Copy(_unmanagedHandles, newItems, _unmanagedHandles.Length); _unmanagedHandles = newItems; // Build list of free entries BuildFreeList(freeIndex); } ////// Destroys PTS page. /// /// Pointer to PTS Page object that should be destroyed. private object OnDestroyPage(object args) { SecurityCriticalDataForSetptsPage = (SecurityCriticalDataForSet )args; OnDestroyPage(ptsPage, true); return null; } /// /// Destroys PTS page. /// /// Pointer to PTS Page object that should be destroyed. /// Whether needs to enter PTS Context. ////// Critical, because: /// a) calls Critical functions PTS.FsDestroyPage, /// b) modifies Critical collection _pages /// Safe, because: /// a) parameter passed to PTS.FsDestroyPage is Critical /// for set, so cannot have randomly assigned value. /// b) removing from Critical collection is safe operation. /// [SecurityCritical, SecurityTreatAsSafe] private void OnDestroyPage(SecurityCriticalDataForSetptsPage, bool enterContext) { Invariant.Assert(ptsPage.Value != IntPtr.Zero, "Invalid page object."); // Dispatcher may invoke this operation when PtsContext is already explicitly // disposed. if (!this.Disposed) { Invariant.Assert(_pages != null, "Collection of pages does not exist."); Invariant.Assert(_pages.Contains(ptsPage.Value), "Page does not exist."); // Destroy given page. // It is necessary to enter PTS Context when executing any PTS methods. try { if (enterContext) { Enter(); } PTS.Validate(PTS.FsDestroyPage(_ptsHost.Context, ptsPage.Value)); } finally { if (enterContext) { Leave(); } _pages.Remove(ptsPage.Value); } } } /// /// Destroys PTS page break record. /// /// Pointer to PTS Page BreakRecord object that should be destroyed. ////// Critical, because: /// a) calls Critical functions PTS.FsDestroyPageBreakRecord, /// b) modifies Critical collection _pageBreakRecords /// Safe, because: /// a) parameter passed to PTS.FsDestroyPageBreakRecord is Critical /// for set, so cannot have randomly assigned value. /// b) removing from Critical collection is safe operation. /// [SecurityCritical, SecurityTreatAsSafe] private object OnDestroyBreakRecord(object args) { SecurityCriticalDataForSetbr = (SecurityCriticalDataForSet )args; Invariant.Assert(br.Value != IntPtr.Zero, "Invalid break record object."); // Dispatcher may invoke this operation when PtsContext is already explicitly // disposed. if (!this.Disposed) { Invariant.Assert(_pageBreakRecords != null, "Collection of break records does not exist."); Invariant.Assert(_pageBreakRecords.Contains(br.Value), "Break record does not exist."); // Destroy given page break record. // It is necessary to enter PTS Context when executing any PTS methods. try { Enter(); PTS.Validate(PTS.FsDestroyPageBreakRecord(_ptsHost.Context, br.Value)); } finally { Leave(); _pageBreakRecords.Remove(br.Value); } } return null; } #endregion Private Methods //------------------------------------------------------------------- // // Private Fields // //------------------------------------------------------------------- #region Private Fields /// /// Array of HandleIndex. This array stores 2 kind of information: /// {1) reference to Object; array index is a handle of the Object, /// (2) linked list of free entries; the first element (0) is always used /// to point to the next free entry. /// ////// See: http://blogs.msdn.com/[....]/archive/2004/02/20/77460.aspx /// According to this article the entire reachable graph from /// a finalizable object is promoted, and it is safe to access its /// members if they do not have their own finalizers. /// Hence it is OK to access this array during finalization. /// private HandleIndex[] _unmanagedHandles; ////// List of created PTS pages. Those are unmanaged resources and /// have to be disposed. /// ////// See: http://blogs.msdn.com/[....]/archive/2004/02/20/77460.aspx /// According to this article the entire reachable graph from /// a finalizable object is promoted, and it is safe to access its /// members if they do not have their own finalizers. /// Hence it is OK to access this array during finalization. /// ////// Members of this list are pointers that are passed to Critical functions /// that'll write to the memory directly in unmanaged code. /// [SecurityCritical] private ArrayList _pages; ////// List of created PTS BreakRecords. Those are unmanaged resources and /// have to be disposed. /// ////// See: http://blogs.msdn.com/[....]/archive/2004/02/20/77460.aspx /// According to this article the entire reachable graph from /// a finalizable object is promoted, and it is safe to access its /// members if they do not have their own finalizers. /// Hence it is OK to access this array during finalization. /// ////// Members of this list are pointers that are passed to Critical functions /// that'll write to the memory directly in unmanaged code. /// [SecurityCritical] private ArrayList _pageBreakRecords; ////// Exception caught during callback execution. Those exceptions are /// converted into error codes and passed to PTS to provide appropriate /// clenaup. Later this exception is re-thrown. /// private Exception _callbackException; ////// PTS Host: all PTS callbacks are defined here. /// private PtsHost _ptsHost; ////// Whether optimal paragraph is enabled for this ptscontext /// private bool _isOptimalParagraphEnabled; ////// TextFormatter - Used only in optimal mode /// private TextFormatter _textFormatter; ////// Whether object is already disposed. /// private int _disposed; ////// Whether Dispose has been completed. It may be set to 'false' even when /// _disposed is set to 'true'. It may happen during Dispose execution. /// This flag is used for verification only. /// private bool _disposeCompleted; ////// Default capacity of the UnmanagedHandles array. The array capacity /// is always increased in multiples of two as required: 16*(2^N). /// private const int _defaultHandlesCapacity = 16; #endregion Private Fields //------------------------------------------------------------------- // // Private Types // //-------------------------------------------------------------------- #region Private Types ////// HandleIndex can store one of following information: /// {1) reference to Object /// (2) index of the next free entry /// private struct HandleIndex { internal int Index; internal object Obj; internal bool IsHandle() { return (Obj != null && Index == 0); } } #endregion Private Types } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WindowsContainer.cs
- BridgeDataReader.cs
- NodeFunctions.cs
- TextChangedEventArgs.cs
- UrlPath.cs
- Base64Decoder.cs
- NetworkCredential.cs
- ChannelBase.cs
- OleDbError.cs
- SystemResourceHost.cs
- ZipIOLocalFileBlock.cs
- RoutedUICommand.cs
- ToolStripItemEventArgs.cs
- ArraySubsetEnumerator.cs
- BinaryMethodMessage.cs
- XmlSchemaValidator.cs
- Expression.cs
- MsmqHostedTransportManager.cs
- _BasicClient.cs
- SyndicationDeserializer.cs
- DbConnectionInternal.cs
- XmlSchemaSubstitutionGroup.cs
- PenLineCapValidation.cs
- DiscoveryExceptionDictionary.cs
- DataContractSerializerSection.cs
- EntryIndex.cs
- PrefixHandle.cs
- DependencyProperty.cs
- ArrayConverter.cs
- CollectionChangeEventArgs.cs
- GridViewDeleteEventArgs.cs
- ValueProviderWrapper.cs
- BindingNavigator.cs
- LassoHelper.cs
- BaseCAMarshaler.cs
- ControlEvent.cs
- MdiWindowListStrip.cs
- SelfIssuedSamlTokenFactory.cs
- DataPagerFieldCollection.cs
- ComUdtElement.cs
- SafeArchiveContext.cs
- WmlValidatorAdapter.cs
- Int32KeyFrameCollection.cs
- ADMembershipProvider.cs
- InstanceCreationEditor.cs
- SecurityKeyIdentifierClause.cs
- Size.cs
- DataGridViewImageColumn.cs
- ItemsControl.cs
- GridViewPageEventArgs.cs
- ValidatedControlConverter.cs
- RequestContextBase.cs
- ValidatorCompatibilityHelper.cs
- SqlRowUpdatedEvent.cs
- OleDbException.cs
- SchemaNames.cs
- ScriptIgnoreAttribute.cs
- WebPartsPersonalization.cs
- Point3DCollection.cs
- ServiceDescriptionImporter.cs
- ReceiveContent.cs
- MorphHelper.cs
- TreeNodeMouseHoverEvent.cs
- MediaElementAutomationPeer.cs
- Memoizer.cs
- SettingsPropertyCollection.cs
- Currency.cs
- HelpInfo.cs
- XmlDocument.cs
- ComNativeDescriptor.cs
- cookiecollection.cs
- SqlServer2KCompatibilityCheck.cs
- Missing.cs
- PropertyItemInternal.cs
- MenuBindingsEditorForm.cs
- TableParaClient.cs
- InvalidAsynchronousStateException.cs
- StickyNoteHelper.cs
- ServicePointManagerElement.cs
- ToolboxSnapDragDropEventArgs.cs
- DecoderFallback.cs
- RegexCode.cs
- TreeNodeCollection.cs
- EdmProviderManifest.cs
- XmlRootAttribute.cs
- ObjectDataSourceFilteringEventArgs.cs
- PeerPresenceInfo.cs
- TypeElement.cs
- WebPartEditorCancelVerb.cs
- HtmlTable.cs
- ContractInferenceHelper.cs
- DSACryptoServiceProvider.cs
- MetadataCache.cs
- SourceExpressionException.cs
- XmlNotation.cs
- InfoCardX509Validator.cs
- BaseProcessor.cs
- mediapermission.cs
- ProcessHostFactoryHelper.cs
- TreeViewImageIndexConverter.cs