2009-09-17 155 views
39

我正在编写一个小型C#应用程序,以在检测到另一个鼠标设备时禁用设备(我的笔记本电脑触摸板),并在未检测到鼠标时再次启用触摸板。我甚至无法禁用设备管理器中的触摸板(它正在默认的鼠标类驱动程序上运行)。以编程方式启用/禁用设备的Win32 API函数

我正在进入设备驱动程序开发,所以我想也许我可以写一个过滤器驱动程序,只接受IOCTLs启用和禁用在设备堆栈上传递鼠标事件消息,并通过原始PDO从用户模式获取消息。然而,I asked that question和有人建议我可以通过SetupDi..函数在用户模式下执行此操作。这将是非常好的,因为这种原始的PDO通信方法是PITA可以使用的。

我只用SetupDiGetClassDevs之前,有那么多的人,可有人使用Win32 API的这一部分更多的经验告诉我很快我应该叫什么人来停止/禁用鼠标设备或它的界面,还是在框架的黑暗角落里有什么东西可以做到这一点(也许在WMI中?)。

更新(24/9/09)我想通过过滤器驱动程序做到这一点,并发布了如何在my original question上做到这一点。我仍然想知道是否可以直接从Win32启用或禁用设备,如果可以,怎么办 - 所以我会打开这个问题。

回答

53

