windows 如何以编程方式禁用系统设备?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4097000/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:33:07  来源:igfitidea点击:

How do I disable a system device programmatically?

c#.netwindows64-bitdevice

提问by Cheetah

I am looking for way to disable a system device (either USB or internal) in C#.NET given either the PID & VID or the device name.

我正在寻找在给定 PID & VID 或设备名称的 C#.NET 中禁用系统设备(USB 或内部)的方法。

After searching I found Hardware Helper Library for C#on CodeProject.

搜索后,我在 CodeProject 上找到了 C# 的硬件助手库

But I need something that will work on XP, Vista & Windows 7 (both x86 and x64 operating systems)...the project I linked only works with XP and Vista x86...even when running the application with administrator privileges.

但是我需要一些可以在 XP、Vista 和 Windows 7(x86 和 x64 操作系统)上运行的东西……我链接的项目只适用于 XP 和 Vista x86……即使在以管理员权限运行应用程序时也是如此。

Does anyone know of a solution that would work on all operating systems?

有谁知道适用于所有操作系统的解决方案?

回答by Frank Racis

Looks like there were two things in drf's version that were giving you trouble. Your x64 problem was caused by SP_DEVINFO_DATA having a uint where an IntPtr was needed. The second is that the SetupDiGetDevicePropertyW function is Vista+ and won't run on XP.

看起来 drf 版本中有两件事给您带来了麻烦。您的 x64 问题是由 SP_DEVINFO_DATA 具有需要 IntPtr 的 uint 引起的。第二个是SetupDiGetDevicePropertyW 函数是Vista+,不能在XP 上运行。

Here's a version with those two issues corrected. I tested as x86 and AnyCPU on XPx86 and Win7X64.

这是修正了这两个问题的版本。我在 XPx86 和 Win7X64 上测试为 x86 和 AnyCPU。

public static class DisableHardware
{
    const uint DIF_PROPERTYCHANGE = 0x12;
    const uint DICS_ENABLE = 1;
    const uint DICS_DISABLE = 2;  // disable device
    const uint DICS_FLAG_GLOBAL = 1; // not profile-specific
    const uint DIGCF_ALLCLASSES = 4;
    const uint DIGCF_PRESENT = 2;
    const uint ERROR_INVALID_DATA = 13;
    const uint ERROR_NO_MORE_ITEMS = 259;
    const uint ERROR_ELEMENT_NOT_FOUND = 1168;

    static DEVPROPKEY DEVPKEY_Device_DeviceDesc;
    static DEVPROPKEY DEVPKEY_Device_HardwareIds;

