How do I disable a system device programatically?

2019-01-04 12:14发布

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.

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

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.

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

5条回答
孤傲高冷的网名
2楼-- · 2019-01-04 12:40

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

  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();
    
查看更多
Rolldiameter
3楼-- · 2019-01-04 12:43

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.

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

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);
        }
    }

}
查看更多
放我归山
4楼-- · 2019-01-04 12:43

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:

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.

查看更多
等我变得足够好
5楼-- · 2019-01-04 12:51

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:

  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.

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);
    }
}
}
查看更多
不美不萌又怎样
6楼-- · 2019-01-04 12:59

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

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));
        }
    }
}
查看更多
登录 后发表回答