Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / System / Windows / Input / Stylus / TabletCollection.cs / 1 / TabletCollection.cs
//// Copyright (C) Microsoft Corporation. All rights reserved. // using System; using System.Diagnostics; using System.Windows; using System.Collections; using System.Globalization; using System.Windows.Media; using MS.Utility; using System.Security; using System.Security.Permissions; using MS.Internal; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using MS.Win32.Penimc; using System.Runtime.InteropServices; using MS.Win32; using Microsoft.Win32; namespace System.Windows.Input { ///////////////////////////////////////////////////////////////////////// ////// Collection of the tablet devices that are available on the machine. /// public class TabletDeviceCollection : ICollection, IEnumerable { const int VistaMajorVersion = 6; ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ////// Critical: Calls ShouldEnableTablets /// [SecurityCritical] internal TabletDeviceCollection() { StylusLogic stylusLogic = StylusLogic.CurrentStylusLogic; bool enabled = stylusLogic.Enabled; if (!enabled) { enabled = ShouldEnableTablets(); } // If enabled or we are a tabletpc (vista sets dynamically if digitizers present) then enable the pen! if (enabled) { UpdateTablets(); // Create the tablet device collection! // Enable stylus input on all hwnds if we have not yet done so. if (!stylusLogic.Enabled) { stylusLogic.EnableCore(); } } } ////// Checks if Tablets should be enabled. /// ////// /// Critical: Calls SecurityCritical routines (IsWisptisRegistered, /// HasTabletDevices, UnsafeNativeMethods.GetSystemMetrics, /// PenThreadPool.GetPenThreadForPenContext, PenThread.WorkerGetTabletsInfo, /// TabletDevice constructor, StylusLogic.EnableCore and /// StylusLogic.CurrentStylusLogic). /// [SecurityCritical] internal static bool ShouldEnableTablets() { bool enabled = false; // We only want to enable by default if Wisptis is registered and tablets are detected. // We do the same detection on all OS versions. // // NOTE: This code does not support the new Vista wisptis feature to be able to exclude // tablet devices using a special registy key. The only side effect of not supporting // this feature is that we would go ahead and load wisptis when we really don't need to // (since wisptis would not return us any tablet devices). This should be a fairly rare // case though. if (IsWisptisRegistered() && HasTabletDevices()) { enabled = true; // start up wisptis } return enabled; } ////// Critical - Asserts read registry permission... /// - TreatAsSafe boundry is HwndSource constructor and Tablet.TabletDevices. /// - called by this objects constructor /// [SecurityCritical] private static bool IsWisptisRegistered() { bool fRegistered = false; RegistryKey key = null; // This object has finalizer to close the key. Object valDefault = null; bool runningOnVista = (Environment.OSVersion.Version.Major >= VistaMajorVersion); string keyToAssertPermissionFor = runningOnVista ? "HKEY_CLASSES_ROOT\\Interface\\{C247F616-BBEB-406A-AED3-F75E656599AE}" : "HKEY_CLASSES_ROOT\\CLSID\\{A5B020FD-E04B-4e67-B65A-E7DEED25B2CF}\\LocalServer32"; string subkeyToOpen = runningOnVista ? "Interface\\{C247F616-BBEB-406A-AED3-F75E656599AE}" : "CLSID\\{A5B020FD-E04B-4e67-B65A-E7DEED25B2CF}\\LocalServer32"; string valueToSearchFor = runningOnVista ? "ITablet2" : "wisptis.exe"; // Perform the OS specific check for wisptis new RegistryPermission(RegistryPermissionAccess.Read, keyToAssertPermissionFor).Assert(); // BlessedAssert try { key = Registry.ClassesRoot.OpenSubKey(subkeyToOpen); if (key != null) { valDefault = key.GetValue(""); } } finally { RegistryPermission.RevertAssert(); } if (key != null) { string sValDefault = valDefault as string; if (sValDefault != null && sValDefault.LastIndexOf(valueToSearchFor, StringComparison.OrdinalIgnoreCase) != -1) { fRegistered = true; } key.Close(); } return fRegistered; } ////// Critical - Calls critical methods (GetRawInputDeviceList, GetRawInputDeviceInfo, Marshal.SizeOf). /// - TreatAsSafe boundry is HwndSource constructor and Tablet.TabletDevices. /// - called by constructor /// [SecurityCritical] private static bool HasTabletDevices() { uint deviceCount = 0; // Determine the number of devices first (result will be -1 if fails and cDevices will have count) int result = (int)MS.Win32.UnsafeNativeMethods.GetRawInputDeviceList(null, ref deviceCount, (uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTDEVICELIST))); if (result >= 0 && deviceCount != 0) { NativeMethods.RAWINPUTDEVICELIST[] ridl = new NativeMethods.RAWINPUTDEVICELIST[deviceCount]; int count = (int)MS.Win32.UnsafeNativeMethods.GetRawInputDeviceList(ridl, ref deviceCount, (uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTDEVICELIST))); if (count > 0) { for (int i = 0; i < count; i++) { if (ridl[i].dwType == NativeMethods.RIM_TYPEHID) { NativeMethods.RID_DEVICE_INFO deviceInfo = new NativeMethods.RID_DEVICE_INFO(); deviceInfo.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.RID_DEVICE_INFO)); uint cbSize = (uint)deviceInfo.cbSize; int cBytes = (int)MS.Win32.UnsafeNativeMethods.GetRawInputDeviceInfo(ridl[i].hDevice, NativeMethods.RIDI_DEVICEINFO, ref deviceInfo, ref cbSize); if (cBytes > 0) { if (deviceInfo.hid.usUsagePage == NativeMethods.HID_USAGE_PAGE_DIGITIZER) { switch (deviceInfo.hid.usUsage) { case NativeMethods.HID_USAGE_DIGITIZER_DIGITIZER: case NativeMethods.HID_USAGE_DIGITIZER_PEN: case NativeMethods.HID_USAGE_DIGITIZER_TOUCHSCREEN: case NativeMethods.HID_USAGE_DIGITIZER_LIGHTPEN: { return true; } } } } else { System.Diagnostics.Debug.WriteLine("TabletDeviceCollection: GetRawInputDeviceInfo failed!"); } } } } else if (count < 0) { System.Diagnostics.Debug.WriteLine("TabletDeviceCollection: GetRawInputDeviceList failed!"); } } return false; } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code with SuppressUnmangedCode /// (GetTabletCount, GetTablet, PimcPInvoke and PimcManager) /// and calls SecurityCritical code TabletDevice constructor. /// [SecurityCritical] internal void UpdateTablets() { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); // REENTRANCY NOTE: Let a PenThread do this work to avoid reentrancy! // On return you get entire list of tablet and info needed to // create all the tablet devices (and stylus device info gets // cached too in penimc which avoids calls to wisptis.exe). // Use existing penthread if we have one otherwise grab an available one. PenThread penThread = _tablets.Length > 0 ? _tablets[0].PenThread : PenThreadPool.GetPenThreadForPenContext(null); TabletDeviceInfo [] tabletdevices = penThread.WorkerGetTabletsInfo(); // First find out the index of the mouse device (usually the first at index 0) uint indexMouseTablet = UInt32.MaxValue; for (uint i = 0; i < tabletdevices.Length; i++) { // See if this is a bogus entry first. if (tabletdevices[i].PimcTablet == null) continue; // If it is the mouse tablet device we want to ignore it. if (tabletdevices[i].DeviceType == (TabletDeviceType)(-1)) { indexMouseTablet = i; tabletdevices[i].PimcTablet = null; // ignore this one! } } // Now figure out count of valid tablet devices left uint count = 0; for (uint k = 0; k < tabletdevices.Length; k++) { if (tabletdevices[k].PimcTablet != null) count++; } TabletDevice[] tablets = new TabletDevice[count]; uint tabletsIndex = 0; for (uint iTablet = 0; iTablet < tabletdevices.Length; iTablet++) { if (tabletdevices[iTablet].PimcTablet == null) { continue; // Skip looking at this index (mouse and bogus tablets are ignored). } int id = tabletdevices[iTablet].Id; // First see if same index has not changed (typical case) if (tabletsIndex < _tablets.Length && _tablets[tabletsIndex].Id == id) { tablets[tabletsIndex] = _tablets[tabletsIndex]; _tablets[tabletsIndex] = null; // clear to ignore on cleanup pass. } else { // Look up and see if we have this tabletdevice created already... TabletDevice tablet = null; for (uint i = 0; i < _tablets.Length; i++) { if (_tablets[i] != null && _tablets[i].Id == id) { tablet = _tablets[i]; _tablets[i] = null; // clear it so we don't dispose it. break; } } // Not found so create it. if (tablet == null) { try { tablet = new TabletDevice(tabletdevices[iTablet], penThread); } catch (InvalidOperationException ex) { // This is caused by the Stylus ID not being unique when trying // to register it in the StylusLogic.__stylusDeviceMap. If we // come across a dup then just ignore registering this tablet device. // There seems to be an issue in wisptis where different tablet IDs get // duplicate Stylus Ids when installing the VHID test devices. if (ex.Data.Contains("System.Windows.Input.StylusLogic")) { continue; // Just go to next without adding this one. } else { throw; // not an expected exception, rethrow it. } } } tablets[tabletsIndex] = tablet; } tabletsIndex++; } // See if we need to re alloc the array due to invalid tabletdevice being seen. if (tabletsIndex != count) { TabletDevice[] updatedTablets = new TabletDevice[tabletsIndex]; Array.Copy(tablets, 0, updatedTablets, 0, tabletsIndex); tablets = updatedTablets; } DisposeTablets(); // Clean up any non null TabletDevice entries on old array. _tablets = tablets; // set updated tabletdevice array _indexMouseTablet = indexMouseTablet; } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code with SuppressUnmangedCode /// (GetTablet, PimcPInvoke and PimcManager) /// and calls SecurityCritical code TabletDevice constructor. /// [SecurityCritical] internal bool HandleTabletAdded(uint wisptisIndex, ref uint tabletIndexChanged) { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); tabletIndexChanged = UInt32.MaxValue; // REENTRANCY NOTE: Let a PenThread do this work to avoid reentrancy! // On return you get the tablet info needed to // create a tablet devices (and stylus device info gets // cached in penimc too which avoids calls to wisptis.exe). // Use existing penthread if we have one otherwise grab an available one. PenThread penThread = _tablets.Length > 0 ? _tablets[0].PenThread : PenThreadPool.GetPenThreadForPenContext(null); TabletDeviceInfo tabletInfo = penThread.WorkerGetTabletInfo(wisptisIndex); // If we failed due to a COM exception on the pen thread then return if (tabletInfo.PimcTablet == null) { return true; // make sure we rebuild our tablet collection. (return true + MaxValue). } // if mouse tabletdevice then ignore it. if (tabletInfo.DeviceType == (TabletDeviceType)(-1)) { _indexMouseTablet = wisptisIndex; // update index. return false; // TabletDevices did not change. } // Now see if this is a duplicate add call we want to filter out (ie - already added to tablet collection). uint indexFound = UInt32.MaxValue; for (uint i = 0; i < _tablets.Length; i++) { // If it is the mouse tablet device we want to ignore it. if (_tablets[i].Id == tabletInfo.Id) { indexFound = i; break; } } // We only want to add this if it is not currently in the collection. Wisptis will send // us duplicate adds at times so this is a work around for that issue. uint tabletIndex = UInt32.MaxValue; if (indexFound == UInt32.MaxValue) { tabletIndex = wisptisIndex; if (tabletIndex > _indexMouseTablet) { tabletIndex--; } else { _indexMouseTablet++; } // if index is out of range then ignore it. Return of MaxValue causes a rebuild of the devices. if (tabletIndex <= _tablets.Length) { try { // Add new tablet at end of collection AddTablet(tabletIndex, new TabletDevice(tabletInfo, penThread)); } catch (InvalidOperationException ex) { // This is caused by the Stylus ID not being unique when trying // to register it in the StylusLogic.__stylusDeviceMap. If we // come across a dup then we should rebuild the tablet device collection. // There seems to be an issue in wisptis where different tablet IDs get // duplicate Stylus Ids when installing the VHID test devices. if (ex.Data.Contains("System.Windows.Input.StylusLogic")) { return true; // trigger the tabletdevices to be rebuilt. } else { throw; // not an expected exception, rethrow it. } } tabletIndexChanged = tabletIndex; return true; } else { return true; // bogus index. Return true so that the caller can rebuild the collection. } } else { return false; // We found this tablet device already. Don't do anything. } } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code RemoveTablet. /// [SecurityCritical] internal uint HandleTabletRemoved(uint wisptisIndex) { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); // if mouse tabletdevice then ignore it. if (wisptisIndex == _indexMouseTablet) { _indexMouseTablet = UInt32.MaxValue; return UInt32.MaxValue; // Don't process this notification any further. } uint tabletIndex = wisptisIndex; if (wisptisIndex > _indexMouseTablet) { tabletIndex--; } else { // Must be less than _indexMouseTablet since equality is done above. _indexMouseTablet--; } // if index is out of range then ignore it. if (tabletIndex >= _tablets.Length) { return UInt32.MaxValue; // Don't process this notification any further. } // Remove tablet from collection RemoveTablet(tabletIndex); return tabletIndex; } ///////////////////////////////////////////////////////////////////// // NOTE: This routine takes indexes that are in the TabletCollection range // and not in the wisptis tablet index range. ////// Critical: calls into SecurityCritical code TabletDevice constructor. /// [SecurityCritical] void AddTablet(uint index, TabletDevice tabletDevice) { Debug.Assert(index <= Count); Debug.Assert(tabletDevice.Type != (TabletDeviceType)(-1)); // make sure not the mouse tablet device! TabletDevice[] newTablets = new TabletDevice[Count + 1]; uint preCopyCount = index; uint postCopyCount = (uint)_tablets.Length - index; Array.Copy(_tablets, 0, newTablets, 0, preCopyCount); newTablets[index] = tabletDevice; Array.Copy(_tablets, index, newTablets, index+1, postCopyCount); _tablets = newTablets; } ///////////////////////////////////////////////////////////////////// // NOTE: This routine takes indexes that are in the TabletCollection range // and not in the wisptis tablet index range. ////// Critical: calls SecurityCritical code TabletDevice.Dispose. /// and StylusLogic.SelectStylusDevice /// [SecurityCritical] void RemoveTablet(uint index) { System.Diagnostics.Debug.Assert(index < Count && Count > 0); TabletDevice removeTablet = _tablets[index]; TabletDevice[] tablets = new TabletDevice[_tablets.Length - 1]; uint preCopyCount = index; uint postCopyCount = (uint)_tablets.Length - index - 1; Array.Copy(_tablets, 0, tablets, 0, preCopyCount); Array.Copy(_tablets, index+1, tablets, index, postCopyCount); _tablets = tablets; // Make sure we release any references to a stylus device that may // have been removed if (Tablet.CurrentTabletDevice == removeTablet) { StylusLogic.CurrentStylusLogic.SelectStylusDevice(null, null, true); } removeTablet.Dispose(); } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code with SuppressUnmangedCode /// (GetTablet, PimcPInvoke and PimcManager) /// and calls SecurityCritical code TabletDevice constructor. /// [SecurityCritical] internal StylusDevice UpdateStylusDevices(int tabletId, int stylusId) { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); for (int iTablet = 0, cTablets = _tablets.Length; iTablet < cTablets; iTablet++) { TabletDevice tablet = _tablets[iTablet]; if (tablet.Id == tabletId) { // Make sure we don't get reentered during this call to penimc! using(tablet.Dispatcher.DisableProcessing()) { return tablet.UpdateStylusDevices(stylusId); } } } return null; } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code TabletDevice.Dispose. /// and StylusLogic.SelectStylusDevice /// [SecurityCritical] internal void DisposeTablets() { if (_tablets != null) { for (int iTablet = 0, cTablets = _tablets.Length; iTablet < cTablets; iTablet++) { if (_tablets[iTablet] != null) { // Make sure this stylus device is not the current one. if (Tablet.CurrentTabletDevice == _tablets[iTablet]) { StylusLogic.CurrentStylusLogic.SelectStylusDevice(null, null, true); } _tablets[iTablet].Dispose(); } } _tablets = null; } } ///////////////////////////////////////////////////////////////////// ////// Critical: - calls into security critical code (PenContext constructor /// and PenContext.CreateContext) /// - takes in data that is potential security risk (hwnd) /// [SecurityCritical] internal PenContext[] CreateContexts(IntPtr hwnd, PenContexts contexts) { int c = Count; PenContext[] ctxs = new PenContext[c]; int i = 0; foreach (TabletDevice tablet in _tablets) { ctxs[i] = tablet.CreateContext(hwnd, contexts); i++; } return ctxs; } ///////////////////////////////////////////////////////////////////// ////// Retrieve the number of TabletDevice objects in the collection. /// public int Count { get { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); return _tablets.Length; } } ///////////////////////////////////////////////////////////////////// ////// Copy the TabletDevice objects in the collection to another array. /// /// destination array /// position in destination array to begin copying void ICollection.CopyTo(Array array, int index) { // Delegate error checking to Array.Copy. Array.Copy(_tablets, 0, array, index, this.Count); } ///////////////////////////////////////////////////////////////////// ////// Copy the TabletDevice objects in the collection to another array /// of TabletDevices. /// /// destination array /// position in destination array to begin copying public void CopyTo(TabletDevice[] array, int index) { ((ICollection)this).CopyTo(array, index); } ///////////////////////////////////////////////////////////////////// ////// Retrieve the specified TabletDevice object from the collection. /// /// index of TabletDevice in collection to retrieve public TabletDevice this[int index] { get { if (index >= Count || index < 0) throw new ArgumentException(SR.Get(SRID.Stylus_IndexOutOfRange, index.ToString(System.Globalization.CultureInfo.InvariantCulture)), "index"); return _tablets[index]; } } ///////////////////////////////////////////////////////////////////// ////// Returns an object which can be used to lock during synchronization by collection users. /// public object SyncRoot { get { return this; } } ///////////////////////////////////////////////////////////////////// ////// /// Determine if the collection has thread-safe operations. /// public bool IsSynchronized { get { return false; } } ///////////////////////////////////////////////////////////////////// ////// Standard implementation of IEnumerable which enables callers to use the /// foreach construct to enumerate through each TabletDevice in the collection. /// IEnumerator IEnumerable.GetEnumerator() { return new TabletDeviceEnumerator(this); } ///////////////////////////////////////////////////////////////////// ////// Standard implementation of IEnumerator for the Tablets collection /// internal struct TabletDeviceEnumerator : IEnumerator { ///////////////////////////////////////////////////////////////// ////// Create a new enumerator, initialized with a TabletDeviceCollection /// /// collection to enumerate over internal TabletDeviceEnumerator(TabletDeviceCollection tabletDeviceCollection) { _tabletDeviceCollection = tabletDeviceCollection; _index = -1; } ///////////////////////////////////////////////////////////////// ////// Move the enumerator index to the next property in the collection. /// public bool MoveNext() { if (_tabletDeviceCollection != null) { if (_index < _tabletDeviceCollection.Count) { _index++; } return _index < _tabletDeviceCollection.Count; } else { return false; } } ///////////////////////////////////////////////////////////////// ////// Reset the enumerator index in the collection to the beginning /// of the collection /// public void Reset() { _index = -1; } ///////////////////////////////////////////////////////////////// ////// Retrieve the currently indexed property in the collection /// object IEnumerator.Current { get { return (TabletDevice)Current; } } ///////////////////////////////////////////////////////////////// ////// Strongly-typed method to retrieve the currently indexed property in the collection /// public TabletDevice Current { get { if ((_index < 0) || (_tabletDeviceCollection == null) || (_index >= _tabletDeviceCollection.Count)) { // samgeo - Presharp issue // Presharp gives a warning when get methods of a property throws an exception. // However, the get method of the IEnumerator class has to throw an exception // by Design. The details can be found in the MSDN documentation for IEnumerator. #pragma warning disable 1634, 1691 #pragma warning suppress 6503 throw new InvalidOperationException(SR.Get(SRID.Stylus_EnumeratorFailure)); #pragma warning restore 1634, 1691 } return _tabletDeviceCollection[_index]; } } ///////////////////////////////////////////////////////////////// TabletDeviceCollection _tabletDeviceCollection; int _index; } ///////////////////////////////////////////////////////////////////// TabletDevice[] _tablets = new TabletDevice[0]; uint _indexMouseTablet = UInt32.MaxValue; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //// Copyright (C) Microsoft Corporation. All rights reserved. // using System; using System.Diagnostics; using System.Windows; using System.Collections; using System.Globalization; using System.Windows.Media; using MS.Utility; using System.Security; using System.Security.Permissions; using MS.Internal; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using MS.Win32.Penimc; using System.Runtime.InteropServices; using MS.Win32; using Microsoft.Win32; namespace System.Windows.Input { ///////////////////////////////////////////////////////////////////////// ////// Collection of the tablet devices that are available on the machine. /// public class TabletDeviceCollection : ICollection, IEnumerable { const int VistaMajorVersion = 6; ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ////// Critical: Calls ShouldEnableTablets /// [SecurityCritical] internal TabletDeviceCollection() { StylusLogic stylusLogic = StylusLogic.CurrentStylusLogic; bool enabled = stylusLogic.Enabled; if (!enabled) { enabled = ShouldEnableTablets(); } // If enabled or we are a tabletpc (vista sets dynamically if digitizers present) then enable the pen! if (enabled) { UpdateTablets(); // Create the tablet device collection! // Enable stylus input on all hwnds if we have not yet done so. if (!stylusLogic.Enabled) { stylusLogic.EnableCore(); } } } ////// Checks if Tablets should be enabled. /// ////// /// Critical: Calls SecurityCritical routines (IsWisptisRegistered, /// HasTabletDevices, UnsafeNativeMethods.GetSystemMetrics, /// PenThreadPool.GetPenThreadForPenContext, PenThread.WorkerGetTabletsInfo, /// TabletDevice constructor, StylusLogic.EnableCore and /// StylusLogic.CurrentStylusLogic). /// [SecurityCritical] internal static bool ShouldEnableTablets() { bool enabled = false; // We only want to enable by default if Wisptis is registered and tablets are detected. // We do the same detection on all OS versions. // // NOTE: This code does not support the new Vista wisptis feature to be able to exclude // tablet devices using a special registy key. The only side effect of not supporting // this feature is that we would go ahead and load wisptis when we really don't need to // (since wisptis would not return us any tablet devices). This should be a fairly rare // case though. if (IsWisptisRegistered() && HasTabletDevices()) { enabled = true; // start up wisptis } return enabled; } ////// Critical - Asserts read registry permission... /// - TreatAsSafe boundry is HwndSource constructor and Tablet.TabletDevices. /// - called by this objects constructor /// [SecurityCritical] private static bool IsWisptisRegistered() { bool fRegistered = false; RegistryKey key = null; // This object has finalizer to close the key. Object valDefault = null; bool runningOnVista = (Environment.OSVersion.Version.Major >= VistaMajorVersion); string keyToAssertPermissionFor = runningOnVista ? "HKEY_CLASSES_ROOT\\Interface\\{C247F616-BBEB-406A-AED3-F75E656599AE}" : "HKEY_CLASSES_ROOT\\CLSID\\{A5B020FD-E04B-4e67-B65A-E7DEED25B2CF}\\LocalServer32"; string subkeyToOpen = runningOnVista ? "Interface\\{C247F616-BBEB-406A-AED3-F75E656599AE}" : "CLSID\\{A5B020FD-E04B-4e67-B65A-E7DEED25B2CF}\\LocalServer32"; string valueToSearchFor = runningOnVista ? "ITablet2" : "wisptis.exe"; // Perform the OS specific check for wisptis new RegistryPermission(RegistryPermissionAccess.Read, keyToAssertPermissionFor).Assert(); // BlessedAssert try { key = Registry.ClassesRoot.OpenSubKey(subkeyToOpen); if (key != null) { valDefault = key.GetValue(""); } } finally { RegistryPermission.RevertAssert(); } if (key != null) { string sValDefault = valDefault as string; if (sValDefault != null && sValDefault.LastIndexOf(valueToSearchFor, StringComparison.OrdinalIgnoreCase) != -1) { fRegistered = true; } key.Close(); } return fRegistered; } ////// Critical - Calls critical methods (GetRawInputDeviceList, GetRawInputDeviceInfo, Marshal.SizeOf). /// - TreatAsSafe boundry is HwndSource constructor and Tablet.TabletDevices. /// - called by constructor /// [SecurityCritical] private static bool HasTabletDevices() { uint deviceCount = 0; // Determine the number of devices first (result will be -1 if fails and cDevices will have count) int result = (int)MS.Win32.UnsafeNativeMethods.GetRawInputDeviceList(null, ref deviceCount, (uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTDEVICELIST))); if (result >= 0 && deviceCount != 0) { NativeMethods.RAWINPUTDEVICELIST[] ridl = new NativeMethods.RAWINPUTDEVICELIST[deviceCount]; int count = (int)MS.Win32.UnsafeNativeMethods.GetRawInputDeviceList(ridl, ref deviceCount, (uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTDEVICELIST))); if (count > 0) { for (int i = 0; i < count; i++) { if (ridl[i].dwType == NativeMethods.RIM_TYPEHID) { NativeMethods.RID_DEVICE_INFO deviceInfo = new NativeMethods.RID_DEVICE_INFO(); deviceInfo.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.RID_DEVICE_INFO)); uint cbSize = (uint)deviceInfo.cbSize; int cBytes = (int)MS.Win32.UnsafeNativeMethods.GetRawInputDeviceInfo(ridl[i].hDevice, NativeMethods.RIDI_DEVICEINFO, ref deviceInfo, ref cbSize); if (cBytes > 0) { if (deviceInfo.hid.usUsagePage == NativeMethods.HID_USAGE_PAGE_DIGITIZER) { switch (deviceInfo.hid.usUsage) { case NativeMethods.HID_USAGE_DIGITIZER_DIGITIZER: case NativeMethods.HID_USAGE_DIGITIZER_PEN: case NativeMethods.HID_USAGE_DIGITIZER_TOUCHSCREEN: case NativeMethods.HID_USAGE_DIGITIZER_LIGHTPEN: { return true; } } } } else { System.Diagnostics.Debug.WriteLine("TabletDeviceCollection: GetRawInputDeviceInfo failed!"); } } } } else if (count < 0) { System.Diagnostics.Debug.WriteLine("TabletDeviceCollection: GetRawInputDeviceList failed!"); } } return false; } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code with SuppressUnmangedCode /// (GetTabletCount, GetTablet, PimcPInvoke and PimcManager) /// and calls SecurityCritical code TabletDevice constructor. /// [SecurityCritical] internal void UpdateTablets() { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); // REENTRANCY NOTE: Let a PenThread do this work to avoid reentrancy! // On return you get entire list of tablet and info needed to // create all the tablet devices (and stylus device info gets // cached too in penimc which avoids calls to wisptis.exe). // Use existing penthread if we have one otherwise grab an available one. PenThread penThread = _tablets.Length > 0 ? _tablets[0].PenThread : PenThreadPool.GetPenThreadForPenContext(null); TabletDeviceInfo [] tabletdevices = penThread.WorkerGetTabletsInfo(); // First find out the index of the mouse device (usually the first at index 0) uint indexMouseTablet = UInt32.MaxValue; for (uint i = 0; i < tabletdevices.Length; i++) { // See if this is a bogus entry first. if (tabletdevices[i].PimcTablet == null) continue; // If it is the mouse tablet device we want to ignore it. if (tabletdevices[i].DeviceType == (TabletDeviceType)(-1)) { indexMouseTablet = i; tabletdevices[i].PimcTablet = null; // ignore this one! } } // Now figure out count of valid tablet devices left uint count = 0; for (uint k = 0; k < tabletdevices.Length; k++) { if (tabletdevices[k].PimcTablet != null) count++; } TabletDevice[] tablets = new TabletDevice[count]; uint tabletsIndex = 0; for (uint iTablet = 0; iTablet < tabletdevices.Length; iTablet++) { if (tabletdevices[iTablet].PimcTablet == null) { continue; // Skip looking at this index (mouse and bogus tablets are ignored). } int id = tabletdevices[iTablet].Id; // First see if same index has not changed (typical case) if (tabletsIndex < _tablets.Length && _tablets[tabletsIndex].Id == id) { tablets[tabletsIndex] = _tablets[tabletsIndex]; _tablets[tabletsIndex] = null; // clear to ignore on cleanup pass. } else { // Look up and see if we have this tabletdevice created already... TabletDevice tablet = null; for (uint i = 0; i < _tablets.Length; i++) { if (_tablets[i] != null && _tablets[i].Id == id) { tablet = _tablets[i]; _tablets[i] = null; // clear it so we don't dispose it. break; } } // Not found so create it. if (tablet == null) { try { tablet = new TabletDevice(tabletdevices[iTablet], penThread); } catch (InvalidOperationException ex) { // This is caused by the Stylus ID not being unique when trying // to register it in the StylusLogic.__stylusDeviceMap. If we // come across a dup then just ignore registering this tablet device. // There seems to be an issue in wisptis where different tablet IDs get // duplicate Stylus Ids when installing the VHID test devices. if (ex.Data.Contains("System.Windows.Input.StylusLogic")) { continue; // Just go to next without adding this one. } else { throw; // not an expected exception, rethrow it. } } } tablets[tabletsIndex] = tablet; } tabletsIndex++; } // See if we need to re alloc the array due to invalid tabletdevice being seen. if (tabletsIndex != count) { TabletDevice[] updatedTablets = new TabletDevice[tabletsIndex]; Array.Copy(tablets, 0, updatedTablets, 0, tabletsIndex); tablets = updatedTablets; } DisposeTablets(); // Clean up any non null TabletDevice entries on old array. _tablets = tablets; // set updated tabletdevice array _indexMouseTablet = indexMouseTablet; } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code with SuppressUnmangedCode /// (GetTablet, PimcPInvoke and PimcManager) /// and calls SecurityCritical code TabletDevice constructor. /// [SecurityCritical] internal bool HandleTabletAdded(uint wisptisIndex, ref uint tabletIndexChanged) { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); tabletIndexChanged = UInt32.MaxValue; // REENTRANCY NOTE: Let a PenThread do this work to avoid reentrancy! // On return you get the tablet info needed to // create a tablet devices (and stylus device info gets // cached in penimc too which avoids calls to wisptis.exe). // Use existing penthread if we have one otherwise grab an available one. PenThread penThread = _tablets.Length > 0 ? _tablets[0].PenThread : PenThreadPool.GetPenThreadForPenContext(null); TabletDeviceInfo tabletInfo = penThread.WorkerGetTabletInfo(wisptisIndex); // If we failed due to a COM exception on the pen thread then return if (tabletInfo.PimcTablet == null) { return true; // make sure we rebuild our tablet collection. (return true + MaxValue). } // if mouse tabletdevice then ignore it. if (tabletInfo.DeviceType == (TabletDeviceType)(-1)) { _indexMouseTablet = wisptisIndex; // update index. return false; // TabletDevices did not change. } // Now see if this is a duplicate add call we want to filter out (ie - already added to tablet collection). uint indexFound = UInt32.MaxValue; for (uint i = 0; i < _tablets.Length; i++) { // If it is the mouse tablet device we want to ignore it. if (_tablets[i].Id == tabletInfo.Id) { indexFound = i; break; } } // We only want to add this if it is not currently in the collection. Wisptis will send // us duplicate adds at times so this is a work around for that issue. uint tabletIndex = UInt32.MaxValue; if (indexFound == UInt32.MaxValue) { tabletIndex = wisptisIndex; if (tabletIndex > _indexMouseTablet) { tabletIndex--; } else { _indexMouseTablet++; } // if index is out of range then ignore it. Return of MaxValue causes a rebuild of the devices. if (tabletIndex <= _tablets.Length) { try { // Add new tablet at end of collection AddTablet(tabletIndex, new TabletDevice(tabletInfo, penThread)); } catch (InvalidOperationException ex) { // This is caused by the Stylus ID not being unique when trying // to register it in the StylusLogic.__stylusDeviceMap. If we // come across a dup then we should rebuild the tablet device collection. // There seems to be an issue in wisptis where different tablet IDs get // duplicate Stylus Ids when installing the VHID test devices. if (ex.Data.Contains("System.Windows.Input.StylusLogic")) { return true; // trigger the tabletdevices to be rebuilt. } else { throw; // not an expected exception, rethrow it. } } tabletIndexChanged = tabletIndex; return true; } else { return true; // bogus index. Return true so that the caller can rebuild the collection. } } else { return false; // We found this tablet device already. Don't do anything. } } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code RemoveTablet. /// [SecurityCritical] internal uint HandleTabletRemoved(uint wisptisIndex) { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); // if mouse tabletdevice then ignore it. if (wisptisIndex == _indexMouseTablet) { _indexMouseTablet = UInt32.MaxValue; return UInt32.MaxValue; // Don't process this notification any further. } uint tabletIndex = wisptisIndex; if (wisptisIndex > _indexMouseTablet) { tabletIndex--; } else { // Must be less than _indexMouseTablet since equality is done above. _indexMouseTablet--; } // if index is out of range then ignore it. if (tabletIndex >= _tablets.Length) { return UInt32.MaxValue; // Don't process this notification any further. } // Remove tablet from collection RemoveTablet(tabletIndex); return tabletIndex; } ///////////////////////////////////////////////////////////////////// // NOTE: This routine takes indexes that are in the TabletCollection range // and not in the wisptis tablet index range. ////// Critical: calls into SecurityCritical code TabletDevice constructor. /// [SecurityCritical] void AddTablet(uint index, TabletDevice tabletDevice) { Debug.Assert(index <= Count); Debug.Assert(tabletDevice.Type != (TabletDeviceType)(-1)); // make sure not the mouse tablet device! TabletDevice[] newTablets = new TabletDevice[Count + 1]; uint preCopyCount = index; uint postCopyCount = (uint)_tablets.Length - index; Array.Copy(_tablets, 0, newTablets, 0, preCopyCount); newTablets[index] = tabletDevice; Array.Copy(_tablets, index, newTablets, index+1, postCopyCount); _tablets = newTablets; } ///////////////////////////////////////////////////////////////////// // NOTE: This routine takes indexes that are in the TabletCollection range // and not in the wisptis tablet index range. ////// Critical: calls SecurityCritical code TabletDevice.Dispose. /// and StylusLogic.SelectStylusDevice /// [SecurityCritical] void RemoveTablet(uint index) { System.Diagnostics.Debug.Assert(index < Count && Count > 0); TabletDevice removeTablet = _tablets[index]; TabletDevice[] tablets = new TabletDevice[_tablets.Length - 1]; uint preCopyCount = index; uint postCopyCount = (uint)_tablets.Length - index - 1; Array.Copy(_tablets, 0, tablets, 0, preCopyCount); Array.Copy(_tablets, index+1, tablets, index, postCopyCount); _tablets = tablets; // Make sure we release any references to a stylus device that may // have been removed if (Tablet.CurrentTabletDevice == removeTablet) { StylusLogic.CurrentStylusLogic.SelectStylusDevice(null, null, true); } removeTablet.Dispose(); } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code with SuppressUnmangedCode /// (GetTablet, PimcPInvoke and PimcManager) /// and calls SecurityCritical code TabletDevice constructor. /// [SecurityCritical] internal StylusDevice UpdateStylusDevices(int tabletId, int stylusId) { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); for (int iTablet = 0, cTablets = _tablets.Length; iTablet < cTablets; iTablet++) { TabletDevice tablet = _tablets[iTablet]; if (tablet.Id == tabletId) { // Make sure we don't get reentered during this call to penimc! using(tablet.Dispatcher.DisableProcessing()) { return tablet.UpdateStylusDevices(stylusId); } } } return null; } ///////////////////////////////////////////////////////////////////// ////// Critical: calls into SecurityCritical code TabletDevice.Dispose. /// and StylusLogic.SelectStylusDevice /// [SecurityCritical] internal void DisposeTablets() { if (_tablets != null) { for (int iTablet = 0, cTablets = _tablets.Length; iTablet < cTablets; iTablet++) { if (_tablets[iTablet] != null) { // Make sure this stylus device is not the current one. if (Tablet.CurrentTabletDevice == _tablets[iTablet]) { StylusLogic.CurrentStylusLogic.SelectStylusDevice(null, null, true); } _tablets[iTablet].Dispose(); } } _tablets = null; } } ///////////////////////////////////////////////////////////////////// ////// Critical: - calls into security critical code (PenContext constructor /// and PenContext.CreateContext) /// - takes in data that is potential security risk (hwnd) /// [SecurityCritical] internal PenContext[] CreateContexts(IntPtr hwnd, PenContexts contexts) { int c = Count; PenContext[] ctxs = new PenContext[c]; int i = 0; foreach (TabletDevice tablet in _tablets) { ctxs[i] = tablet.CreateContext(hwnd, contexts); i++; } return ctxs; } ///////////////////////////////////////////////////////////////////// ////// Retrieve the number of TabletDevice objects in the collection. /// public int Count { get { if (_tablets == null) throw new ObjectDisposedException("TabletDeviceCollection"); return _tablets.Length; } } ///////////////////////////////////////////////////////////////////// ////// Copy the TabletDevice objects in the collection to another array. /// /// destination array /// position in destination array to begin copying void ICollection.CopyTo(Array array, int index) { // Delegate error checking to Array.Copy. Array.Copy(_tablets, 0, array, index, this.Count); } ///////////////////////////////////////////////////////////////////// ////// Copy the TabletDevice objects in the collection to another array /// of TabletDevices. /// /// destination array /// position in destination array to begin copying public void CopyTo(TabletDevice[] array, int index) { ((ICollection)this).CopyTo(array, index); } ///////////////////////////////////////////////////////////////////// ////// Retrieve the specified TabletDevice object from the collection. /// /// index of TabletDevice in collection to retrieve public TabletDevice this[int index] { get { if (index >= Count || index < 0) throw new ArgumentException(SR.Get(SRID.Stylus_IndexOutOfRange, index.ToString(System.Globalization.CultureInfo.InvariantCulture)), "index"); return _tablets[index]; } } ///////////////////////////////////////////////////////////////////// ////// Returns an object which can be used to lock during synchronization by collection users. /// public object SyncRoot { get { return this; } } ///////////////////////////////////////////////////////////////////// ////// /// Determine if the collection has thread-safe operations. /// public bool IsSynchronized { get { return false; } } ///////////////////////////////////////////////////////////////////// ////// Standard implementation of IEnumerable which enables callers to use the /// foreach construct to enumerate through each TabletDevice in the collection. /// IEnumerator IEnumerable.GetEnumerator() { return new TabletDeviceEnumerator(this); } ///////////////////////////////////////////////////////////////////// ////// Standard implementation of IEnumerator for the Tablets collection /// internal struct TabletDeviceEnumerator : IEnumerator { ///////////////////////////////////////////////////////////////// ////// Create a new enumerator, initialized with a TabletDeviceCollection /// /// collection to enumerate over internal TabletDeviceEnumerator(TabletDeviceCollection tabletDeviceCollection) { _tabletDeviceCollection = tabletDeviceCollection; _index = -1; } ///////////////////////////////////////////////////////////////// ////// Move the enumerator index to the next property in the collection. /// public bool MoveNext() { if (_tabletDeviceCollection != null) { if (_index < _tabletDeviceCollection.Count) { _index++; } return _index < _tabletDeviceCollection.Count; } else { return false; } } ///////////////////////////////////////////////////////////////// ////// Reset the enumerator index in the collection to the beginning /// of the collection /// public void Reset() { _index = -1; } ///////////////////////////////////////////////////////////////// ////// Retrieve the currently indexed property in the collection /// object IEnumerator.Current { get { return (TabletDevice)Current; } } ///////////////////////////////////////////////////////////////// ////// Strongly-typed method to retrieve the currently indexed property in the collection /// public TabletDevice Current { get { if ((_index < 0) || (_tabletDeviceCollection == null) || (_index >= _tabletDeviceCollection.Count)) { // samgeo - Presharp issue // Presharp gives a warning when get methods of a property throws an exception. // However, the get method of the IEnumerator class has to throw an exception // by Design. The details can be found in the MSDN documentation for IEnumerator. #pragma warning disable 1634, 1691 #pragma warning suppress 6503 throw new InvalidOperationException(SR.Get(SRID.Stylus_EnumeratorFailure)); #pragma warning restore 1634, 1691 } return _tabletDeviceCollection[_index]; } } ///////////////////////////////////////////////////////////////// TabletDeviceCollection _tabletDeviceCollection; int _index; } ///////////////////////////////////////////////////////////////////// TabletDevice[] _tablets = new TabletDevice[0]; uint _indexMouseTablet = UInt32.MaxValue; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BufferAllocator.cs
- LassoSelectionBehavior.cs
- MenuStrip.cs
- BitmapPalettes.cs
- SoapObjectWriter.cs
- DataGridViewDesigner.cs
- DatePickerDateValidationErrorEventArgs.cs
- UnescapedXmlDiagnosticData.cs
- WebPartDescriptionCollection.cs
- BindingCompleteEventArgs.cs
- ValueExpressions.cs
- XmlAnyElementAttributes.cs
- EditingCommands.cs
- RuntimeWrappedException.cs
- CodeDOMProvider.cs
- TransformConverter.cs
- ZipIOModeEnforcingStream.cs
- FixUpCollection.cs
- WebPartRestoreVerb.cs
- EventProxy.cs
- ActivityExecutionContext.cs
- ArrayTypeMismatchException.cs
- DesignerVerb.cs
- RevocationPoint.cs
- RequestQueryProcessor.cs
- ProxyWebPartManager.cs
- ArraySortHelper.cs
- RevocationPoint.cs
- rsa.cs
- ConfigurationManagerInternalFactory.cs
- WindowsSolidBrush.cs
- SuppressIldasmAttribute.cs
- CharEntityEncoderFallback.cs
- CodeSpit.cs
- ValueUtilsSmi.cs
- ColumnCollectionEditor.cs
- TreeViewItemAutomationPeer.cs
- ColumnMapTranslator.cs
- X509InitiatorCertificateClientElement.cs
- CompatibleComparer.cs
- PageVisual.cs
- indexingfiltermarshaler.cs
- WebExceptionStatus.cs
- FormClosingEvent.cs
- ThumbButtonInfoCollection.cs
- ZoneButton.cs
- OdbcParameter.cs
- PartialCachingAttribute.cs
- RightsManagementEncryptionTransform.cs
- ThemeableAttribute.cs
- WorkflowPageSetupDialog.cs
- DragDropHelper.cs
- InteropEnvironment.cs
- TreeViewDesigner.cs
- CaseInsensitiveOrdinalStringComparer.cs
- CompositeActivityTypeDescriptor.cs
- ActivationArguments.cs
- NotFiniteNumberException.cs
- GridViewPageEventArgs.cs
- MessageQueueCriteria.cs
- GraphicsContainer.cs
- MethodAccessException.cs
- SynchronizationScope.cs
- OpenFileDialog.cs
- CodeAttachEventStatement.cs
- BufferedGraphicsContext.cs
- FeatureSupport.cs
- PasswordBoxAutomationPeer.cs
- EllipseGeometry.cs
- KeyGestureValueSerializer.cs
- AQNBuilder.cs
- ConfigXmlText.cs
- DecimalSumAggregationOperator.cs
- DiscoveryRequestHandler.cs
- FileDataSourceCache.cs
- RuntimeCompatibilityAttribute.cs
- DataGridDefaultColumnWidthTypeConverter.cs
- WsdlInspector.cs
- _NetRes.cs
- DiscoveryClientDocuments.cs
- JournalEntryListConverter.cs
- BinHexDecoder.cs
- Blend.cs
- XmlQueryCardinality.cs
- DefaultPrintController.cs
- WorkflowServiceAttributes.cs
- OperationResponse.cs
- ServiceTimeoutsElement.cs
- DesignBinding.cs
- HwndTarget.cs
- SemanticBasicElement.cs
- TextParentUndoUnit.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- CapacityStreamGeometryContext.cs
- ApplicationFileCodeDomTreeGenerator.cs
- CodeTypeOfExpression.cs
- ComponentConverter.cs
- CachedBitmap.cs
- LogicalExpr.cs
- DataGridViewColumnCollection.cs