    [StructLayout(LayoutKind.Sequential)]
    struct SP_CLASSINSTALL_HEADER
    {
        public UInt32 cbSize;
        public UInt32 InstallFunction;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SP_PROPCHANGE_PARAMS
    {
        public SP_CLASSINSTALL_HEADER ClassInstallHeader;
        public UInt32 StateChange;
        public UInt32 Scope;
        public UInt32 HwProfile;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SP_DEVINFO_DATA
    {
        public UInt32 cbSize;
        public Guid classGuid;
        public UInt32 devInst;
        public IntPtr reserved;     // CHANGE #1 - was UInt32
    }

    [StructLayout(LayoutKind.Sequential)]
    struct DEVPROPKEY
    {
        public Guid fmtid;
        public UInt32 pid;
    }

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern IntPtr SetupDiGetClassDevsW(
        [In] ref Guid ClassGuid,
        [MarshalAs(UnmanagedType.LPWStr)]
string Enumerator,
        IntPtr parent,
        UInt32 flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiDestroyDeviceInfoList(IntPtr handle);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet,
        UInt32 memberIndex,
        [Out] out SP_DEVINFO_DATA deviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiSetClassInstallParams(
        IntPtr deviceInfoSet,
        [In] ref SP_DEVINFO_DATA deviceInfoData,
        [In] ref SP_PROPCHANGE_PARAMS classInstallParams,
        UInt32 ClassInstallParamsSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiChangeState(
        IntPtr deviceInfoSet,
        [In] ref SP_DEVINFO_DATA deviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiGetDevicePropertyW(
            IntPtr deviceInfoSet,
            [In] ref SP_DEVINFO_DATA DeviceInfoData,
            [In] ref DEVPROPKEY propertyKey,
            [Out] out UInt32 propertyType,
            IntPtr propertyBuffer,
            UInt32 propertyBufferSize,
            out UInt32 requiredSize,
            UInt32 flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiGetDeviceRegistryPropertyW(
      IntPtr DeviceInfoSet,
      [In] ref SP_DEVINFO_DATA  DeviceInfoData,
      UInt32 Property,
      [Out] out UInt32  PropertyRegDataType,
      IntPtr PropertyBuffer,
      UInt32 PropertyBufferSize,
      [In,Out] ref UInt32 RequiredSize
    );

    static DisableHardware()
    {
        DisableHardware.DEVPKEY_Device_DeviceDesc = new DEVPROPKEY();
        DEVPKEY_Device_DeviceDesc.fmtid = new Guid(
                0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67,
                0xd1, 0x46, 0xa8, 0x50, 0xe0);
        DEVPKEY_Device_DeviceDesc.pid = 2;

        DEVPKEY_Device_HardwareIds = new DEVPROPKEY();
        DEVPKEY_Device_HardwareIds.fmtid = new Guid(
            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67,
            0xd1, 0x46, 0xa8, 0x50, 0xe0);
        DEVPKEY_Device_HardwareIds.pid = 3;
    }




    public static void DisableDevice(Func<string, bool> filter, bool disable = true)
    {
        IntPtr info = IntPtr.Zero;
        Guid NullGuid = Guid.Empty;
        try
        {
            info = SetupDiGetClassDevsW(
                ref NullGuid,
                null,
                IntPtr.Zero,
                DIGCF_ALLCLASSES);
            CheckError("SetupDiGetClassDevs");

            SP_DEVINFO_DATA devdata = new SP_DEVINFO_DATA();
            devdata.cbSize = (UInt32)Marshal.SizeOf(devdata);

            // Get first device matching device criterion.
            for (uint i = 0; ; i++)
            {
                SetupDiEnumDeviceInfo(info,
                    i,
                    out devdata);
                // if no items match filter, throw
                if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
                    CheckError("No device found matching filter.", 0xcffff);
                CheckError("SetupDiEnumDeviceInfo");

                string devicepath = GetStringPropertyForDevice(info,
                                           devdata, 1); // SPDRP_HARDWAREID

                // Uncomment to print name/path
                //Console.WriteLine(GetStringPropertyForDevice(info,
                //                         devdata, DEVPKEY_Device_DeviceDesc));
                //Console.WriteLine("   {0}", devicepath);
                if (devicepath != null && filter(devicepath)) break;

            }

            SP_CLASSINSTALL_HEADER header = new SP_CLASSINSTALL_HEADER();
            header.cbSize = (UInt32)Marshal.SizeOf(header);
            header.InstallFunction = DIF_PROPERTYCHANGE;

            SP_PROPCHANGE_PARAMS propchangeparams = new SP_PROPCHANGE_PARAMS();
            propchangeparams.ClassInstallHeader = header;
            propchangeparams.StateChange = disable ? DICS_DISABLE : DICS_ENABLE;
            propchangeparams.Scope = DICS_FLAG_GLOBAL;
            propchangeparams.HwProfile = 0;

            SetupDiSetClassInstallParams(info,
                ref devdata,
                ref propchangeparams,
                (UInt32)Marshal.SizeOf(propchangeparams));
            CheckError("SetupDiSetClassInstallParams");

            SetupDiChangeState(
                info,
                ref devdata);
            CheckError("SetupDiChangeState");
        }
        finally
        {
            if (info != IntPtr.Zero)
                SetupDiDestroyDeviceInfoList(info);
        }
    }
    private static void CheckError(string message, int lasterror = -1)
    {

        int code = lasterror == -1 ? Marshal.GetLastWin32Error() : lasterror;
        if (code != 0)
            throw new ApplicationException(
                String.Format("Error disabling hardware device (Code {0}): {1}",
                    code, message));
    }

    private static string GetStringPropertyForDevice(IntPtr info, SP_DEVINFO_DATA devdata,
        uint propId)
    {
        uint proptype, outsize;
        IntPtr buffer = IntPtr.Zero;
        try
        {
            uint buflen = 512;
            buffer = Marshal.AllocHGlobal((int)buflen);
            outsize=0;
            // CHANGE #2 - Use this instead of SetupDiGetDeviceProperty 
            SetupDiGetDeviceRegistryPropertyW(
                info,
                ref devdata,
                propId,
                out proptype,
                buffer,
                buflen,
                ref outsize);
            byte[] lbuffer = new byte[outsize];
            Marshal.Copy(buffer, lbuffer, 0, (int)outsize);
            int errcode = Marshal.GetLastWin32Error();
            if (errcode == ERROR_INVALID_DATA) return null;
            CheckError("SetupDiGetDeviceProperty", errcode);
            return Encoding.Unicode.GetString(lbuffer);
        }
        finally
        {
            if (buffer != IntPtr.Zero)
                Marshal.FreeHGlobal(buffer);
        }
    }

}

回答by drf

It can be done using P/Invoke methods on the Windows Setup API. The API functions have been in Windows since W2K. The API calls may require administrative rights. Below is some rough code for using these APIs to disable (as well as enable) devices in C#, which allow invoking:

可以使用 Windows 安装程序 API 上的 P/Invoke 方法来完成。自 W2K 以来,API 函数一直在 Windows 中。API 调用可能需要管理权限。下面是一些粗略的代码,用于在 C# 中使用这些 API 禁用(以及启用)允许调用的设备:

  DisableDevice(
        n => n.ToUpperInvariant().Contains("VID_3F20&PID_8A1D"),
        true); // true disables the device, false enables it

The first parameter is a filter that is passed the hardware ID. This disables or enables the first device matching the provided filter. There is no effect if the device is already in the target state.

第一个参数是传递硬件 ID 的过滤器。这将禁用或启用与提供的过滤器匹配的第一个设备。如果设备已经处于目标状态,则没有任何影响。

The code follows.

代码如下。

public static class DisableHardware {
const uint DIF_PROPERTYCHANGE = 0x12;
const uint DICS_ENABLE = 1;
const uint DICS_DISABLE = 2;  // disable device
const uint DICS_FLAG_GLOBAL = 1; // not profile-specific
const uint DIGCF_ALLCLASSES = 4;
const uint DIGCF_PRESENT = 2;
const uint ERROR_NO_MORE_ITEMS = 259;
const uint ERROR_ELEMENT_NOT_FOUND = 1168;

static DEVPROPKEY DEVPKEY_Device_DeviceDesc;
static DEVPROPKEY DEVPKEY_Device_HardwareIds;

[StructLayout(LayoutKind.Sequential)]
struct SP_CLASSINSTALL_HEADER
{
    public UInt32 cbSize;
    public UInt32 InstallFunction;
}

[StructLayout(LayoutKind.Sequential)]
struct SP_PROPCHANGE_PARAMS
{
    public SP_CLASSINSTALL_HEADER ClassInstallHeader;
    public UInt32 StateChange;
    public UInt32 Scope;
    public UInt32 HwProfile;
}

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVINFO_DATA
{
    public UInt32 cbSize;
    public Guid classGuid;
    public UInt32 devInst;
    public UInt32 reserved;
}

[StructLayout(LayoutKind.Sequential)]
struct DEVPROPKEY
{
    public Guid fmtid;
    public UInt32 pid;
}

[DllImport("setupapi.dll", SetLastError = true)]
static extern IntPtr SetupDiGetClassDevsW(
    [In] ref Guid ClassGuid,
    [MarshalAs(UnmanagedType.LPWStr)]
    string Enumerator,
    IntPtr parent,
    UInt32 flags);

[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiDestroyDeviceInfoList(IntPtr handle);

[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet,
    UInt32 memberIndex,
    [Out] out SP_DEVINFO_DATA deviceInfoData);

[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiSetClassInstallParams(
    IntPtr deviceInfoSet,
    [In] ref SP_DEVINFO_DATA deviceInfoData,
    [In] ref SP_PROPCHANGE_PARAMS classInstallParams,
    UInt32 ClassInstallParamsSize);

[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiChangeState(
    IntPtr deviceInfoSet,
    [In] ref SP_DEVINFO_DATA deviceInfoData);

[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiGetDevicePropertyW(
        IntPtr deviceInfoSet,
        [In] ref SP_DEVINFO_DATA DeviceInfoData,
        [In] ref DEVPROPKEY propertyKey,
        [Out] out UInt32 propertyType,
        IntPtr propertyBuffer,
        UInt32 propertyBufferSize,
        out UInt32 requiredSize,
        UInt32 flags);

static DisableHardware()
{
    DisableHardware.DEVPKEY_Device_DeviceDesc = new DEVPROPKEY();
    DEVPKEY_Device_DeviceDesc.fmtid = new Guid(
            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67,
            0xd1, 0x46, 0xa8, 0x50, 0xe0);
    DEVPKEY_Device_DeviceDesc.pid = 2;

    DEVPKEY_Device_HardwareIds = new DEVPROPKEY();
    DEVPKEY_Device_HardwareIds.fmtid = new Guid(
        0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67,
        0xd1, 0x46, 0xa8, 0x50, 0xe0);
    DEVPKEY_Device_HardwareIds.pid = 3;
}




public static void DisableDevice(Func<string, bool> filter, bool disable = true)
{
    IntPtr info = IntPtr.Zero;
    Guid NullGuid = Guid.Empty;
    try
    {
        info = SetupDiGetClassDevsW(
            ref NullGuid,
            null,
            IntPtr.Zero,
            DIGCF_ALLCLASSES);
        CheckError("SetupDiGetClassDevs");

        SP_DEVINFO_DATA devdata = new SP_DEVINFO_DATA();
        devdata.cbSize = (UInt32)Marshal.SizeOf(devdata);

        // Get first device matching device criterion.
        for (uint i = 0; ; i++)
        {
            SetupDiEnumDeviceInfo(info,
                i,
                out devdata);
            // if no items match filter, throw
            if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
                CheckError("No device found matching filter.", 0xcffff);
            CheckError("SetupDiEnumDeviceInfo");

            string devicepath = GetStringPropertyForDevice(info,
                                       devdata, DEVPKEY_Device_HardwareIds);
            // Uncomment to print name/path
            //Console.WriteLine(GetStringPropertyForDevice(info,
            //                         devdata, DEVPKEY_Device_DeviceDesc));
            //Console.WriteLine("   {0}", devicepath);
            if (devicepath != null && filter(devicepath)) break;

        }

        SP_CLASSINSTALL_HEADER header = new SP_CLASSINSTALL_HEADER();
        header.cbSize = (UInt32)Marshal.SizeOf(header);
        header.InstallFunction = DIF_PROPERTYCHANGE;

        SP_PROPCHANGE_PARAMS propchangeparams = new SP_PROPCHANGE_PARAMS();
        propchangeparams.ClassInstallHeader = header;
        propchangeparams.StateChange = disable ? DICS_DISABLE : DICS_ENABLE;
        propchangeparams.Scope = DICS_FLAG_GLOBAL;
        propchangeparams.HwProfile = 0;

        SetupDiSetClassInstallParams(info,
            ref devdata,
            ref propchangeparams,
            (UInt32)Marshal.SizeOf(propchangeparams));
        CheckError("SetupDiSetClassInstallParams");

        SetupDiChangeState(
            info,
            ref devdata);
        CheckError("SetupDiChangeState");
    }
    finally
    {
        if (info != IntPtr.Zero)
            SetupDiDestroyDeviceInfoList(info);
    }
}
private static void CheckError(string message, int lasterror = -1)
{

    int code = lasterror == -1 ? Marshal.GetLastWin32Error() : lasterror;
    if (code != 0)
        throw new ApplicationException(
            String.Format("Error disabling hardware device (Code {0}): {1}",
                code, message));
}

private static string GetStringPropertyForDevice(IntPtr info, SP_DEVINFO_DATA devdata,
    DEVPROPKEY key)
{
    uint proptype, outsize;
    IntPtr buffer = IntPtr.Zero;
    try
    {
        uint buflen = 512;
        buffer = Marshal.AllocHGlobal((int)buflen);
        SetupDiGetDevicePropertyW(
            info,
            ref devdata,
            ref key,
            out proptype,
            buffer,
            buflen,
            out outsize,
            0);
        byte[] lbuffer = new byte[outsize];
        Marshal.Copy(buffer, lbuffer, 0, (int)outsize);
        int errcode = Marshal.GetLastWin32Error();
        if (errcode == ERROR_ELEMENT_NOT_FOUND) return null;
        CheckError("SetupDiGetDeviceProperty", errcode);
        return Encoding.Unicode.GetString(lbuffer);
    }
    finally
    {
        if (buffer != IntPtr.Zero)
            Marshal.FreeHGlobal(buffer);
    }
}
}

回答by DoomMuffins

I've built upon the XP-compatible answer and improved it a bit by adding a SafeDeviceInformationSetHandleclass and performing some general code cleanup/refactoring, and am adding it here for posterity:

我已经建立在与 XP 兼容的答案的基础上,并通过添加一个SafeDeviceInformationSetHandle类并执行一些通用代码清理/重构对其进行了改进,并将其添加到此处以供后代使用:

using System;
using System.Text;
using System.Security;
using System.ComponentModel;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;

public static class SetupApi
{
    private const string SETUPAPI = "setupapi.dll";
    private const int ERROR_INVALID_DATA = 13;
    private const int ERROR_INSUFFICIENT_BUFFER = 122;

    private class SafeDeviceInformationSetHandle : SafeHandleMinusOneIsInvalid
    {
        private SafeDeviceInformationSetHandle() : base(true)
        { }

        private SafeDeviceInformationSetHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
        {
            SetHandle(preexistingHandle);
        }

        [SecurityCritical]
        protected override bool ReleaseHandle()
        {
            return SetupDiDestroyDeviceInfoList(handle);
        }
    }

    #region Enumerations

    [Flags]
    private enum DIGCF : uint
    {
        DEFAULT         = 0x00000001,
        PRESENT         = 0x00000002,
        ALLCLASSES      = 0x00000004,
        PROFILE         = 0x00000008,
        DEVICEINTERFACE = 0x00000010
    }

    private enum SPDRP : uint
    {
        /// <summary>
        /// DeviceDesc (R/W)
        /// </summary>
        DEVICEDESC = 0x00000000,

        /// <summary>
        /// HardwareID (R/W)
        /// </summary>
        HARDWAREID = 0x00000001,

        /// <summary>
        /// CompatibleIDs (R/W)
        /// </summary>
        COMPATIBLEIDS = 0x00000002,

        /// <summary>
        /// unused
        /// </summary>
        UNUSED0 = 0x00000003,

        /// <summary>
        /// Service (R/W)
        /// </summary>
        SERVICE = 0x00000004,

        /// <summary>
        /// unused
        /// </summary>
        UNUSED1 = 0x00000005,

        /// <summary>
        /// unused
        /// </summary>
        UNUSED2 = 0x00000006,

        /// <summary>
        /// Class (R--tied to ClassGUID)
        /// </summary>
        CLASS = 0x00000007,

        /// <summary>
        /// ClassGUID (R/W)
        /// </summary>
        CLASSGUID = 0x00000008,

        /// <summary>
        /// Driver (R/W)
        /// </summary>
        DRIVER = 0x00000009,

        /// <summary>
        /// ConfigFlags (R/W)
        /// </summary>
        CONFIGFLAGS = 0x0000000A,

        /// <summary>
        /// Mfg (R/W)
        /// </summary>
        MFG = 0x0000000B,

        /// <summary>
        /// FriendlyName (R/W)
        /// </summary>
        FRIENDLYNAME = 0x0000000C,

        /// <summary>
        /// LocationInformation (R/W)
        /// </summary>
        LOCATION_INFORMATION = 0x0000000D,

        /// <summary>
        /// PhysicalDeviceObjectName (R)
        /// </summary>
        PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E,

        /// <summary>
        /// Capabilities (R)
        /// </summary>
        CAPABILITIES = 0x0000000F,

        /// <summary>
        /// UiNumber (R)
        /// </summary>
        UI_NUMBER = 0x00000010,

        /// <summary>
        /// UpperFilters (R/W)
        /// </summary>
        UPPERFILTERS = 0x00000011,

        /// <summary>
        /// LowerFilters (R/W)
        /// </summary>
        LOWERFILTERS = 0x00000012,

        /// <summary>
        /// BusTypeGUID (R)
        /// </summary>
        BUSTYPEGUID = 0x00000013,

        /// <summary>
        /// LegacyBusType (R)
        /// </summary>
        LEGACYBUSTYPE = 0x00000014,

        /// <summary>
        /// BusNumber (R)
        /// </summary>
        BUSNUMBER = 0x00000015,

        /// <summary>
        /// Enumerator Name (R)
        /// </summary>
        ENUMERATOR_NAME = 0x00000016,

        /// <summary>
        /// Security (R/W, binary form)
        /// </summary>
        SECURITY = 0x00000017,

        /// <summary>
        /// Security (W, SDS form)
        /// </summary>
        SECURITY_SDS = 0x00000018,

        /// <summary>
        /// Device Type (R/W)
        /// </summary>
        DEVTYPE = 0x00000019,

        /// <summary>
        /// Device is exclusive-access (R/W)
        /// </summary>
        EXCLUSIVE = 0x0000001A,

        /// <summary>
        /// Device Characteristics (R/W)
        /// </summary>
        CHARACTERISTICS = 0x0000001B,

        /// <summary>
        /// Device Address (R)
        /// </summary>
        ADDRESS = 0x0000001C,

        /// <summary>
        /// UiNumberDescFormat (R/W)
        /// </summary>
        UI_NUMBER_DESC_FORMAT = 0X0000001D,

        /// <summary>
        /// Device Power Data (R)
        /// </summary>
        DEVICE_POWER_DATA = 0x0000001E,

        /// <summary>
        /// Removal Policy (R)
        /// </summary>
        REMOVAL_POLICY = 0x0000001F,

        /// <summary>
        /// Hardware Removal Policy (R)
        /// </summary>
        REMOVAL_POLICY_HW_DEFAULT = 0x00000020,

        /// <summary>
        /// Removal Policy Override (RW)
        /// </summary>
        REMOVAL_POLICY_OVERRIDE = 0x00000021,

        /// <summary>
        /// Device Install State (R)
        /// </summary>
        INSTALL_STATE = 0x00000022,

        /// <summary>
        /// Device Location Paths (R)
        /// </summary>
        LOCATION_PATHS = 0x00000023,
    }

    private enum DIF : uint
    {
        SELECTDEVICE                   = 0x00000001,
        INSTALLDEVICE                  = 0x00000002,
        ASSIGNRESOURCES                = 0x00000003,
        PROPERTIES                     = 0x00000004,
        REMOVE                         = 0x00000005,
        FIRSTTIMESETUP                 = 0x00000006,
        FOUNDDEVICE                    = 0x00000007,
        SELECTCLASSDRIVERS             = 0x00000008,
        VALIDATECLASSDRIVERS           = 0x00000009,
        INSTALLCLASSDRIVERS            = 0x0000000A,
        CALCDISKSPACE                  = 0x0000000B,
        DESTROYPRIVATEDATA             = 0x0000000C,
        VALIDATEDRIVER                 = 0x0000000D,
        DETECT                         = 0x0000000F,
        INSTALLWIZARD                  = 0x00000010,
        DESTROYWIZARDDATA              = 0x00000011,
        PROPERTYCHANGE                 = 0x00000012,
        ENABLECLASS                    = 0x00000013,
        DETECTVERIFY                   = 0x00000014,
        INSTALLDEVICEFILES             = 0x00000015,
        UNREMOVE                       = 0x00000016,
        SELECTBESTCOMPATDRV            = 0x00000017,
        ALLOW_INSTALL                  = 0x00000018,
        REGISTERDEVICE                 = 0x00000019,
        NEWDEVICEWIZARD_PRESELECT      = 0x0000001A,
        NEWDEVICEWIZARD_SELECT         = 0x0000001B,
        NEWDEVICEWIZARD_PREANALYZE     = 0x0000001C,
        NEWDEVICEWIZARD_POSTANALYZE    = 0x0000001D,
        NEWDEVICEWIZARD_FINISHINSTALL  = 0x0000001E,
        UNUSED1                        = 0x0000001F,
        INSTALLINTERFACES              = 0x00000020,
        DETECTCANCEL                   = 0x00000021,
        REGISTER_COINSTALLERS          = 0x00000022,
        ADDPROPERTYPAGE_ADVANCED       = 0x00000023,
        ADDPROPERTYPAGE_BASIC          = 0x00000024,
        RESERVED1                      = 0x00000025,
        TROUBLESHOOTER                 = 0x00000026,
        POWERMESSAGEWAKE               = 0x00000027,
        ADDREMOTEPROPERTYPAGE_ADVANCED = 0x00000028,
        UPDATEDRIVER_UI                = 0x00000029,
        FINISHINSTALL_ACTION           = 0x0000002A,
        RESERVED2                      = 0x00000030,
    }

    private enum DICS : uint
    {
        ENABLE     = 0x00000001,
        DISABLE    = 0x00000002,
        PROPCHANGE = 0x00000003,
        START      = 0x00000004,
        STOP       = 0x00000005,
    }

    [Flags]
    private enum DICS_FLAG : uint
    {
        GLOBAL          = 0x00000001,
        CONFIGSPECIFIC  = 0x00000002,
        CONFIGGENERAL   = 0x00000004,
    }

    #endregion

    #region Structures

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVINFO_DATA
    {
        public UInt32 cbSize;
        public Guid ClassGuid;
        public UInt32 DevInst;
        public IntPtr Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_CLASSINSTALL_HEADER
    {
        public UInt32 cbSize;
        public DIF InstallFunction;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_PROPCHANGE_PARAMS
    {
        public SP_CLASSINSTALL_HEADER ClassInstallHeader;
        public DICS StateChange;
        public DICS_FLAG Scope;
        public UInt32 HwProfile;
    }

    #endregion

    #region P/Invoke Functions

    [DllImport(SETUPAPI, SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern SafeDeviceInformationSetHandle SetupDiGetClassDevs(
        [In] ref Guid ClassGuid,
        [In] string Enumerator,
        IntPtr hwndParent,
        DIGCF Flags
    );

    [DllImport(SETUPAPI, SetLastError = true)]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    [DllImport(SETUPAPI, SetLastError = true)]
    private static extern bool SetupDiEnumDeviceInfo(
        SafeDeviceInformationSetHandle DeviceInfoSet,
        UInt32 MemberIndex,
        ref SP_DEVINFO_DATA DeviceInfoData
    );

    [DllImport(SETUPAPI, SetLastError = true)]
    private static extern bool SetupDiSetClassInstallParams(
        SafeDeviceInformationSetHandle DeviceInfoSet,
        [In] ref SP_DEVINFO_DATA deviceInfoData,
        [In] ref SP_PROPCHANGE_PARAMS classInstallParams,
        UInt32 ClassInstallParamsSize
    );

    [DllImport(SETUPAPI, SetLastError = true)]
    private static extern bool SetupDiChangeState(
        SafeDeviceInformationSetHandle DeviceInfoSet,
        [In, Out] ref SP_DEVINFO_DATA DeviceInfoData
    );

    [DllImport(SETUPAPI, SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool SetupDiGetDeviceRegistryProperty(
        SafeDeviceInformationSetHandle DeviceInfoSet,
        [In] ref SP_DEVINFO_DATA DeviceInfoData,
        SPDRP Property,
        out RegistryValueKind PropertyRegDataType,
        [Out] byte[] PropertyBuffer,
        UInt32 PropertyBufferSize,
        out UInt32 RequiredSize
    );

    #endregion

    private static void CheckWin32CallSuccess(bool success)
    {
        if (!success)
        {
            throw new Win32Exception();
        }
    }

    private static string GetStringPropertyForDevice(SafeDeviceInformationSetHandle infoSet, ref SP_DEVINFO_DATA devInfo, SPDRP property)
    {
        RegistryValueKind regType;
        UInt32 requiredSize;

        if (!SetupDiGetDeviceRegistryProperty(infoSet, ref devInfo, property, out regType, null, 0, out requiredSize))
        {
            switch (Marshal.GetLastWin32Error())
            {
                case ERROR_INSUFFICIENT_BUFFER:
                    break;
                case ERROR_INVALID_DATA:
                    return string.Empty;
                default:
                    throw new Win32Exception();
            }
        }

        byte[] propertyBuffer = new byte[requiredSize];
        CheckWin32CallSuccess(SetupDiGetDeviceRegistryProperty(infoSet, ref devInfo, property, out regType, propertyBuffer, (uint)propertyBuffer.Length, out requiredSize));

        return Encoding.Unicode.GetString(propertyBuffer);
    }

    public static void EnableDevice(Func<string, bool> hardwareIdFilter, bool enable)
    {
        Guid nullGuid = Guid.Empty;
        using (SafeDeviceInformationSetHandle infoSet = SetupDiGetClassDevs(ref nullGuid, null, IntPtr.Zero, DIGCF.ALLCLASSES))
        {
            CheckWin32CallSuccess(!infoSet.IsInvalid);

            SP_DEVINFO_DATA devInfo = new SP_DEVINFO_DATA();
            devInfo.cbSize = (UInt32) Marshal.SizeOf(devInfo);

            for (uint index = 0; ; ++index)
            {
                CheckWin32CallSuccess(SetupDiEnumDeviceInfo(infoSet, index, ref devInfo));

                string hardwareId = GetStringPropertyForDevice(infoSet, ref devInfo, SPDRP.HARDWAREID);

                if ((!string.IsNullOrEmpty(hardwareId)) && (hardwareIdFilter(hardwareId)))
                {
                    break;
                }
            }

            SP_CLASSINSTALL_HEADER classinstallHeader = new SP_CLASSINSTALL_HEADER();
            classinstallHeader.cbSize = (UInt32) Marshal.SizeOf(classinstallHeader);
            classinstallHeader.InstallFunction = DIF.PROPERTYCHANGE;

            SP_PROPCHANGE_PARAMS propchangeParams = new SP_PROPCHANGE_PARAMS
                                                        {
                                                            ClassInstallHeader = classinstallHeader,
                                                            StateChange = enable ? DICS.ENABLE : DICS.DISABLE,
                                                            Scope = DICS_FLAG.GLOBAL,
                                                            HwProfile = 0,
                                                        };

            CheckWin32CallSuccess(SetupDiSetClassInstallParams(infoSet, ref devInfo, ref propchangeParams, (UInt32)Marshal.SizeOf(propchangeParams)));

            CheckWin32CallSuccess(SetupDiChangeState(infoSet, ref devInfo));
        }
    }
}

回答by Jannis Kappertz

I managed to solve this Problem using DevManView.exe (freeware):

我设法使用 DevManView.exe(免费软件)解决了这个问题:

  1. Download DevManView.exe and put the .exe file somewhere: http://www.nirsoft.net/utils/device_manager_view.html

  2. Go to your Device Manager and search for the Name of the device you want to enable/disable.

  3. In C#, create and start a new process for disabling the device (using the name of the device you found in the device manager).

    Process devManViewProc = new Process();
    devManViewProc.StartInfo.FileName = @"<path to DevManView.exe>\DevManView.exe";
    devManViewProc.StartInfo.Arguments = "/disable \"<name of the device>\"";
    devManViewProc.Start();
    devManViewProc.WaitForExit();
    
  4. And enable it again.

    devManViewProc.StartInfo.Arguments = "/enable \"<name of the device>\"";
    devManViewProc.Start();
    devManViewProc.WaitForExit();
    
  1. 下载 DevManView.exe 并将 .exe 文件放在某处:http://www.nirsoft.net/utils/device_manager_view.html

  2. 转到您的设备管理器并搜索您要启用/禁用的设备的名称。

  3. 在 C# 中,创建并启动一个用于禁用设备的新进程(使用您在设备管理器中找到的设备名称)。

    Process devManViewProc = new Process();
    devManViewProc.StartInfo.FileName = @"<path to DevManView.exe>\DevManView.exe";
    devManViewProc.StartInfo.Arguments = "/disable \"<name of the device>\"";
    devManViewProc.Start();
    devManViewProc.WaitForExit();
    
  4. 并再次启用它。

    devManViewProc.StartInfo.Arguments = "/enable \"<name of the device>\"";
    devManViewProc.Start();
    devManViewProc.WaitForExit();
    

回答by Peter

I'm using devcon.exe to solve this issue. with the following code:

我正在使用 devcon.exe 来解决这个问题。使用以下代码:

public class DevconHelper
{
    private readonly ILogger logger;
    public DevconHelper(ILogger logger)
    {
        this.logger = logger;
    }

    readonly static string devconPath = @"devcon\" + (Environment.Is64BitOperatingSystem ? "x64" : "x86") + @"\devcon.exe";
    readonly static Regex parseHwidsOutput = new Regex(@"(?<id>[^\n]+)\n {4}Name: (?<name>[^\n]+)\n {4}Hardware IDs:\n(?<hwids>(?: {8}[^\n]+\n?)+)");
    readonly static Regex parseEnableDisableOutput = new Regex(@"(\d+) device\(s\) (are enabled|disabled)\.");

    public async Task<IEnumerable<Device>> GetDevicesAsync(string filterString = "*")
    {
        logger.Trace("GetDevicesAsync");
        using (var listDevicesProcess = Process.Start(new ProcessStartInfo(devconPath, "hwids " + filterString) { RedirectStandardOutput = true, UseShellExecute = false }))
        {
            var content = await listDevicesProcess.StandardOutput.ReadToEndAsync();

            var matches = parseHwidsOutput.Matches(content.Replace(Environment.NewLine, "\n")); //Regex is based on \n
            logger.Trace("GetDevicesAsync process output: {Content}, parsed {NumberOfMatches}, devconPath: {DevconPath}", content, matches.Count, devconPath);
            return matches.OfType<Match>().Select(match =>
            {
                var id = match.Groups["id"].Value;
                var name = match.Groups["name"].Value;
                var hwids = match.Groups["hwids"].Value.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(line => line.Trim());
                return new Device() { Id = id, Name = name, HardwareIds = hwids.ToArray() };
            });
        }
    }

    public async Task<bool> EnableAsync(Device device)
    {
        logger.Trace("EnableAsync");
        using (var disableProcess = Process.Start(new ProcessStartInfo(devconPath, "enable " + device.HardwareIds.First()) { RedirectStandardOutput = true, UseShellExecute = false }))
        {
            var content = await disableProcess.StandardOutput.ReadToEndAsync();
            var lastLine = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Last();
            logger.Trace("EnableAsync process output: {Content}, LastLine: {LastLine}", content, lastLine);
            return parseEnableDisableOutput.IsMatch(lastLine);
        }
    }

    public async Task<bool> DisableAsync(Device device)
    {
        logger.Trace("DisableAsync");
        using (var disableProcess = Process.Start(new ProcessStartInfo(devconPath, "disable " + device.HardwareIds.First()) { RedirectStandardOutput = true, UseShellExecute = false }))
        {
            var content = await disableProcess.StandardOutput.ReadToEndAsync();
            var lastLine = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Last();
            logger.Trace("DisableAsync process output: {Content}, LastLine: {LastLine}", content, lastLine);
            return parseEnableDisableOutput.IsMatch(lastLine);
        }
    }

    public class Device
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string[] HardwareIds { get; set; }
    }
}

Then you can use it like this.

然后你可以像这样使用它。

var devices = await devconHelper.GetDevicesAsync();
var device = devices.FirstOrDefault(x => x.Name == Settings.GPSDeviceName);
if (device != null)
{
    logger.Trace("Found the device!");
    logger.Info("Disabling the device!");
    if (await devconHelper.DisableAsync(device))
    {
        logger.Info("GPS device has been disabled!");
    }
    else
    {
        logger.Warn("Failed to disable the device!");
    }
    await Task.Delay(1000);
    logger.Info("Enabling device!");
    if (await devconHelper.EnableAsync(device))
    {
        logger.Info("Device has been enabled!");
    }
    else
    {
        logger.Fatal("Failed to enable the device!");
    }
}
else
{
    logger.Warn("Could not find the device!");
}

This has been tested on windows 10 and 8.1 and works as intended!

这已在 Windows 10 和 8.1 上进行了测试,并按预期工作!

回答by Mehul Trivedi

It can be done using P/Invoke methods on the Windows Setup API. The API functions have been in Windows since W2K. The API calls may require administrative rights. Below is some rough code for using these APIs to disable (as well as enable) devices in C#, which allow invoking:

可以使用 Windows 安装程序 API 上的 P/Invoke 方法来完成。自 W2K 以来,API 函数一直在 Windows 中。API 调用可能需要管理权限。下面是一些粗略的代码,用于在 C# 中使用这些 API 禁用(以及启用)允许调用的设备:

DisableDevice(
    n => n.ToUpperInvariant().Contains("VID_3F20&PID_8A1D"),
    true); // true disables the device, false enables it

This works on Windows 10 on Dell inspi 15.

这适用于 Dell inspi 15 上的 Windows 10。