您可以从Win32的使用的SetupDi API的启用/禁用设备(因此从C#通过P/Invoke的),但并非所有的设备都是“禁用,能够”用这种方式。

您尝试从Win32(或WMI或调用SetupDi *系列函数的任何其他API)中禁用触摸板时遇到的问题是,在大多数带有触摸板的笔记本电脑中使用的默认鼠标驱动程序(“PS/2兼容鼠标”)不支持使用SetupDi API禁用。我怀疑这可能是因为使用PS/2连接器的实际老鼠不能在没有硬件硬件的情况下热分离。

要验证您无法禁用,请进入设备管理器并右键单击鼠标驱动程序。如果您看到禁用选项,则可以使用SetupDi将其禁用。如果没有禁用选项,那么你运气不好......欢迎来到IOCTL-land!

如果看到禁用选项,然后在下面的代码(从VB范例,我发现here移植到C#)应该让你禁用和重新启用该设备。

下面的代码来调用库:

public static void EnableMouse(bool enable) 
    { 
     // every type of device has a hard-coded GUID, this is the one for mice 
     Guid mouseGuid = new Guid("{4d36e96f-e325-11ce-bfc1-08002be10318}"); 

     // get this from the properties dialog box of this device in Device Manager 
     string instancePath = @"ACPI\PNP0F03\4&3688D3F&0"; 

     DeviceHelper.SetDeviceEnabled(mouseGuid, instancePath, enable); 
    } 

这里的库本身,改编自here

using System; 
using System.Text; 
using System.Collections.Generic; 
using DisableDevice; 
using System.Runtime.InteropServices; 
using System.ComponentModel; 
using Microsoft.Win32.SafeHandles; 
using System.Security; 
using System.Runtime.ConstrainedExecution; 
using System.Management; 

namespace DisableDevice 
{ 

    [Flags()] 
    internal enum SetupDiGetClassDevsFlags 
    { 
     Default = 1, 
     Present = 2, 
     AllClasses = 4, 
     Profile = 8, 
     DeviceInterface = (int)0x10 
    } 

    internal enum DiFunction 
    { 
     SelectDevice = 1, 
     InstallDevice = 2, 
     AssignResources = 3, 
     Properties = 4, 
     Remove = 5, 
     FirstTimeSetup = 6, 
     FoundDevice = 7, 
     SelectClassDrivers = 8, 
     ValidateClassDrivers = 9, 
     InstallClassDrivers = (int)0xa, 
     CalcDiskSpace = (int)0xb, 
     DestroyPrivateData = (int)0xc, 
     ValidateDriver = (int)0xd, 
     Detect = (int)0xf, 
     InstallWizard = (int)0x10, 
     DestroyWizardData = (int)0x11, 
     PropertyChange = (int)0x12, 
     EnableClass = (int)0x13, 
     DetectVerify = (int)0x14, 
     InstallDeviceFiles = (int)0x15, 
     UnRemove = (int)0x16, 
     SelectBestCompatDrv = (int)0x17, 
     AllowInstall = (int)0x18, 
     RegisterDevice = (int)0x19, 
     NewDeviceWizardPreSelect = (int)0x1a, 
     NewDeviceWizardSelect = (int)0x1b, 
     NewDeviceWizardPreAnalyze = (int)0x1c, 
     NewDeviceWizardPostAnalyze = (int)0x1d, 
     NewDeviceWizardFinishInstall = (int)0x1e, 
     Unused1 = (int)0x1f, 
     InstallInterfaces = (int)0x20, 
     DetectCancel = (int)0x21, 
     RegisterCoInstallers = (int)0x22, 
     AddPropertyPageAdvanced = (int)0x23, 
     AddPropertyPageBasic = (int)0x24, 
     Reserved1 = (int)0x25, 
     Troubleshooter = (int)0x26, 
     PowerMessageWake = (int)0x27, 
     AddRemotePropertyPageAdvanced = (int)0x28, 
     UpdateDriverUI = (int)0x29, 
     Reserved2 = (int)0x30 
    } 

    internal enum StateChangeAction 
    { 
     Enable = 1, 
     Disable = 2, 
     PropChange = 3, 
     Start = 4, 
     Stop = 5 
    } 

    [Flags()] 
    internal enum Scopes 
    { 
     Global = 1, 
     ConfigSpecific = 2, 
     ConfigGeneral = 4 
    } 

    internal enum SetupApiError 
    { 
     NoAssociatedClass = unchecked((int)0xe0000200), 
     ClassMismatch = unchecked((int)0xe0000201), 
     DuplicateFound = unchecked((int)0xe0000202), 
     NoDriverSelected = unchecked((int)0xe0000203), 
     KeyDoesNotExist = unchecked((int)0xe0000204), 
     InvalidDevinstName = unchecked((int)0xe0000205), 
     InvalidClass = unchecked((int)0xe0000206), 
     DevinstAlreadyExists = unchecked((int)0xe0000207), 
     DevinfoNotRegistered = unchecked((int)0xe0000208), 
     InvalidRegProperty = unchecked((int)0xe0000209), 
     NoInf = unchecked((int)0xe000020a), 
     NoSuchHDevinst = unchecked((int)0xe000020b), 
     CantLoadClassIcon = unchecked((int)0xe000020c), 
     InvalidClassInstaller = unchecked((int)0xe000020d), 
     DiDoDefault = unchecked((int)0xe000020e), 
     DiNoFileCopy = unchecked((int)0xe000020f), 
     InvalidHwProfile = unchecked((int)0xe0000210), 
     NoDeviceSelected = unchecked((int)0xe0000211), 
     DevinfolistLocked = unchecked((int)0xe0000212), 
     DevinfodataLocked = unchecked((int)0xe0000213), 
     DiBadPath = unchecked((int)0xe0000214), 
     NoClassInstallParams = unchecked((int)0xe0000215), 
     FileQueueLocked = unchecked((int)0xe0000216), 
     BadServiceInstallSect = unchecked((int)0xe0000217), 
     NoClassDriverList = unchecked((int)0xe0000218), 
     NoAssociatedService = unchecked((int)0xe0000219), 
     NoDefaultDeviceInterface = unchecked((int)0xe000021a), 
     DeviceInterfaceActive = unchecked((int)0xe000021b), 
     DeviceInterfaceRemoved = unchecked((int)0xe000021c), 
     BadInterfaceInstallSect = unchecked((int)0xe000021d), 
     NoSuchInterfaceClass = unchecked((int)0xe000021e), 
     InvalidReferenceString = unchecked((int)0xe000021f), 
     InvalidMachineName = unchecked((int)0xe0000220), 
     RemoteCommFailure = unchecked((int)0xe0000221), 
     MachineUnavailable = unchecked((int)0xe0000222), 
     NoConfigMgrServices = unchecked((int)0xe0000223), 
     InvalidPropPageProvider = unchecked((int)0xe0000224), 
     NoSuchDeviceInterface = unchecked((int)0xe0000225), 
     DiPostProcessingRequired = unchecked((int)0xe0000226), 
     InvalidCOInstaller = unchecked((int)0xe0000227), 
     NoCompatDrivers = unchecked((int)0xe0000228), 
     NoDeviceIcon = unchecked((int)0xe0000229), 
     InvalidInfLogConfig = unchecked((int)0xe000022a), 
     DiDontInstall = unchecked((int)0xe000022b), 
     InvalidFilterDriver = unchecked((int)0xe000022c), 
     NonWindowsNTDriver = unchecked((int)0xe000022d), 
     NonWindowsDriver = unchecked((int)0xe000022e), 
     NoCatalogForOemInf = unchecked((int)0xe000022f), 
     DevInstallQueueNonNative = unchecked((int)0xe0000230), 
     NotDisableable = unchecked((int)0xe0000231), 
     CantRemoveDevinst = unchecked((int)0xe0000232), 
     InvalidTarget = unchecked((int)0xe0000233), 
     DriverNonNative = unchecked((int)0xe0000234), 
     InWow64 = unchecked((int)0xe0000235), 
     SetSystemRestorePoint = unchecked((int)0xe0000236), 
     IncorrectlyCopiedInf = unchecked((int)0xe0000237), 
     SceDisabled = unchecked((int)0xe0000238), 
     UnknownException = unchecked((int)0xe0000239), 
     PnpRegistryError = unchecked((int)0xe000023a), 
     RemoteRequestUnsupported = unchecked((int)0xe000023b), 
     NotAnInstalledOemInf = unchecked((int)0xe000023c), 
     InfInUseByDevices = unchecked((int)0xe000023d), 
     DiFunctionObsolete = unchecked((int)0xe000023e), 
     NoAuthenticodeCatalog = unchecked((int)0xe000023f), 
     AuthenticodeDisallowed = unchecked((int)0xe0000240), 
     AuthenticodeTrustedPublisher = unchecked((int)0xe0000241), 
     AuthenticodeTrustNotEstablished = unchecked((int)0xe0000242), 
     AuthenticodePublisherNotTrusted = unchecked((int)0xe0000243), 
     SignatureOSAttributeMismatch = unchecked((int)0xe0000244), 
     OnlyValidateViaAuthenticode = unchecked((int)0xe0000245) 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct DeviceInfoData 
    { 
     public int Size; 
     public Guid ClassGuid; 
     public int DevInst; 
     public IntPtr Reserved; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct PropertyChangeParameters 
    { 
     public int Size; 
     // part of header. It's flattened out into 1 structure. 
     public DiFunction DiFunction; 
     public StateChangeAction StateChange; 
     public Scopes Scope; 
     public int HwProfile; 
    } 

    internal class NativeMethods 
    { 

     private const string setupapi = "setupapi.dll"; 

     private NativeMethods() 
     { 
     } 

     [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool SetupDiCallClassInstaller(DiFunction installFunction, SafeDeviceInfoSetHandle deviceInfoSet, [In()] 
ref DeviceInfoData deviceInfoData); 

     [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool SetupDiEnumDeviceInfo(SafeDeviceInfoSetHandle deviceInfoSet, int memberIndex, ref DeviceInfoData deviceInfoData); 

     [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)] 
     public static extern SafeDeviceInfoSetHandle SetupDiGetClassDevs([In()] 
ref Guid classGuid, [MarshalAs(UnmanagedType.LPWStr)] 
string enumerator, IntPtr hwndParent, SetupDiGetClassDevsFlags flags); 

     /* 
     [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool SetupDiGetDeviceInstanceId(SafeDeviceInfoSetHandle deviceInfoSet, [In()] 
ref DeviceInfoData did, [MarshalAs(UnmanagedType.LPTStr)] 
StringBuilder deviceInstanceId, int deviceInstanceIdSize, [Out()] 
ref int requiredSize); 
     */ 
     [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool SetupDiGetDeviceInstanceId(
      IntPtr DeviceInfoSet, 
      ref DeviceInfoData did, 
      [MarshalAs(UnmanagedType.LPTStr)] StringBuilder DeviceInstanceId, 
      int DeviceInstanceIdSize, 
      out int RequiredSize 
     ); 

     [SuppressUnmanagedCodeSecurity()] 
     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
     [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); 

     [DllImport(setupapi, CallingConvention = CallingConvention.Winapi, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool SetupDiSetClassInstallParams(SafeDeviceInfoSetHandle deviceInfoSet, [In()] 
ref DeviceInfoData deviceInfoData, [In()] 
ref PropertyChangeParameters classInstallParams, int classInstallParamsSize); 

    } 

    internal class SafeDeviceInfoSetHandle : SafeHandleZeroOrMinusOneIsInvalid 
    { 

     public SafeDeviceInfoSetHandle() 
      : base(true) 
     { 
     } 

     protected override bool ReleaseHandle() 
     { 
      return NativeMethods.SetupDiDestroyDeviceInfoList(this.handle); 
     } 

    } 

    public sealed class DeviceHelper 
    { 

     private DeviceHelper() 
     { 
     } 

     /// <summary> 
     /// Enable or disable a device. 
     /// </summary> 
     /// <param name="classGuid">The class guid of the device. Available in the device manager.</param> 
     /// <param name="instanceId">The device instance id of the device. Available in the device manager.</param> 
     /// <param name="enable">True to enable, False to disable.</param> 
     /// <remarks>Will throw an exception if the device is not Disableable.</remarks> 
     public static void SetDeviceEnabled(Guid classGuid, string instanceId, bool enable) 
     { 
      SafeDeviceInfoSetHandle diSetHandle = null; 
      try 
      { 
       // Get the handle to a device information set for all devices matching classGuid that are present on the 
       // system. 
       diSetHandle = NativeMethods.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, SetupDiGetClassDevsFlags.Present); 
       // Get the device information data for each matching device. 
       DeviceInfoData[] diData = GetDeviceInfoData(diSetHandle); 
       // Find the index of our instance. i.e. the touchpad mouse - I have 3 mice attached... 
       int index = GetIndexOfInstance(diSetHandle, diData, instanceId); 
       // Disable... 
       EnableDevice(diSetHandle, diData[index], enable); 
      } 
      finally 
      { 
       if (diSetHandle != null) 
       { 
        if (diSetHandle.IsClosed == false) 
        { 
         diSetHandle.Close(); 
        } 
        diSetHandle.Dispose(); 
       } 
      } 
     } 

     private static DeviceInfoData[] GetDeviceInfoData(SafeDeviceInfoSetHandle handle) 
     { 
      List<DeviceInfoData> data = new List<DeviceInfoData>(); 
      DeviceInfoData did = new DeviceInfoData(); 
      int didSize = Marshal.SizeOf(did); 
      did.Size = didSize; 
      int index = 0; 
      while (NativeMethods.SetupDiEnumDeviceInfo(handle, index, ref did)) 
      { 
       data.Add(did); 
       index += 1; 
       did = new DeviceInfoData(); 
       did.Size = didSize; 
      } 
      return data.ToArray(); 
     } 

     // Find the index of the particular DeviceInfoData for the instanceId. 
     private static int GetIndexOfInstance(SafeDeviceInfoSetHandle handle, DeviceInfoData[] diData, string instanceId) 
     { 
      const int ERROR_INSUFFICIENT_BUFFER = 122; 
      for (int index = 0; index <= diData.Length - 1; index++) 
      { 
       StringBuilder sb = new StringBuilder(1); 
       int requiredSize = 0; 
       bool result = NativeMethods.SetupDiGetDeviceInstanceId(handle.DangerousGetHandle(), ref diData[index], sb, sb.Capacity, out requiredSize); 
       if (result == false && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) 
       { 
        sb.Capacity = requiredSize; 
        result = NativeMethods.SetupDiGetDeviceInstanceId(handle.DangerousGetHandle(), ref diData[index], sb, sb.Capacity, out requiredSize); 
       } 
       if (result == false) 
        throw new Win32Exception(); 
       if (instanceId.Equals(sb.ToString())) 
       { 
        return index; 
       } 
      } 
      // not found 
      return -1; 
     } 

     // enable/disable... 
     private static void EnableDevice(SafeDeviceInfoSetHandle handle, DeviceInfoData diData, bool enable) 
     { 
      PropertyChangeParameters @params = new PropertyChangeParameters(); 
      // The size is just the size of the header, but we've flattened the structure. 
      // The header comprises the first two fields, both integer. 
      @params.Size = 8; 
      @params.DiFunction = DiFunction.PropertyChange; 
      @params.Scope = Scopes.Global; 
      if (enable) 
      { 
       @params.StateChange = StateChangeAction.Enable; 
      } 
      else 
      { 
       @params.StateChange = StateChangeAction.Disable; 
      } 

      bool result = NativeMethods.SetupDiSetClassInstallParams(handle, ref diData, ref @params, Marshal.SizeOf(@params)); 
      if (result == false) throw new Win32Exception(); 
      result = NativeMethods.SetupDiCallClassInstaller(DiFunction.PropertyChange, handle, ref diData); 
      if (result == false) 
      { 
       int err = Marshal.GetLastWin32Error(); 
       if (err == (int)SetupApiError.NotDisableable) 
        throw new ArgumentException("Device can't be disabled (programmatically or in Device Manager)."); 
       else if (err >= (int)SetupApiError.NoAssociatedClass && err <= (int)SetupApiError.OnlyValidateViaAuthenticode) 
        throw new Win32Exception("SetupAPI error: " + ((SetupApiError)err).ToString()); 
       else 
        throw new Win32Exception(); 
      } 
     } 
    } 
} 

注意,当你上线int index = GetIndexOfInstance(diSetHandle, diData, instanceId);索引-OUT-越界异常,你可能使用了错误的classGuid的设备或错误的实例Id。

另请注意,当您在64位Windows平台上运行此代码时,应该在构建应用程序时定位到64位平台。否则 - 即在64位Windows平台上将应用程序作为32位进程运行时 - 您将收到一个SetupAPI错误InWow64(ERROR_IN_WOW64)。

针对64位Windows平台时,您可能还必须对应用程序的其他部分进行更改,例如,在做指针运算时,为了防止溢出。

+0

谢谢,这是我需要知道的。 – 2009-10-28 23:20:46

+1

if(err <=(int)SetupApiError.NoAssociatedClass && err> =(int)SetupApiError.OnlyValidateViaAuthenticode)应该被翻转(> = ... && ... <=) – 2011-07-12 21:27:26

+2

@Edwin Evans - 漂亮!我使用您的修补程序更新了上面的代码。 – 2011-07-13 12:20:34

0

据我所知,触摸板是一个非标准设备(标准鼠标作为子集)。在我的笔记本电脑上,我无法使用Fn键将其禁用,直到我安装了正确的ATK100驱动程序。您应该查找ATK100.DLL的互操作。

+0

对我来说,它只是一个普通的ps/2鼠标。 – 2009-09-17 14:16:32

+0

它也会显示为鼠标。你错过了ATK部分。 – 2009-09-17 14:42:50

6

这是你在找什么?

Hardware Helper Library for C#

+1

谢谢,我也发现了这一点,但由于某种原因,它对我无效。 – 2009-10-28 23:22:22

相关问题