我正在编写一个小型C#应用程序,以在检测到其他鼠标设备时禁用设备(我的笔记本电脑触摸板),并在未检测到鼠标时再次启用触摸板。我什至不能在设备管理器中禁用触摸板(它在默认的鼠标类驱动程序上运行)。
我正在开发设备驱动程序,因此我想也许可以编写一个小的过滤器驱动程序,该驱动程序仅接受IOCTL来启用和禁用在设备堆栈上传递鼠标事件消息,并通过原始PDO从用户模式获取消息。但是,我问了这个问题,有人建议我可以通过 SetupDi .. 函数在用户模式下执行此操作。那真的很好,因为这种原始的PDO通信方法是可以使用的PITA。
我以前只使用过 SetupDiGetClassDevs ,而且它们太多了,能否有人对Win32 API的这一部分有更多的经验,可以快速告诉我应该叫什么来停止/禁用鼠标设备或其接口,或者是否有。在框架的黑暗角落中的某个地方可以做到这一点(也许在WMI中?)。
更新(09/24/09) 我弄清楚了如何使用过滤器驱动程序来完成此工作,并在最初的问题上发布了我的操作方法。我仍然想知道是否可以直接从Win32启用或禁用设备,如果可以,如何启用-因此我将保留此问题。
您可以使用SetupDi API从Win32(因此可以通过P / Invoke从C#)启用/禁用设备,但并非所有设备都以此方式“禁用”。
您尝试从Win32(或WMI或调用SetupDi *系列功能的任何其他API)禁用触摸板时会遇到的问题是,大多数带有触摸板的笔记本电脑(默认为PS / 2个兼容的鼠标”)不支持使用SetupDi API禁用。我怀疑这可能是因为使用PS / 2连接器的实际旧鼠标如果没有安装硬件就无法热拆卸。
要验证您不能禁用它,请进入“设备管理器”并右键单击鼠标驱动程序。如果看到禁用选项,则可以使用SetupDi禁用它。如果没有禁用选项,那么您不走运…欢迎来到IOCTL领域!
如果 确实 看到禁用选项,那么下面的代码(从我在这里找到的VB示例移植到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); }
这是图书馆本身,改编自这里。
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(); } } } }
请注意,当您在行上收到Index-Out-Of-Bounds异常时int index = GetIndexOfInstance(diSetHandle, diData, instanceId);,您可能为设备使用了错误的classGuid或错误的instanceId。
int index = GetIndexOfInstance(diSetHandle, diData, instanceId);
还要注意,当您在64位Windows平台上运行此代码时,在构建应用程序时应以64位平台为目标。否则- 例如,在64位Windows平台上将应用程序作为32位进程运行时-您将收到SetupAPI错误InWow64(ERROR_IN_WOW64)。
以64位Windows平台为目标时,您可能还必须对应用程序的其他部分进行更改,例如在进行指针算术时,以防止溢出。