Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Input / Stylus / PenThreadWorker.cs / 1305600 / PenThreadWorker.cs
//#define TRACEPTW using System; using System.Diagnostics; using System.Collections; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows.Media; using System.Threading; using System.Security; using System.Security.Permissions; using MS.Internal; using MS.Internal.PresentationCore; // SecurityHelper using System.Collections.Generic; using System.Collections.ObjectModel; using MS.Win32.Penimc; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Input { ///////////////////////////////////////////////////////////////////////// internal sealed class PenThreadWorker { ///List of constants for PenImc const int PenEventNone = 0; const int PenEventTimeout = 1; const int PenEventPenInRange = 707; const int PenEventPenOutOfRange = 708; const int PenEventPenDown = 709; const int PenEventPenUp = 710; const int PenEventPackets = 711; const int PenEventSystem = 714; const int MaxContextPerThread = 31; // (64 - 1) / 2 = 31. Max handle limit for MsgWaitForMultipleMessageEx() const int EventsFrequency = 8; ////// Critical - Marked critical to prevent inadvertant code from modifying this. /// [SecurityCritical] IntPtr [] _handles = new IntPtr[0]; ////// Critical - Marked critical to prevent inadvertant code from modifying this. /// [SecurityCritical] WeakReference [] _penContexts = new WeakReference[0]; ////// Critical - Marked critical to prevent inadvertant code from modifying this. /// [SecurityCritical] IPimcContext [] _pimcContexts = new IPimcContext[0]; ////// SecurityCritical - This is got under an elevation and is hence critical. /// private SecurityCriticalData_pimcResetHandle; private volatile bool __disposed; private List _workerOperation = new List (); private object _workerOperationLock = new Object(); // For caching move events. /// /// Critical to prevent accidental spread to transparent code /// [SecurityCritical] private PenContext _cachedMovePenContext; private int _cachedMoveStylusPointerId; private int _cachedMoveStartTimestamp; private int [] _cachedMoveData; ///////////////////////////////////////////////////////////////////// // // Here's a bunch of helper classes to manage marshalling the calls // over to the worker thread to be executed synchronously. // ///////////////////////////////////////////////////////////////////// // Base class for all worker operations private abstract class WorkerOperation { AutoResetEvent _doneEvent; internal WorkerOperation() { _doneEvent = new AutoResetEvent(false); } ////// Critical - Calls SecurityCritical code OnDoWork which is differred based on the various derived class. /// Called by PenThreadWorker.ThreadProc(). /// [SecurityCritical] internal void DoWork() { try { OnDoWork(); } finally { _doneEvent.Set(); } } ////// Critical - Calls SecurityCritical code OnDoWork which is differred based on the various derived class. /// Called by WorkerOperation.DoWork(). /// [SecurityCritical] protected abstract void OnDoWork(); internal AutoResetEvent DoneEvent { get { return _doneEvent;} } } // Class that handles getting the current rect for a tablet device. private class WorkerOperationThreadStart : WorkerOperation { ///////////////////////////////////////////////////////////////////////// ////// Used to signal when the thread has started up. /// protected override void OnDoWork() { // We don't need to do anything. Just have event signal we've executed. } } // Class that handles getting the tablet device info for all tablets on the system. private class WorkerOperationGetTabletsInfo : WorkerOperation { internal TabletDeviceInfo[] TabletDevicesInfo { get { return _tabletDevicesInfo;} } ///////////////////////////////////////////////////////////////////////// ////// Returns the list of TabletDeviceInfo structs that contain information /// about all of the TabletDevices on the system. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - returns security critical data _pimcTablet /// [SecurityCritical] protected override void OnDoWork() { try { // create new collection of tablets MS.Win32.Penimc.IPimcManager pimcManager = MS.Win32.Penimc.UnsafeNativeMethods.PimcManager; uint cTablets; pimcManager.GetTabletCount(out cTablets); TabletDeviceInfo[] tablets = new TabletDeviceInfo[cTablets]; for ( uint iTablet = 0; iTablet < cTablets; iTablet++ ) { MS.Win32.Penimc.IPimcTablet pimcTablet; pimcManager.GetTablet(iTablet, out pimcTablet); tablets[iTablet] = PenThreadWorker.GetTabletInfoHelper(pimcTablet); } // Set result data and signal we are done. _tabletDevicesInfo = tablets; } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationGetTabletsInfo.OnDoWork failed due to a COMException"); // return no devices found on error. _tabletDevicesInfo = new TabletDeviceInfo[0]; } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to an ArgumentException. Debug.WriteLine("WorkerOperationGetTabletsInfo.OnDoWork failed due to an ArgumentException"); // return no devices found on error. _tabletDevicesInfo = new TabletDeviceInfo[0]; } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationGetTabletsInfo.OnDoWork failed due to an UnauthorizedAccessException"); // return no devices found on error. _tabletDevicesInfo = new TabletDeviceInfo[0]; } } TabletDeviceInfo[] _tabletDevicesInfo; } // Class that handles creating a context for a particular tablet device. private class WorkerOperationCreateContext : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationCreateContext(IntPtr hwnd, IPimcTablet pimcTablet) { _hwnd = hwnd; _pimcTablet = pimcTablet; } internal PenContextInfo Result { get { return _result;} } ///////////////////////////////////////////////////////////////////////// ////// Creates a new context for this a window and given tablet device and /// returns a new PenContext in the workOperation class. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handle security critical data _hwnd, _pimcTablet. /// [SecurityCritical] protected override void OnDoWork() { IPimcContext pimcContext; int id; IntPtr commHandle; try { _pimcTablet.CreateContext(_hwnd, true, 250, out pimcContext, out id, out commHandle); // Set result data and signal we are done. PenContextInfo result; result.ContextId = id; result.PimcContext = new SecurityCriticalDataClass(pimcContext); result.CommHandle = new SecurityCriticalDataClass (commHandle); _result = result; } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationCreateContext.OnDoWork failed due to a COMException"); // set with uninitialized PenContextInfo (all zero). _result = new PenContextInfo(); } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to an ArgumentException. Debug.WriteLine("WorkerOperationCreateContext.OnDoWork failed due to an ArgumentException"); // set with uninitialized PenContextInfo (all zero). _result = new PenContextInfo(); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationCreateContext.OnDoWork failed due to an UnauthorizedAccessException"); // set with uninitialized PenContextInfo (all zero). _result = new PenContextInfo(); } } /// /// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IntPtr _hwnd; ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IPimcTablet _pimcTablet; PenContextInfo _result; } // Class that handles refreshing the cursor devices for a particular tablet device. private class WorkerOperationRefreshCursorInfo : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationRefreshCursorInfo(IPimcTablet pimcTablet) { _pimcTablet = pimcTablet; } internal StylusDeviceInfo[] StylusDevicesInfo { get { return _stylusDevicesInfo; } } ///////////////////////////////////////////////////////////////////////// ////// Causes the stylus devices info (cursors) in penimc to be refreshed /// for the passed in IPimcTablet. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handle security critical data _pimcTablet. /// [SecurityCritical] protected override void OnDoWork() { try { _pimcTablet.RefreshCursorInfo(); _stylusDevicesInfo = PenThreadWorker.GetStylusDevicesInfo(_pimcTablet); } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationRefreshCursorInfo.OnDoWork failed due to a COMException"); } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to a ArgumentException. Debug.WriteLine("WorkerOperationRefreshCursorInfo.OnDoWork failed due to an ArgumentException"); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationRefreshCursorInfo.OnDoWork failed due to an UnauthorizedAccessException"); } } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IPimcTablet _pimcTablet; StylusDeviceInfo[] _stylusDevicesInfo; } // Class that handles getting info about a specific tablet device. private class WorkerOperationGetTabletInfo : WorkerOperation { internal WorkerOperationGetTabletInfo(uint index) { _index = index; } internal TabletDeviceInfo TabletDeviceInfo { get { return _tabletDeviceInfo;} } ///////////////////////////////////////////////////////////////////////// ////// Fills in a struct containing the list of TabletDevice properties for /// a given tablet device index. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - returns security critical data _pimcTablet /// [SecurityCritical] protected override void OnDoWork() { try { // create new collection of tablets MS.Win32.Penimc.IPimcManager pimcManager = MS.Win32.Penimc.UnsafeNativeMethods.PimcManager; MS.Win32.Penimc.IPimcTablet pimcTablet; pimcManager.GetTablet(_index, out pimcTablet); // Set result data and signal we are done. _tabletDeviceInfo = PenThreadWorker.GetTabletInfoHelper(pimcTablet); } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationGetTabletInfo.OnDoWork failed due to COMException"); // set to uninitialized TabletDeviceInfo struct (all zeros) to signal failure. _tabletDeviceInfo = new TabletDeviceInfo(); } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to an ArgumentException. Debug.WriteLine("WorkerOperationGetTabletInfo.OnDoWork failed due to an ArgumentException"); // set to uninitialized TabletDeviceInfo struct (all zeros) to signal failure. _tabletDeviceInfo = new TabletDeviceInfo(); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationGetTabletInfo.OnDoWork failed due to an UnauthorizedAccessException"); // set to uninitialized TabletDeviceInfo struct (all zeros) to signal failure. _tabletDeviceInfo = new TabletDeviceInfo(); } } uint _index; TabletDeviceInfo _tabletDeviceInfo; } // Class that handles getting the current rect for a tablet device. private class WorkerOperationWorkerGetUpdatedSizes : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationWorkerGetUpdatedSizes(IPimcTablet pimcTablet) { _pimcTablet = pimcTablet; } internal TabletDeviceSizeInfo TabletDeviceSizeInfo { get { return _tabletDeviceSizeInfo;} } ///////////////////////////////////////////////////////////////////////// ////// Gets the current rectangle for a tablet device and returns in workOperation class. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data _pimcTablet /// [SecurityCritical] protected override void OnDoWork() { try { int displayWidth, displayHeight, tabletWidth, tabletHeight; _pimcTablet.GetTabletAndDisplaySize(out tabletWidth, out tabletHeight, out displayWidth, out displayHeight); // Set result data and signal we are done. _tabletDeviceSizeInfo = new TabletDeviceSizeInfo( new Size( tabletWidth, tabletHeight), new Size( displayWidth, displayHeight)); } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationWorkerGetUpdatedSizes.OnDoWork failed due to a COMException"); // Size structs will be 1x1 if a COM exception is thrown. Should be dead context anyway on exception. _tabletDeviceSizeInfo = new TabletDeviceSizeInfo(new Size( 1, 1), new Size( 1, 1)); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationWorkerGetUpdatedSizes.OnDoWork failed due to an UnauthorizedAccessException"); // Size structs will be 1x1 if a COM exception is thrown. Should be dead context anyway on exception. _tabletDeviceSizeInfo = new TabletDeviceSizeInfo(new Size( 1, 1), new Size( 1, 1)); } } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IPimcTablet _pimcTablet; TabletDeviceSizeInfo _tabletDeviceSizeInfo; } // Class that handles getting the current rect for a tablet device. private class WorkerOperationAddContext : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationAddContext(PenContext penContext, PenThreadWorker penThreadWorker) { _newPenContext = penContext; _penThreadWorker = penThreadWorker; } internal bool Result { get { return _result;} } ///////////////////////////////////////////////////////////////////////// ////// Adds a PenContext to the list of contexts that events can be received /// from and returns whether it was successful in workOperation class. /// ////// Critical: - handles security critical data _penContexts, _handles, _pimcContexts /// [SecurityCritical] protected override void OnDoWork() { _result = _penThreadWorker.AddPenContext(_newPenContext); } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenContext _newPenContext; ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenThreadWorker _penThreadWorker; bool _result; } // Class that handles getting the current rect for a tablet device. private class WorkerOperationRemoveContext : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationRemoveContext(PenContext penContext, PenThreadWorker penThreadWorker) { _penContextToRemove = penContext; _penThreadWorker = penThreadWorker; } internal bool Result { get { return _result;} } ///////////////////////////////////////////////////////////////////////// ////// Adds a PenContext to the list of contexts that events can be received /// from and returns whether it was successful in workOperation class. /// ////// Critical: - handles security critical data _penContexts, _handles, _pimcContexts /// [SecurityCritical] protected override void OnDoWork() { _result = _penThreadWorker.RemovePenContext(_penContextToRemove); } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenContext _penContextToRemove; ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenThreadWorker _penThreadWorker; bool _result; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code MS.Win32.Penimc.UnsafeNativeMethods.CreateResetEvent /// and handles SecurityCritical data resetHandle. /// Called by PenThread constructor. /// TreatAsSafe boundry is Stylus.EnableCore, Stylus.RegisterHwndForInput /// and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal PenThreadWorker() { IntPtr resetHandle; // Consider: We could use a AutoResetEvent handle instead and avoid the penimc.dll call. MS.Win32.Penimc.UnsafeNativeMethods.CreateResetEvent(out resetHandle); _pimcResetHandle = new SecurityCriticalData(resetHandle); WorkerOperationThreadStart started = new WorkerOperationThreadStart(); lock(_workerOperationLock) { _workerOperation.Add((WorkerOperation)started); } Thread thread = new Thread(new ThreadStart(ThreadProc)); thread.IsBackground = true; // don't hold process open due to this thread. thread.Start(); // Wait for this work to be completed (ie thread is started up). started.DoneEvent.WaitOne(); started.DoneEvent.Close(); } /// /// Critical - Needs to call SupressUnmanagedCodeSecurity attributed /// code to free unmanaged resource handle. Needs to be /// SecurityCritical for that. Also references SecurityCriticalData. /// [SecurityCritical] internal void Dispose() { if(!__disposed) { __disposed = true; // Kick thread to wake up and see we are disposed. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Let it destroy the reset event. } GC.KeepAlive(this); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data penContext. /// Called by PenThread.AddPenContext. /// [SecurityCritical] internal bool WorkerAddPenContext(PenContext penContext) { if (__disposed) { throw new ObjectDisposedException(null, SR.Get(SRID.Penservice_Disposed)); } Debug.Assert(penContext != null); WorkerOperationAddContext addContextOperation = new WorkerOperationAddContext(penContext, this); lock(_workerOperationLock) { _workerOperation.Add(addContextOperation); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. addContextOperation.DoneEvent.WaitOne(); addContextOperation.DoneEvent.Close(); return addContextOperation.Result; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data penContext. /// Called by PenThread.Disable. /// [SecurityCritical] internal bool WorkerRemovePenContext(PenContext penContext) { if (__disposed) { return true; } Debug.Assert(penContext != null); WorkerOperationRemoveContext removeContextOperation = new WorkerOperationRemoveContext(penContext, this); lock(_workerOperationLock) { _workerOperation.Add(removeContextOperation); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. removeContextOperation.DoneEvent.WaitOne(); removeContextOperation.DoneEvent.Close(); return removeContextOperation.Result; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle. /// Called by PenThreadPool.WorkerGetTabletsInfo. /// [SecurityCritical] internal TabletDeviceInfo[] WorkerGetTabletsInfo() { // Set data up for this call WorkerOperationGetTabletsInfo getTablets = new WorkerOperationGetTabletsInfo(); lock(_workerOperationLock) { _workerOperation.Add(getTablets); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. getTablets.DoneEvent.WaitOne(); getTablets.DoneEvent.Close(); return getTablets.TabletDevicesInfo; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data /// (hwnd, pimcTablet). /// Called by PenThreadPool.WorkerCreateContext. /// TreatAsSafe boundry is Stylus.EnableCore and HwndWrapperHook class /// (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal PenContextInfo WorkerCreateContext(IntPtr hwnd, IPimcTablet pimcTablet) { WorkerOperationCreateContext createContextOperation = new WorkerOperationCreateContext( hwnd, pimcTablet); lock(_workerOperationLock) { _workerOperation.Add(createContextOperation); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. createContextOperation.DoneEvent.WaitOne(); createContextOperation.DoneEvent.Close(); return createContextOperation.Result; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data pimcTablet. /// Called by PenThreadPool.WorkerRefreshCursorInfo. /// [SecurityCritical] internal StylusDeviceInfo[] WorkerRefreshCursorInfo(IPimcTablet pimcTablet) { WorkerOperationRefreshCursorInfo refreshCursorInfo = new WorkerOperationRefreshCursorInfo( pimcTablet); lock(_workerOperationLock) { _workerOperation.Add(refreshCursorInfo); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. refreshCursorInfo.DoneEvent.WaitOne(); refreshCursorInfo.DoneEvent.Close(); return refreshCursorInfo.StylusDevicesInfo; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle. /// Called by PenThreadPool.WorkerGetTabletInfo. /// [SecurityCritical] internal TabletDeviceInfo WorkerGetTabletInfo(uint index) { // Set up data for call WorkerOperationGetTabletInfo getTabletInfo = new WorkerOperationGetTabletInfo( index); lock(_workerOperationLock) { _workerOperation.Add(getTabletInfo); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. getTabletInfo.DoneEvent.WaitOne(); getTabletInfo.DoneEvent.Close(); return getTabletInfo.TabletDeviceInfo; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and pimcTablet. /// Called by PenThreadPool.WorkerGetUpdatedTabletRect. /// [SecurityCritical] internal TabletDeviceSizeInfo WorkerGetUpdatedSizes(IPimcTablet pimcTablet) { // Set data up for call WorkerOperationWorkerGetUpdatedSizes getUpdatedSizes = new WorkerOperationWorkerGetUpdatedSizes(pimcTablet); lock(_workerOperationLock) { _workerOperation.Add(getUpdatedSizes); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. getUpdatedSizes.DoneEvent.WaitOne(); getUpdatedSizes.DoneEvent.Close(); return getUpdatedSizes.TabletDeviceSizeInfo; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code PenContext.FirePenInRange and PenContext.FirePackets. /// Called by FireEvent and ThreadProc. /// TreatAsSafe boundry is ThreadProc. /// [SecurityCritical] void FlushCache(bool goingOutOfRange) { // Force any cached move/inairmove data to be flushed if we have any. if (_cachedMoveData != null) { // If we are going out of range and this stylus id is not currently in range // then eat these cached events (keeps from going in and out of range quickly) if (!goingOutOfRange || _cachedMovePenContext.IsInRange(_cachedMoveStylusPointerId)) { _cachedMovePenContext.FirePenInRange(_cachedMoveStylusPointerId, _cachedMoveData, _cachedMoveStartTimestamp); _cachedMovePenContext.FirePackets(_cachedMoveStylusPointerId, _cachedMoveData, _cachedMoveStartTimestamp); } _cachedMoveData = null; _cachedMovePenContext = null; _cachedMoveStylusPointerId = 0; } } ///////////////////////////////////////////////////////////////////// ////// SecurityCritical: Accesses SecurityCritical data _cachedMovePenContext. /// [SecurityCritical] bool DoCacheEvent(int evt, PenContext penContext, int stylusPointerId, int [] data, int timestamp) { // NOTE: Big assumption is that we always get other events between packets (ie don't get move // down position followed by move in up position). We don't account for that here but it should // never happen. if (evt == PenEventPackets) { // If no cache then just cache it. if (_cachedMoveData == null) { _cachedMovePenContext = penContext; _cachedMoveStylusPointerId = stylusPointerId; _cachedMoveStartTimestamp = timestamp; _cachedMoveData = data; return true; } else if (_cachedMovePenContext == penContext && stylusPointerId == _cachedMoveStylusPointerId) { int sinceBeginning = timestamp - _cachedMoveStartTimestamp; if (timestamp < _cachedMoveStartTimestamp) sinceBeginning = (Int32.MaxValue - _cachedMoveStartTimestamp) + timestamp; if (EventsFrequency > sinceBeginning) { // Add to cache data int[] data0 = _cachedMoveData; _cachedMoveData = new int [data0.Length + data.Length]; data0.CopyTo(_cachedMoveData, 0); data.CopyTo(_cachedMoveData, data0.Length); return true; } } } return false; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code FlushCache, PenContext.FirePenDown, PenContext.FirePenUp, /// PenContext.FirePenInRange, PenContext.FirePackets, PenContext.FirePenOutOfRange, PenContext.FireSystemGesture. /// Called by ThreadProc. /// TreatAsSafe boundry is ThreadProc. /// [SecurityCritical] internal void FireEvent(PenContext penContext, int evt, int stylusPointerId, int cPackets, int cbPacket, IntPtr pPackets) { // disposed? if (__disposed) { return; // Don't process this event if we're in the process of shutting down. } // marshal the data to our cache if (cbPacket % 4 != 0) { throw new InvalidOperationException(SR.Get(SRID.PenService_InvalidPacketData)); } int cItems = cPackets * (cbPacket / 4); int[] data = null; if (0 < cItems) { data = new int [cItems]; // GetDataArray(cItems); // see comment on GetDataArray Marshal.Copy(pPackets, data, 0, cItems); } else { data = null; } int timestamp = Environment.TickCount; // Deal with caching packet data. if (DoCacheEvent(evt, penContext, stylusPointerId, data, timestamp)) { return; } else { FlushCache(false); // make sure we flush cache if not caching. } // // fire it // switch (evt) { case PenEventPenDown: penContext.FirePenInRange(stylusPointerId, data, timestamp); penContext.FirePenDown(stylusPointerId, data, timestamp); break; case PenEventPenUp: penContext.FirePenInRange(stylusPointerId, data, timestamp); penContext.FirePenUp(stylusPointerId, data, timestamp); break; case PenEventPackets: penContext.FirePenInRange(stylusPointerId, data, timestamp); penContext.FirePackets(stylusPointerId, data, timestamp); break; case PenEventPenInRange: // We fire this special event just to give the app thread an early peak at // the inrange to filter out mouse moves before we get our first stylus event. penContext.FirePenInRange(stylusPointerId, null, timestamp); break; case PenEventPenOutOfRange: penContext.FirePenOutOfRange(stylusPointerId, timestamp); break; case PenEventSystem: penContext.FireSystemGesture(stylusPointerId, timestamp); break; } } ///////////////////////////////////////////////////////////////////////// ////// Returns a struct containing the list of TabletDevice properties for /// a given tablet device (pimcTablet). /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data pimcTablet /// [SecurityCritical] private static TabletDeviceInfo GetTabletInfoHelper(IPimcTablet pimcTablet) { TabletDeviceInfo tabletInfo = new TabletDeviceInfo(); tabletInfo.PimcTablet = new SecurityCriticalDataClass(pimcTablet); pimcTablet.GetKey(out tabletInfo.Id); pimcTablet.GetName(out tabletInfo.Name); pimcTablet.GetPlugAndPlayId(out tabletInfo.PlugAndPlayId); int iTabletWidth, iTabletHeight, iDisplayWidth, iDisplayHeight; pimcTablet.GetTabletAndDisplaySize(out iTabletWidth, out iTabletHeight, out iDisplayWidth, out iDisplayHeight); tabletInfo.SizeInfo = new TabletDeviceSizeInfo(new Size(iTabletWidth, iTabletHeight), new Size(iDisplayWidth, iDisplayHeight)); int caps; pimcTablet.GetHardwareCaps(out caps); tabletInfo.HardwareCapabilities = (TabletHardwareCapabilities)caps; int deviceType; pimcTablet.GetDeviceType(out deviceType); tabletInfo.DeviceType = (TabletDeviceType)(deviceType -1); // NTRAID:WINDOWSOS#1679154-2006/06/09-WAYNEZEN, // REENTRANCY NOTE: Let a PenThread do this work to avoid reentrancy! // The IPimcTablet object is created in the pen thread. If we access it from the UI thread, // COM will set up message pumping which will cause reentrancy here. InitializeSupportedStylusPointProperties(pimcTablet, tabletInfo); tabletInfo.StylusDevicesInfo = GetStylusDevicesInfo(pimcTablet); return tabletInfo; } ///////////////////////////////////////////////////////////////////////// /// /// Initializing the supported stylus point properties. and returns in workOperation class. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data pimcTablet /// [SecurityCritical] private static void InitializeSupportedStylusPointProperties(IPimcTablet pimcTablet, TabletDeviceInfo tabletInfo) { int cProps; int cButtons; int pressureIndex = -1; pimcTablet.GetPacketDescriptionInfo(out cProps, out cButtons); // Calls Unmanaged code - SecurityCritical with SUC. Listproperties = new List (cProps + cButtons + 3); for ( int i = 0; i < cProps; i++ ) { Guid guid; int min, max; int units; float res; pimcTablet.GetPacketPropertyInfo(i, out guid, out min, out max, out units, out res); // Calls Unmanaged code - SecurityCritical with SUC. if ( pressureIndex == -1 && guid == StylusPointPropertyIds.NormalPressure ) { pressureIndex = i; } StylusPointProperty property = new StylusPointProperty(guid, false); properties.Add(property); } for ( int i = 0; i < cButtons; i++ ) { Guid buttonGuid; pimcTablet.GetPacketButtonInfo(i, out buttonGuid); // Calls Unmanaged code - SecurityCritical with SUC. StylusPointProperty buttonProperty = new StylusPointProperty(buttonGuid, true); properties.Add(buttonProperty); } //validate we can never get X, Y at index != 0, 1 Debug.Assert(properties[StylusPointDescription.RequiredXIndex /*0*/].Id == StylusPointPropertyIds.X, "X isn't where we expect it! Fix PenImc to ask for X at index 0"); Debug.Assert(properties[StylusPointDescription.RequiredYIndex /*1*/].Id == StylusPointPropertyIds.Y, "Y isn't where we expect it! Fix PenImc to ask for Y at index 1"); // NOTE: We can't force pressure since touch digitizers may not provide this info. The following assert is bogus. //Debug.Assert(pressureIndex == -1 || pressureIndex == StylusPointDescription.RequiredPressureIndex /*2*/, // "Fix PenImc to ask for NormalPressure at index 2!"); if ( pressureIndex == -1 ) { //pressure wasn't found. Add it properties.Insert(StylusPointDescription.RequiredPressureIndex /*2*/, System.Windows.Input.StylusPointProperties.NormalPressure); } else { //this device supports pressure tabletInfo.HardwareCapabilities |= TabletHardwareCapabilities.SupportsPressure; } tabletInfo.StylusPointProperties = new ReadOnlyCollection (properties); tabletInfo.PressureIndex = pressureIndex; } ///////////////////////////////////////////////////////////////////////// /// /// Getting the cursor info of the stylus devices. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data pimcTablet /// [SecurityCritical] private static StylusDeviceInfo[] GetStylusDevicesInfo(IPimcTablet pimcTablet) { int cCursors; pimcTablet.GetCursorCount(out cCursors); // Calls Unmanaged code - SecurityCritical with SUC. StylusDeviceInfo[] stylusDevicesInfo = new StylusDeviceInfo[cCursors]; for ( int iCursor = 0; iCursor < cCursors; iCursor++ ) { string sCursorName; int cursorId; bool fCursorInverted; pimcTablet.GetCursorInfo(iCursor, out sCursorName, out cursorId, out fCursorInverted); // Calls Unmanaged code - SecurityCritical with SUC. int cButtons; pimcTablet.GetCursorButtonCount(iCursor, out cButtons); // Calls Unmanaged code - SecurityCritical with SUC. StylusButton[] buttons = new StylusButton[cButtons]; for ( int iButton = 0; iButton < cButtons; iButton++ ) { string sButtonName; Guid buttonGuid; pimcTablet.GetCursorButtonInfo(iCursor, iButton, out sButtonName, out buttonGuid); // Calls Unmanaged code - SecurityCritical with SUC. buttons[iButton] = new StylusButton(sButtonName, buttonGuid); } StylusButtonCollection buttonCollection = new StylusButtonCollection(buttons); stylusDevicesInfo[iCursor].CursorName = sCursorName; stylusDevicesInfo[iCursor].CursorId = cursorId; stylusDevicesInfo[iCursor].CursorInverted = fCursorInverted; stylusDevicesInfo[iCursor].ButtonCollection = buttonCollection; } return stylusDevicesInfo; } ////// Critical - Accesses SecurityCriticalData (penContext, _penContexts, PenContext.CommHandle, /// _pimcContexts, and _handles). /// [SecurityCritical] internal bool AddPenContext(PenContext penContext) { ListpenContextRefs = new List (); // keep them alive while processing! int i; bool result = false; // Now go through and figure out the good entries // Need to clean up the list for gc'd references. for (i=0; i<_penContexts.Length; i++) { if (_penContexts[i].IsAlive) { PenContext pc = _penContexts[i].Target as PenContext; // We only need to ref if we have a penContext. if (pc != null) { penContextRefs.Add(pc); } } } // Now try again to see if we have room. if (penContextRefs.Count < MaxContextPerThread) { penContextRefs.Add(penContext); // add the new one to our list. // Now build up the handle array and PimcContext ref array. _pimcContexts = new IPimcContext[penContextRefs.Count]; _penContexts = new WeakReference[penContextRefs.Count]; _handles = new IntPtr[penContextRefs.Count]; for (i=0; i < penContextRefs.Count; i++) { PenContext pc = penContextRefs[i]; // We'd have hole in our array if this ever happened. Debug.Assert(pc != null && pc.CommHandle != IntPtr.Zero); _handles[i] = pc.CommHandle; // Add to array. _pimcContexts[i] = pc._pimcContext.Value; _penContexts[i] = new WeakReference(pc); pc = null; } result = true; } // Now clean up old refs and assign new array. penContextRefs.Clear(); // Make sure we remove refs! penContextRefs = null; return result; } /// /// Critical - Accesses SecurityCriticalData (penContext, _penContexts, PenContext.CommHandle, /// _pimcContexts, and _handles). /// [SecurityCritical] internal bool RemovePenContext(PenContext penContext) { ListpenContextRefs = new List (); // keep them alive while processing! int i; bool removed = false; // Now go through and figure out the good entries // Need to clean up the list for gc'd references. for (i=0; i<_penContexts.Length; i++) { if (_penContexts[i].IsAlive) { PenContext pc = _penContexts[i].Target as PenContext; // See if we should keep this PenContext. // We keep if not GC'd and not the removing one (except if it is // in range where we need to wait till it goes out of range). if (pc != null && (pc != penContext || pc.IsInRange(0))) { penContextRefs.Add(pc); } } } removed = !penContextRefs.Contains(penContext); // Now build up the handle array and PimcContext ref array. _pimcContexts = new IPimcContext[penContextRefs.Count]; _penContexts = new WeakReference[penContextRefs.Count]; _handles = new IntPtr[penContextRefs.Count]; for (i=0; i < penContextRefs.Count; i++) { PenContext pc = penContextRefs[i]; // We'd have hole in our array if this ever happened. Debug.Assert(pc != null && pc.CommHandle != IntPtr.Zero); _handles[i] = pc.CommHandle; // Add to array. _pimcContexts[i] = pc._pimcContext.Value; _penContexts[i] = new WeakReference(pc); pc = null; } // Now clean up old refs and assign new array. penContextRefs.Clear(); // Make sure we remove refs! penContextRefs = null; return removed; } ///////////////////////////////////////////////////////////////////// /// /// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.GetPenEvent, /// MS.Win32.Penimc.UnsafeNativeMethods.GetPenEventMultiple, /// MS.Win32.Penimc.UnsafeNativeMethods.DestroyResetEvent, FireEvent and FlushCache) and /// accesses SecurityCriticalData (PenContext.CommHandle and _pimcResetHandle.Value). /// It is a thread proc so it is top of stack and is created by PenThreadWorker constructor. /// [SecurityCritical] internal void ThreadProc() { Thread.CurrentThread.Name = "Stylus Input"; try { // // the rarely iterated loop // while (!__disposed) { #if TRACEPTW Debug.WriteLine(String.Format("PenThreadWorker::ThreadProc(): Update __penContextWeakRefList loop")); #endif WorkerOperation [] workerOps = null; lock(_workerOperationLock) { if (_workerOperation.Count > 0) { workerOps = _workerOperation.ToArray(); _workerOperation.Clear(); } } if (workerOps != null) { for (int j=0; jList of constants for PenImc const int PenEventNone = 0; const int PenEventTimeout = 1; const int PenEventPenInRange = 707; const int PenEventPenOutOfRange = 708; const int PenEventPenDown = 709; const int PenEventPenUp = 710; const int PenEventPackets = 711; const int PenEventSystem = 714; const int MaxContextPerThread = 31; // (64 - 1) / 2 = 31. Max handle limit for MsgWaitForMultipleMessageEx() const int EventsFrequency = 8; /// /// Critical - Marked critical to prevent inadvertant code from modifying this. /// [SecurityCritical] IntPtr [] _handles = new IntPtr[0]; ////// Critical - Marked critical to prevent inadvertant code from modifying this. /// [SecurityCritical] WeakReference [] _penContexts = new WeakReference[0]; ////// Critical - Marked critical to prevent inadvertant code from modifying this. /// [SecurityCritical] IPimcContext [] _pimcContexts = new IPimcContext[0]; ////// SecurityCritical - This is got under an elevation and is hence critical. /// private SecurityCriticalData_pimcResetHandle; private volatile bool __disposed; private List _workerOperation = new List (); private object _workerOperationLock = new Object(); // For caching move events. /// /// Critical to prevent accidental spread to transparent code /// [SecurityCritical] private PenContext _cachedMovePenContext; private int _cachedMoveStylusPointerId; private int _cachedMoveStartTimestamp; private int [] _cachedMoveData; ///////////////////////////////////////////////////////////////////// // // Here's a bunch of helper classes to manage marshalling the calls // over to the worker thread to be executed synchronously. // ///////////////////////////////////////////////////////////////////// // Base class for all worker operations private abstract class WorkerOperation { AutoResetEvent _doneEvent; internal WorkerOperation() { _doneEvent = new AutoResetEvent(false); } ////// Critical - Calls SecurityCritical code OnDoWork which is differred based on the various derived class. /// Called by PenThreadWorker.ThreadProc(). /// [SecurityCritical] internal void DoWork() { try { OnDoWork(); } finally { _doneEvent.Set(); } } ////// Critical - Calls SecurityCritical code OnDoWork which is differred based on the various derived class. /// Called by WorkerOperation.DoWork(). /// [SecurityCritical] protected abstract void OnDoWork(); internal AutoResetEvent DoneEvent { get { return _doneEvent;} } } // Class that handles getting the current rect for a tablet device. private class WorkerOperationThreadStart : WorkerOperation { ///////////////////////////////////////////////////////////////////////// ////// Used to signal when the thread has started up. /// protected override void OnDoWork() { // We don't need to do anything. Just have event signal we've executed. } } // Class that handles getting the tablet device info for all tablets on the system. private class WorkerOperationGetTabletsInfo : WorkerOperation { internal TabletDeviceInfo[] TabletDevicesInfo { get { return _tabletDevicesInfo;} } ///////////////////////////////////////////////////////////////////////// ////// Returns the list of TabletDeviceInfo structs that contain information /// about all of the TabletDevices on the system. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - returns security critical data _pimcTablet /// [SecurityCritical] protected override void OnDoWork() { try { // create new collection of tablets MS.Win32.Penimc.IPimcManager pimcManager = MS.Win32.Penimc.UnsafeNativeMethods.PimcManager; uint cTablets; pimcManager.GetTabletCount(out cTablets); TabletDeviceInfo[] tablets = new TabletDeviceInfo[cTablets]; for ( uint iTablet = 0; iTablet < cTablets; iTablet++ ) { MS.Win32.Penimc.IPimcTablet pimcTablet; pimcManager.GetTablet(iTablet, out pimcTablet); tablets[iTablet] = PenThreadWorker.GetTabletInfoHelper(pimcTablet); } // Set result data and signal we are done. _tabletDevicesInfo = tablets; } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationGetTabletsInfo.OnDoWork failed due to a COMException"); // return no devices found on error. _tabletDevicesInfo = new TabletDeviceInfo[0]; } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to an ArgumentException. Debug.WriteLine("WorkerOperationGetTabletsInfo.OnDoWork failed due to an ArgumentException"); // return no devices found on error. _tabletDevicesInfo = new TabletDeviceInfo[0]; } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationGetTabletsInfo.OnDoWork failed due to an UnauthorizedAccessException"); // return no devices found on error. _tabletDevicesInfo = new TabletDeviceInfo[0]; } } TabletDeviceInfo[] _tabletDevicesInfo; } // Class that handles creating a context for a particular tablet device. private class WorkerOperationCreateContext : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationCreateContext(IntPtr hwnd, IPimcTablet pimcTablet) { _hwnd = hwnd; _pimcTablet = pimcTablet; } internal PenContextInfo Result { get { return _result;} } ///////////////////////////////////////////////////////////////////////// ////// Creates a new context for this a window and given tablet device and /// returns a new PenContext in the workOperation class. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handle security critical data _hwnd, _pimcTablet. /// [SecurityCritical] protected override void OnDoWork() { IPimcContext pimcContext; int id; IntPtr commHandle; try { _pimcTablet.CreateContext(_hwnd, true, 250, out pimcContext, out id, out commHandle); // Set result data and signal we are done. PenContextInfo result; result.ContextId = id; result.PimcContext = new SecurityCriticalDataClass(pimcContext); result.CommHandle = new SecurityCriticalDataClass (commHandle); _result = result; } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationCreateContext.OnDoWork failed due to a COMException"); // set with uninitialized PenContextInfo (all zero). _result = new PenContextInfo(); } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to an ArgumentException. Debug.WriteLine("WorkerOperationCreateContext.OnDoWork failed due to an ArgumentException"); // set with uninitialized PenContextInfo (all zero). _result = new PenContextInfo(); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationCreateContext.OnDoWork failed due to an UnauthorizedAccessException"); // set with uninitialized PenContextInfo (all zero). _result = new PenContextInfo(); } } /// /// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IntPtr _hwnd; ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IPimcTablet _pimcTablet; PenContextInfo _result; } // Class that handles refreshing the cursor devices for a particular tablet device. private class WorkerOperationRefreshCursorInfo : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationRefreshCursorInfo(IPimcTablet pimcTablet) { _pimcTablet = pimcTablet; } internal StylusDeviceInfo[] StylusDevicesInfo { get { return _stylusDevicesInfo; } } ///////////////////////////////////////////////////////////////////////// ////// Causes the stylus devices info (cursors) in penimc to be refreshed /// for the passed in IPimcTablet. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handle security critical data _pimcTablet. /// [SecurityCritical] protected override void OnDoWork() { try { _pimcTablet.RefreshCursorInfo(); _stylusDevicesInfo = PenThreadWorker.GetStylusDevicesInfo(_pimcTablet); } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationRefreshCursorInfo.OnDoWork failed due to a COMException"); } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to a ArgumentException. Debug.WriteLine("WorkerOperationRefreshCursorInfo.OnDoWork failed due to an ArgumentException"); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationRefreshCursorInfo.OnDoWork failed due to an UnauthorizedAccessException"); } } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IPimcTablet _pimcTablet; StylusDeviceInfo[] _stylusDevicesInfo; } // Class that handles getting info about a specific tablet device. private class WorkerOperationGetTabletInfo : WorkerOperation { internal WorkerOperationGetTabletInfo(uint index) { _index = index; } internal TabletDeviceInfo TabletDeviceInfo { get { return _tabletDeviceInfo;} } ///////////////////////////////////////////////////////////////////////// ////// Fills in a struct containing the list of TabletDevice properties for /// a given tablet device index. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - returns security critical data _pimcTablet /// [SecurityCritical] protected override void OnDoWork() { try { // create new collection of tablets MS.Win32.Penimc.IPimcManager pimcManager = MS.Win32.Penimc.UnsafeNativeMethods.PimcManager; MS.Win32.Penimc.IPimcTablet pimcTablet; pimcManager.GetTablet(_index, out pimcTablet); // Set result data and signal we are done. _tabletDeviceInfo = PenThreadWorker.GetTabletInfoHelper(pimcTablet); } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationGetTabletInfo.OnDoWork failed due to COMException"); // set to uninitialized TabletDeviceInfo struct (all zeros) to signal failure. _tabletDeviceInfo = new TabletDeviceInfo(); } catch ( System.ArgumentException ) { // result will not be initialized if we fail due to an ArgumentException. Debug.WriteLine("WorkerOperationGetTabletInfo.OnDoWork failed due to an ArgumentException"); // set to uninitialized TabletDeviceInfo struct (all zeros) to signal failure. _tabletDeviceInfo = new TabletDeviceInfo(); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationGetTabletInfo.OnDoWork failed due to an UnauthorizedAccessException"); // set to uninitialized TabletDeviceInfo struct (all zeros) to signal failure. _tabletDeviceInfo = new TabletDeviceInfo(); } } uint _index; TabletDeviceInfo _tabletDeviceInfo; } // Class that handles getting the current rect for a tablet device. private class WorkerOperationWorkerGetUpdatedSizes : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationWorkerGetUpdatedSizes(IPimcTablet pimcTablet) { _pimcTablet = pimcTablet; } internal TabletDeviceSizeInfo TabletDeviceSizeInfo { get { return _tabletDeviceSizeInfo;} } ///////////////////////////////////////////////////////////////////////// ////// Gets the current rectangle for a tablet device and returns in workOperation class. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data _pimcTablet /// [SecurityCritical] protected override void OnDoWork() { try { int displayWidth, displayHeight, tabletWidth, tabletHeight; _pimcTablet.GetTabletAndDisplaySize(out tabletWidth, out tabletHeight, out displayWidth, out displayHeight); // Set result data and signal we are done. _tabletDeviceSizeInfo = new TabletDeviceSizeInfo( new Size( tabletWidth, tabletHeight), new Size( displayWidth, displayHeight)); } catch ( System.Runtime.InteropServices.COMException ) { // result will not be initialized if we fail due to a COM exception. Debug.WriteLine("WorkerOperationWorkerGetUpdatedSizes.OnDoWork failed due to a COMException"); // Size structs will be 1x1 if a COM exception is thrown. Should be dead context anyway on exception. _tabletDeviceSizeInfo = new TabletDeviceSizeInfo(new Size( 1, 1), new Size( 1, 1)); } catch ( System.UnauthorizedAccessException ) { // result will not be initialized if we fail due to an UnauthorizedAccessException. Debug.WriteLine("WorkerOperationWorkerGetUpdatedSizes.OnDoWork failed due to an UnauthorizedAccessException"); // Size structs will be 1x1 if a COM exception is thrown. Should be dead context anyway on exception. _tabletDeviceSizeInfo = new TabletDeviceSizeInfo(new Size( 1, 1), new Size( 1, 1)); } } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] IPimcTablet _pimcTablet; TabletDeviceSizeInfo _tabletDeviceSizeInfo; } // Class that handles getting the current rect for a tablet device. private class WorkerOperationAddContext : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationAddContext(PenContext penContext, PenThreadWorker penThreadWorker) { _newPenContext = penContext; _penThreadWorker = penThreadWorker; } internal bool Result { get { return _result;} } ///////////////////////////////////////////////////////////////////////// ////// Adds a PenContext to the list of contexts that events can be received /// from and returns whether it was successful in workOperation class. /// ////// Critical: - handles security critical data _penContexts, _handles, _pimcContexts /// [SecurityCritical] protected override void OnDoWork() { _result = _penThreadWorker.AddPenContext(_newPenContext); } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenContext _newPenContext; ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenThreadWorker _penThreadWorker; bool _result; } // Class that handles getting the current rect for a tablet device. private class WorkerOperationRemoveContext : WorkerOperation { ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] internal WorkerOperationRemoveContext(PenContext penContext, PenThreadWorker penThreadWorker) { _penContextToRemove = penContext; _penThreadWorker = penThreadWorker; } internal bool Result { get { return _result;} } ///////////////////////////////////////////////////////////////////////// ////// Adds a PenContext to the list of contexts that events can be received /// from and returns whether it was successful in workOperation class. /// ////// Critical: - handles security critical data _penContexts, _handles, _pimcContexts /// [SecurityCritical] protected override void OnDoWork() { _result = _penThreadWorker.RemovePenContext(_penContextToRemove); } ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenContext _penContextToRemove; ////// Critical - Critical data got under an elevation and is hence critical. /// [SecurityCritical] PenThreadWorker _penThreadWorker; bool _result; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code MS.Win32.Penimc.UnsafeNativeMethods.CreateResetEvent /// and handles SecurityCritical data resetHandle. /// Called by PenThread constructor. /// TreatAsSafe boundry is Stylus.EnableCore, Stylus.RegisterHwndForInput /// and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal PenThreadWorker() { IntPtr resetHandle; // Consider: We could use a AutoResetEvent handle instead and avoid the penimc.dll call. MS.Win32.Penimc.UnsafeNativeMethods.CreateResetEvent(out resetHandle); _pimcResetHandle = new SecurityCriticalData(resetHandle); WorkerOperationThreadStart started = new WorkerOperationThreadStart(); lock(_workerOperationLock) { _workerOperation.Add((WorkerOperation)started); } Thread thread = new Thread(new ThreadStart(ThreadProc)); thread.IsBackground = true; // don't hold process open due to this thread. thread.Start(); // Wait for this work to be completed (ie thread is started up). started.DoneEvent.WaitOne(); started.DoneEvent.Close(); } /// /// Critical - Needs to call SupressUnmanagedCodeSecurity attributed /// code to free unmanaged resource handle. Needs to be /// SecurityCritical for that. Also references SecurityCriticalData. /// [SecurityCritical] internal void Dispose() { if(!__disposed) { __disposed = true; // Kick thread to wake up and see we are disposed. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Let it destroy the reset event. } GC.KeepAlive(this); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data penContext. /// Called by PenThread.AddPenContext. /// [SecurityCritical] internal bool WorkerAddPenContext(PenContext penContext) { if (__disposed) { throw new ObjectDisposedException(null, SR.Get(SRID.Penservice_Disposed)); } Debug.Assert(penContext != null); WorkerOperationAddContext addContextOperation = new WorkerOperationAddContext(penContext, this); lock(_workerOperationLock) { _workerOperation.Add(addContextOperation); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. addContextOperation.DoneEvent.WaitOne(); addContextOperation.DoneEvent.Close(); return addContextOperation.Result; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data penContext. /// Called by PenThread.Disable. /// [SecurityCritical] internal bool WorkerRemovePenContext(PenContext penContext) { if (__disposed) { return true; } Debug.Assert(penContext != null); WorkerOperationRemoveContext removeContextOperation = new WorkerOperationRemoveContext(penContext, this); lock(_workerOperationLock) { _workerOperation.Add(removeContextOperation); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. removeContextOperation.DoneEvent.WaitOne(); removeContextOperation.DoneEvent.Close(); return removeContextOperation.Result; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle. /// Called by PenThreadPool.WorkerGetTabletsInfo. /// [SecurityCritical] internal TabletDeviceInfo[] WorkerGetTabletsInfo() { // Set data up for this call WorkerOperationGetTabletsInfo getTablets = new WorkerOperationGetTabletsInfo(); lock(_workerOperationLock) { _workerOperation.Add(getTablets); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. getTablets.DoneEvent.WaitOne(); getTablets.DoneEvent.Close(); return getTablets.TabletDevicesInfo; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data /// (hwnd, pimcTablet). /// Called by PenThreadPool.WorkerCreateContext. /// TreatAsSafe boundry is Stylus.EnableCore and HwndWrapperHook class /// (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal PenContextInfo WorkerCreateContext(IntPtr hwnd, IPimcTablet pimcTablet) { WorkerOperationCreateContext createContextOperation = new WorkerOperationCreateContext( hwnd, pimcTablet); lock(_workerOperationLock) { _workerOperation.Add(createContextOperation); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. createContextOperation.DoneEvent.WaitOne(); createContextOperation.DoneEvent.Close(); return createContextOperation.Result; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and handles SecurityCritical data pimcTablet. /// Called by PenThreadPool.WorkerRefreshCursorInfo. /// [SecurityCritical] internal StylusDeviceInfo[] WorkerRefreshCursorInfo(IPimcTablet pimcTablet) { WorkerOperationRefreshCursorInfo refreshCursorInfo = new WorkerOperationRefreshCursorInfo( pimcTablet); lock(_workerOperationLock) { _workerOperation.Add(refreshCursorInfo); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. refreshCursorInfo.DoneEvent.WaitOne(); refreshCursorInfo.DoneEvent.Close(); return refreshCursorInfo.StylusDevicesInfo; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle. /// Called by PenThreadPool.WorkerGetTabletInfo. /// [SecurityCritical] internal TabletDeviceInfo WorkerGetTabletInfo(uint index) { // Set up data for call WorkerOperationGetTabletInfo getTabletInfo = new WorkerOperationGetTabletInfo( index); lock(_workerOperationLock) { _workerOperation.Add(getTabletInfo); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. getTabletInfo.DoneEvent.WaitOne(); getTabletInfo.DoneEvent.Close(); return getTabletInfo.TabletDeviceInfo; } ////// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent), /// accesses SecurityCriticalData _pimcResetHandle and pimcTablet. /// Called by PenThreadPool.WorkerGetUpdatedTabletRect. /// [SecurityCritical] internal TabletDeviceSizeInfo WorkerGetUpdatedSizes(IPimcTablet pimcTablet) { // Set data up for call WorkerOperationWorkerGetUpdatedSizes getUpdatedSizes = new WorkerOperationWorkerGetUpdatedSizes(pimcTablet); lock(_workerOperationLock) { _workerOperation.Add(getUpdatedSizes); } // Kick thread to do this work. MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle.Value); // Wait for this work to be completed. getUpdatedSizes.DoneEvent.WaitOne(); getUpdatedSizes.DoneEvent.Close(); return getUpdatedSizes.TabletDeviceSizeInfo; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code PenContext.FirePenInRange and PenContext.FirePackets. /// Called by FireEvent and ThreadProc. /// TreatAsSafe boundry is ThreadProc. /// [SecurityCritical] void FlushCache(bool goingOutOfRange) { // Force any cached move/inairmove data to be flushed if we have any. if (_cachedMoveData != null) { // If we are going out of range and this stylus id is not currently in range // then eat these cached events (keeps from going in and out of range quickly) if (!goingOutOfRange || _cachedMovePenContext.IsInRange(_cachedMoveStylusPointerId)) { _cachedMovePenContext.FirePenInRange(_cachedMoveStylusPointerId, _cachedMoveData, _cachedMoveStartTimestamp); _cachedMovePenContext.FirePackets(_cachedMoveStylusPointerId, _cachedMoveData, _cachedMoveStartTimestamp); } _cachedMoveData = null; _cachedMovePenContext = null; _cachedMoveStylusPointerId = 0; } } ///////////////////////////////////////////////////////////////////// ////// SecurityCritical: Accesses SecurityCritical data _cachedMovePenContext. /// [SecurityCritical] bool DoCacheEvent(int evt, PenContext penContext, int stylusPointerId, int [] data, int timestamp) { // NOTE: Big assumption is that we always get other events between packets (ie don't get move // down position followed by move in up position). We don't account for that here but it should // never happen. if (evt == PenEventPackets) { // If no cache then just cache it. if (_cachedMoveData == null) { _cachedMovePenContext = penContext; _cachedMoveStylusPointerId = stylusPointerId; _cachedMoveStartTimestamp = timestamp; _cachedMoveData = data; return true; } else if (_cachedMovePenContext == penContext && stylusPointerId == _cachedMoveStylusPointerId) { int sinceBeginning = timestamp - _cachedMoveStartTimestamp; if (timestamp < _cachedMoveStartTimestamp) sinceBeginning = (Int32.MaxValue - _cachedMoveStartTimestamp) + timestamp; if (EventsFrequency > sinceBeginning) { // Add to cache data int[] data0 = _cachedMoveData; _cachedMoveData = new int [data0.Length + data.Length]; data0.CopyTo(_cachedMoveData, 0); data.CopyTo(_cachedMoveData, data0.Length); return true; } } } return false; } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code FlushCache, PenContext.FirePenDown, PenContext.FirePenUp, /// PenContext.FirePenInRange, PenContext.FirePackets, PenContext.FirePenOutOfRange, PenContext.FireSystemGesture. /// Called by ThreadProc. /// TreatAsSafe boundry is ThreadProc. /// [SecurityCritical] internal void FireEvent(PenContext penContext, int evt, int stylusPointerId, int cPackets, int cbPacket, IntPtr pPackets) { // disposed? if (__disposed) { return; // Don't process this event if we're in the process of shutting down. } // marshal the data to our cache if (cbPacket % 4 != 0) { throw new InvalidOperationException(SR.Get(SRID.PenService_InvalidPacketData)); } int cItems = cPackets * (cbPacket / 4); int[] data = null; if (0 < cItems) { data = new int [cItems]; // GetDataArray(cItems); // see comment on GetDataArray Marshal.Copy(pPackets, data, 0, cItems); } else { data = null; } int timestamp = Environment.TickCount; // Deal with caching packet data. if (DoCacheEvent(evt, penContext, stylusPointerId, data, timestamp)) { return; } else { FlushCache(false); // make sure we flush cache if not caching. } // // fire it // switch (evt) { case PenEventPenDown: penContext.FirePenInRange(stylusPointerId, data, timestamp); penContext.FirePenDown(stylusPointerId, data, timestamp); break; case PenEventPenUp: penContext.FirePenInRange(stylusPointerId, data, timestamp); penContext.FirePenUp(stylusPointerId, data, timestamp); break; case PenEventPackets: penContext.FirePenInRange(stylusPointerId, data, timestamp); penContext.FirePackets(stylusPointerId, data, timestamp); break; case PenEventPenInRange: // We fire this special event just to give the app thread an early peak at // the inrange to filter out mouse moves before we get our first stylus event. penContext.FirePenInRange(stylusPointerId, null, timestamp); break; case PenEventPenOutOfRange: penContext.FirePenOutOfRange(stylusPointerId, timestamp); break; case PenEventSystem: penContext.FireSystemGesture(stylusPointerId, timestamp); break; } } ///////////////////////////////////////////////////////////////////////// ////// Returns a struct containing the list of TabletDevice properties for /// a given tablet device (pimcTablet). /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data pimcTablet /// [SecurityCritical] private static TabletDeviceInfo GetTabletInfoHelper(IPimcTablet pimcTablet) { TabletDeviceInfo tabletInfo = new TabletDeviceInfo(); tabletInfo.PimcTablet = new SecurityCriticalDataClass(pimcTablet); pimcTablet.GetKey(out tabletInfo.Id); pimcTablet.GetName(out tabletInfo.Name); pimcTablet.GetPlugAndPlayId(out tabletInfo.PlugAndPlayId); int iTabletWidth, iTabletHeight, iDisplayWidth, iDisplayHeight; pimcTablet.GetTabletAndDisplaySize(out iTabletWidth, out iTabletHeight, out iDisplayWidth, out iDisplayHeight); tabletInfo.SizeInfo = new TabletDeviceSizeInfo(new Size(iTabletWidth, iTabletHeight), new Size(iDisplayWidth, iDisplayHeight)); int caps; pimcTablet.GetHardwareCaps(out caps); tabletInfo.HardwareCapabilities = (TabletHardwareCapabilities)caps; int deviceType; pimcTablet.GetDeviceType(out deviceType); tabletInfo.DeviceType = (TabletDeviceType)(deviceType -1); // NTRAID:WINDOWSOS#1679154-2006/06/09-WAYNEZEN, // REENTRANCY NOTE: Let a PenThread do this work to avoid reentrancy! // The IPimcTablet object is created in the pen thread. If we access it from the UI thread, // COM will set up message pumping which will cause reentrancy here. InitializeSupportedStylusPointProperties(pimcTablet, tabletInfo); tabletInfo.StylusDevicesInfo = GetStylusDevicesInfo(pimcTablet); return tabletInfo; } ///////////////////////////////////////////////////////////////////////// /// /// Initializing the supported stylus point properties. and returns in workOperation class. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data pimcTablet /// [SecurityCritical] private static void InitializeSupportedStylusPointProperties(IPimcTablet pimcTablet, TabletDeviceInfo tabletInfo) { int cProps; int cButtons; int pressureIndex = -1; pimcTablet.GetPacketDescriptionInfo(out cProps, out cButtons); // Calls Unmanaged code - SecurityCritical with SUC. Listproperties = new List (cProps + cButtons + 3); for ( int i = 0; i < cProps; i++ ) { Guid guid; int min, max; int units; float res; pimcTablet.GetPacketPropertyInfo(i, out guid, out min, out max, out units, out res); // Calls Unmanaged code - SecurityCritical with SUC. if ( pressureIndex == -1 && guid == StylusPointPropertyIds.NormalPressure ) { pressureIndex = i; } StylusPointProperty property = new StylusPointProperty(guid, false); properties.Add(property); } for ( int i = 0; i < cButtons; i++ ) { Guid buttonGuid; pimcTablet.GetPacketButtonInfo(i, out buttonGuid); // Calls Unmanaged code - SecurityCritical with SUC. StylusPointProperty buttonProperty = new StylusPointProperty(buttonGuid, true); properties.Add(buttonProperty); } //validate we can never get X, Y at index != 0, 1 Debug.Assert(properties[StylusPointDescription.RequiredXIndex /*0*/].Id == StylusPointPropertyIds.X, "X isn't where we expect it! Fix PenImc to ask for X at index 0"); Debug.Assert(properties[StylusPointDescription.RequiredYIndex /*1*/].Id == StylusPointPropertyIds.Y, "Y isn't where we expect it! Fix PenImc to ask for Y at index 1"); // NOTE: We can't force pressure since touch digitizers may not provide this info. The following assert is bogus. //Debug.Assert(pressureIndex == -1 || pressureIndex == StylusPointDescription.RequiredPressureIndex /*2*/, // "Fix PenImc to ask for NormalPressure at index 2!"); if ( pressureIndex == -1 ) { //pressure wasn't found. Add it properties.Insert(StylusPointDescription.RequiredPressureIndex /*2*/, System.Windows.Input.StylusPointProperties.NormalPressure); } else { //this device supports pressure tabletInfo.HardwareCapabilities |= TabletHardwareCapabilities.SupportsPressure; } tabletInfo.StylusPointProperties = new ReadOnlyCollection (properties); tabletInfo.PressureIndex = pressureIndex; } ///////////////////////////////////////////////////////////////////////// /// /// Getting the cursor info of the stylus devices. /// ////// Critical: - calls into unmanaged code that is SecurityCritical with SUC attribute. /// - handles security critical data pimcTablet /// [SecurityCritical] private static StylusDeviceInfo[] GetStylusDevicesInfo(IPimcTablet pimcTablet) { int cCursors; pimcTablet.GetCursorCount(out cCursors); // Calls Unmanaged code - SecurityCritical with SUC. StylusDeviceInfo[] stylusDevicesInfo = new StylusDeviceInfo[cCursors]; for ( int iCursor = 0; iCursor < cCursors; iCursor++ ) { string sCursorName; int cursorId; bool fCursorInverted; pimcTablet.GetCursorInfo(iCursor, out sCursorName, out cursorId, out fCursorInverted); // Calls Unmanaged code - SecurityCritical with SUC. int cButtons; pimcTablet.GetCursorButtonCount(iCursor, out cButtons); // Calls Unmanaged code - SecurityCritical with SUC. StylusButton[] buttons = new StylusButton[cButtons]; for ( int iButton = 0; iButton < cButtons; iButton++ ) { string sButtonName; Guid buttonGuid; pimcTablet.GetCursorButtonInfo(iCursor, iButton, out sButtonName, out buttonGuid); // Calls Unmanaged code - SecurityCritical with SUC. buttons[iButton] = new StylusButton(sButtonName, buttonGuid); } StylusButtonCollection buttonCollection = new StylusButtonCollection(buttons); stylusDevicesInfo[iCursor].CursorName = sCursorName; stylusDevicesInfo[iCursor].CursorId = cursorId; stylusDevicesInfo[iCursor].CursorInverted = fCursorInverted; stylusDevicesInfo[iCursor].ButtonCollection = buttonCollection; } return stylusDevicesInfo; } ////// Critical - Accesses SecurityCriticalData (penContext, _penContexts, PenContext.CommHandle, /// _pimcContexts, and _handles). /// [SecurityCritical] internal bool AddPenContext(PenContext penContext) { ListpenContextRefs = new List (); // keep them alive while processing! int i; bool result = false; // Now go through and figure out the good entries // Need to clean up the list for gc'd references. for (i=0; i<_penContexts.Length; i++) { if (_penContexts[i].IsAlive) { PenContext pc = _penContexts[i].Target as PenContext; // We only need to ref if we have a penContext. if (pc != null) { penContextRefs.Add(pc); } } } // Now try again to see if we have room. if (penContextRefs.Count < MaxContextPerThread) { penContextRefs.Add(penContext); // add the new one to our list. // Now build up the handle array and PimcContext ref array. _pimcContexts = new IPimcContext[penContextRefs.Count]; _penContexts = new WeakReference[penContextRefs.Count]; _handles = new IntPtr[penContextRefs.Count]; for (i=0; i < penContextRefs.Count; i++) { PenContext pc = penContextRefs[i]; // We'd have hole in our array if this ever happened. Debug.Assert(pc != null && pc.CommHandle != IntPtr.Zero); _handles[i] = pc.CommHandle; // Add to array. _pimcContexts[i] = pc._pimcContext.Value; _penContexts[i] = new WeakReference(pc); pc = null; } result = true; } // Now clean up old refs and assign new array. penContextRefs.Clear(); // Make sure we remove refs! penContextRefs = null; return result; } /// /// Critical - Accesses SecurityCriticalData (penContext, _penContexts, PenContext.CommHandle, /// _pimcContexts, and _handles). /// [SecurityCritical] internal bool RemovePenContext(PenContext penContext) { ListpenContextRefs = new List (); // keep them alive while processing! int i; bool removed = false; // Now go through and figure out the good entries // Need to clean up the list for gc'd references. for (i=0; i<_penContexts.Length; i++) { if (_penContexts[i].IsAlive) { PenContext pc = _penContexts[i].Target as PenContext; // See if we should keep this PenContext. // We keep if not GC'd and not the removing one (except if it is // in range where we need to wait till it goes out of range). if (pc != null && (pc != penContext || pc.IsInRange(0))) { penContextRefs.Add(pc); } } } removed = !penContextRefs.Contains(penContext); // Now build up the handle array and PimcContext ref array. _pimcContexts = new IPimcContext[penContextRefs.Count]; _penContexts = new WeakReference[penContextRefs.Count]; _handles = new IntPtr[penContextRefs.Count]; for (i=0; i < penContextRefs.Count; i++) { PenContext pc = penContextRefs[i]; // We'd have hole in our array if this ever happened. Debug.Assert(pc != null && pc.CommHandle != IntPtr.Zero); _handles[i] = pc.CommHandle; // Add to array. _pimcContexts[i] = pc._pimcContext.Value; _penContexts[i] = new WeakReference(pc); pc = null; } // Now clean up old refs and assign new array. penContextRefs.Clear(); // Make sure we remove refs! penContextRefs = null; return removed; } ///////////////////////////////////////////////////////////////////// /// /// Critical - Calls SecurityCritical code (MS.Win32.Penimc.UnsafeNativeMethods.GetPenEvent, /// MS.Win32.Penimc.UnsafeNativeMethods.GetPenEventMultiple, /// MS.Win32.Penimc.UnsafeNativeMethods.DestroyResetEvent, FireEvent and FlushCache) and /// accesses SecurityCriticalData (PenContext.CommHandle and _pimcResetHandle.Value). /// It is a thread proc so it is top of stack and is created by PenThreadWorker constructor. /// [SecurityCritical] internal void ThreadProc() { Thread.CurrentThread.Name = "Stylus Input"; try { // // the rarely iterated loop // while (!__disposed) { #if TRACEPTW Debug.WriteLine(String.Format("PenThreadWorker::ThreadProc(): Update __penContextWeakRefList loop")); #endif WorkerOperation [] workerOps = null; lock(_workerOperationLock) { if (_workerOperation.Count > 0) { workerOps = _workerOperation.ToArray(); _workerOperation.Clear(); } } if (workerOps != null) { for (int j=0; j
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- KeyBinding.cs
- DocumentOrderComparer.cs
- DesignerActionUIStateChangeEventArgs.cs
- FixedLineResult.cs
- XmlFormatExtensionPrefixAttribute.cs
- Button.cs
- AttachInfo.cs
- ExpressionBuilderCollection.cs
- EntityDataSourceUtil.cs
- TransformerInfoCollection.cs
- StateWorkerRequest.cs
- SecurityRequiresReviewAttribute.cs
- WindowsPrincipal.cs
- WindowsRegion.cs
- TypeAccessException.cs
- ProtocolElementCollection.cs
- XmlUtilWriter.cs
- XmlNodeChangedEventArgs.cs
- ToggleProviderWrapper.cs
- HeaderCollection.cs
- AttachedAnnotation.cs
- MDIWindowDialog.cs
- XmlSchemaGroup.cs
- XmlSchemaSimpleTypeList.cs
- StringDictionaryCodeDomSerializer.cs
- MonitoringDescriptionAttribute.cs
- WebPartCollection.cs
- FolderLevelBuildProviderAppliesToAttribute.cs
- WebPartConnectVerb.cs
- OleDbParameter.cs
- CatalogPartCollection.cs
- SelectionChangedEventArgs.cs
- SqlCharStream.cs
- SourceFileBuildProvider.cs
- GridViewRowPresenterBase.cs
- SqlTrackingService.cs
- XmlNodeChangedEventArgs.cs
- DataGridViewRowCollection.cs
- DispatcherTimer.cs
- QilExpression.cs
- VisualStyleInformation.cs
- WorkflowApplicationException.cs
- DefaultTextStore.cs
- MultiDataTrigger.cs
- CodeSubDirectoriesCollection.cs
- PointConverter.cs
- Parser.cs
- CqlParserHelpers.cs
- SmiTypedGetterSetter.cs
- DocumentViewer.cs
- ResourceManager.cs
- SafeBitVector32.cs
- ComplexTypeEmitter.cs
- SQLInt32Storage.cs
- GridViewCommandEventArgs.cs
- CoTaskMemHandle.cs
- PrePostDescendentsWalker.cs
- KeyEvent.cs
- SafeFileMappingHandle.cs
- StringResourceManager.cs
- ShellProvider.cs
- ellipse.cs
- FloaterParagraph.cs
- HtmlValidationSummaryAdapter.cs
- DispatcherHookEventArgs.cs
- PointConverter.cs
- MachineKeyConverter.cs
- Range.cs
- ActivityMarkupSerializer.cs
- MessageEncoder.cs
- HandleExceptionArgs.cs
- MemberNameValidator.cs
- OperationCanceledException.cs
- VariableValue.cs
- XPathNavigatorKeyComparer.cs
- HScrollBar.cs
- SafeUserTokenHandle.cs
- TypeDelegator.cs
- TemplateInstanceAttribute.cs
- HostVisual.cs
- HwndAppCommandInputProvider.cs
- RunClient.cs
- CryptoConfig.cs
- DataGridViewRowErrorTextNeededEventArgs.cs
- NameScopePropertyAttribute.cs
- BindingValueChangedEventArgs.cs
- BinaryMethodMessage.cs
- CqlIdentifiers.cs
- ColorAnimationUsingKeyFrames.cs
- LongTypeConverter.cs
- TypeForwardedToAttribute.cs
- TouchesCapturedWithinProperty.cs
- ThrowHelper.cs
- XmlSchemaAll.cs
- SqlTriggerContext.cs
- SqlUtil.cs
- MimeObjectFactory.cs
- FtpCachePolicyElement.cs
- SqlAliaser.cs
- TableParagraph.cs