Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Input / Stylus / PenThreadWorker.cs / 1 / PenThreadWorker.cs
//#define TRACE
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 = 30;
///
/// 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.
List properties = 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)
{
List penContextRefs = 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)
{
List penContextRefs = 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 TRACE
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 = 30;
///
/// 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.
List properties = 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)
{
List penContextRefs = 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)
{
List penContextRefs = 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 TRACE
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
- DataGridViewColumnHeaderCell.cs
- CodeBinaryOperatorExpression.cs
- TextRunTypographyProperties.cs
- StdValidatorsAndConverters.cs
- VirtualPathProvider.cs
- SynchronizedInputProviderWrapper.cs
- TranslateTransform.cs
- LongTypeConverter.cs
- TreeChangeInfo.cs
- TextEditorDragDrop.cs
- AccessedThroughPropertyAttribute.cs
- SoapTypeAttribute.cs
- Operators.cs
- SmiEventSink_DeferedProcessing.cs
- ColumnWidthChangedEvent.cs
- RecordsAffectedEventArgs.cs
- Geometry.cs
- DataServiceRequestOfT.cs
- PropertyDescriptorComparer.cs
- ButtonFlatAdapter.cs
- ColorEditor.cs
- TableHeaderCell.cs
- DataColumnMapping.cs
- Int32KeyFrameCollection.cs
- ScanQueryOperator.cs
- XsltSettings.cs
- XmlTypeAttribute.cs
- ReferentialConstraint.cs
- ParseNumbers.cs
- FileDialogCustomPlace.cs
- DbFunctionCommandTree.cs
- KeyInterop.cs
- FontFaceLayoutInfo.cs
- ControllableStoryboardAction.cs
- Point4DValueSerializer.cs
- ReflectionUtil.cs
- XmlValidatingReader.cs
- SafeEventLogReadHandle.cs
- ClientScriptManagerWrapper.cs
- StylusDownEventArgs.cs
- DataGridViewTextBoxCell.cs
- HeaderedContentControl.cs
- WindowsListViewSubItem.cs
- typedescriptorpermissionattribute.cs
- FragmentQueryKB.cs
- TypeUsage.cs
- BrowserCapabilitiesFactoryBase.cs
- HtmlInputButton.cs
- TextDecoration.cs
- ResourceExpressionEditorSheet.cs
- EventMappingSettingsCollection.cs
- FrameworkTemplate.cs
- XpsFixedDocumentReaderWriter.cs
- odbcmetadatacollectionnames.cs
- GridViewColumnHeader.cs
- DropDownButton.cs
- BatchParser.cs
- ToolStripRenderer.cs
- ObjectDataSourceEventArgs.cs
- Dump.cs
- TextParagraphCache.cs
- DesignSurfaceEvent.cs
- ThreadExceptionEvent.cs
- FixedTextPointer.cs
- SQLMoneyStorage.cs
- TypeGenericEnumerableViewSchema.cs
- PartitionedStream.cs
- DataSetMappper.cs
- HttpWriter.cs
- FloaterBaseParaClient.cs
- PartBasedPackageProperties.cs
- GlyphRun.cs
- TdsEnums.cs
- CollectionBuilder.cs
- ConnectionsZone.cs
- PassportAuthentication.cs
- RadialGradientBrush.cs
- ColumnWidthChangedEvent.cs
- LineGeometry.cs
- DeploymentSection.cs
- __Filters.cs
- SplineKeyFrames.cs
- BooleanAnimationBase.cs
- CurrentChangingEventManager.cs
- TextBlockAutomationPeer.cs
- Package.cs
- FormatterConverter.cs
- IsolatedStorageFilePermission.cs
- QueryStringParameter.cs
- BitmapEffect.cs
- dbenumerator.cs
- FormViewRow.cs
- SwitchElementsCollection.cs
- GotoExpression.cs
- SchemaConstraints.cs
- ScrollChangedEventArgs.cs
- CheckBoxStandardAdapter.cs
- OleDbReferenceCollection.cs
- DataTableClearEvent.cs
- EffectiveValueEntry.cs