Win32 API函数以编程方式启用/禁用设备

我正在编写一个小型C#应用程序,以在检测到其他鼠标设备时禁用设备(我的笔记本电脑触摸板),并在未检测到鼠标时再次启用触摸板。我什至不能在设备管理器中禁用触摸板(它在默认的鼠标类驱动程序上运行)。

我正在开发设备驱动程序,因此我想也许可以编写一个小的过滤器驱动程序,该驱动程序仅接受IOCTL来启用和禁用在设备堆栈上传递鼠标事件消息,并通过原始PDO从用户模式获取消息。但是,我问了这个问题,有人建议我可以通过 SetupDi .. 函数在用户模式下执行此操作。那真的很好,因为这种原始的PDO通信方法是可以使用的PITA。

我以前只使用过 SetupDiGetClassDevs ,而且它们太多了,能否有人对Win32

API的这一部分有更多的经验,可以快速告诉我应该叫什么来停止/禁用鼠标设备或其接口,或者是否有。在框架的黑暗角落中的某个地方可以做到这一点(也许在WMI中?)。

我弄清楚了如何使用过滤器驱动程序来完成此工作,并在最初的问题上发布了我的操作方法。我仍然想知道是否可以直接从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。

还要注意,当您在64位Windows平台上运行此代码时,在构建应用程序时应以64位平台为目标。否则-

例如,在64位Windows平台上将应用程序作为32位进程运行时-您将收到SetupAPI错误InWow64(ERROR_IN_WOW64)。

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

以上是 Win32 API函数以编程方式启用/禁用设备 的全部内容, 来源链接: utcz.com/qa/407708.html

回到顶部