2009-09-17 77 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

相關問題