Windows Storage Management API - VDS (Virtual Disk Service) Uninstall Disk Equivalent method

687 views Asked by At

Since VDS is being deprecated and the Windows Storage Management API is replacing it - are there any WMI, IOCTL, DeviceIoControl or Windows Storage Management API methods that are equivalent to the VDS method "UninstallDisks"?

I'm not able to find any other method of doing what the VDS method "UninstallDisks" does.

Any help would be appreciated.

1

There are 1 answers

1
parkerflyz On

Figured it out myself with a combination of other contributors code.

Reference: Win32 API function to programmatically enable/disable device

Main codebase below:

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

namespace WindowsStorageManagementAPI.Devices
{
    public class DeviceInfoData
    {
        public int Size { get; set; }
        public Guid ClassGuid { get; set; }
        public int DevInst { get; set; }
        public IntPtr Reserved { get; set; }
    }

    public class SetupApiWrapper
    {
        private const string SetupAPI = "setupapi.dll";
        private const string NewDevLib = "Newdev.dll";

        #region NATIVE ENUMS
        [Flags()]
        private enum SetupDiGetClassDevsFlags
        {
            Default = 1,
            Present = 2,
            AllClasses = (int)0x04,
            Profile = 8,
            DeviceInterface = (int)0x10
        }

        private 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
        }

        private enum StateChangeAction
        {
            Enable = 1,
            Disable = 2,
            PropChange = 3,
            Start = 4,
            Stop = 5
        }

        [Flags()]
        private enum Scope
        {
            Global = 1,
            ConfigSpecific = 2,
            ConfigGeneral = 4
        }

        private 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),
            NoMoreItems = unchecked((int)0xe0000259),
            ElementNotFound = unchecked((int)0xe0001168),
            InvalidData = unchecked((int)0xe0000013),
        }
        #endregion

        #region NATIVE STRUCTS
        [StructLayout(LayoutKind.Sequential)]
        private struct DeviceInfoDataNative
        {
            public int Size;
            public Guid ClassGuid;
            public int DeviceInstance;
            public IntPtr Reserved;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct ClassInstallHeader
        {
            public int Size;
            public DiFunction InstallFunction;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct PropertyChangeParameters
        {
            public ClassInstallHeader ClassInstallHeader;

            public StateChangeAction StateChange;
            public Scope Scope;
            public int HwProfile;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RemoveDeviceParameters
        {
            public ClassInstallHeader ClassInstallHeader;
            public Scope Scope;
            public int HwProfile;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct DevicePropertyKey
        {
            public Guid fmtId;
            public int pId;

            // from devpkey.h
            public static readonly DevicePropertyKey Device_Parent = new DevicePropertyKey { fmtId = new Guid("{4340A6C5-93FA-4706-972C-7B648008A5A7}"), pId = 8 };
            public static readonly DevicePropertyKey Device_Children = new DevicePropertyKey { fmtId = new Guid("{4340A6C5-93FA-4706-972C-7B648008A5A7}"), pId = 9 };
        }
        #endregion

        #region P/INVOKE
        [SuppressUnmanagedCodeSecurity()]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport(SetupAPI, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);

        [DllImport(SetupAPI, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetupDiCallClassInstaller(DiFunction installFunction, SafeDeviceInfoSetHandle deviceInfoSet, [In()] ref DeviceInfoDataNative deviceInfoData);

        [DllImport(SetupAPI, SetLastError = true)]
        private static extern bool SetupDiEnumDeviceInfo(SafeDeviceInfoSetHandle DeviceInfoSet, int MemberIndex, ref DeviceInfoDataNative DeviceInfoData);

        [DllImport(SetupAPI, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern SafeDeviceInfoSetHandle SetupDiGetClassDevs(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPWStr)] string Enumerator, IntPtr HwndParent, SetupDiGetClassDevsFlags Flags);

        [DllImport(SetupAPI, SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetupDiGetDeviceInstanceId(IntPtr deviceInfoSet, ref DeviceInfoDataNative did, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder DeviceInstanceId, int DeviceInstanceIdSize, out int RequiredSize);

        [DllImport(SetupAPI, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetupDiSetClassInstallParams(SafeDeviceInfoSetHandle deviceInfoSet, [In()] ref DeviceInfoDataNative deviceInfoData, [In()] ref RemoveDeviceParameters classInstallParams, int classInstallParamsSize);

        [DllImport("Newdev.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DiUninstallDevice(IntPtr hwnd, [In()] SafeDeviceInfoSetHandle deviceInfoSet, [In()] ref DeviceInfoDataNative deviceInfoData, [In()] int flags, out bool NeedReboot);

        [DllImport(SetupAPI, SetLastError = true, EntryPoint = "SetupDiGetDevicePropertyW")]
        private static extern bool SetupDiGetDeviceProperty(SafeDeviceInfoSetHandle deviceInfoSet, ref DeviceInfoDataNative DeviceInfoData, ref DevicePropertyKey propertyKey, out int propertyType, IntPtr propertyBuffer, int propertyBufferSize, out int requiredSize, int flags);
        #endregion

        private class SafeDeviceInfoSetHandle : SafeHandleZeroOrMinusOneIsInvalid
        {

            private SafeDeviceInfoSetHandle() : base(true)
            {
            }

            protected override bool ReleaseHandle()
            {
                return SetupDiDestroyDeviceInfoList(this.handle);
            }
        }

        private static DeviceInfoDataNative GetDeviceInfoData(SafeDeviceInfoSetHandle handle)
        {
            DeviceInfoDataNative _data = new DeviceInfoDataNative();

            _data.Size = Marshal.SizeOf(_data);

            if (!SetupDiEnumDeviceInfo(handle, 0, ref _data))
            {
                int error = Marshal.GetLastWin32Error();

                if (error == (int)SetupApiError.NoMoreItems)                                    
                    return _data;

                throw new Win32Exception(error);
            }

            return _data;
        }

        private static DeviceInfoDataNative[] GetDevicesInfoData(SafeDeviceInfoSetHandle handle)
        {
            List<DeviceInfoDataNative> _data = new List<DeviceInfoDataNative>();
            DeviceInfoDataNative deviceInfoData = new DeviceInfoDataNative();

            int index = 0;
            int deviceInfoDataSize = Marshal.SizeOf(deviceInfoData);

            deviceInfoData.Size = deviceInfoDataSize;

            while (SetupDiEnumDeviceInfo(handle, index, ref deviceInfoData))
            {
                _data.Add(deviceInfoData);
                index += 1;
                deviceInfoData = new DeviceInfoDataNative();
                deviceInfoData.Size = deviceInfoDataSize;
            }

            return _data.ToArray();
        }

        private static int GetIndexOfInstance(SafeDeviceInfoSetHandle handle, DeviceInfoDataNative[] 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 = SetupDiGetDeviceInstanceId(handle.DangerousGetHandle(), ref diData[index], sb, sb.Capacity, out requiredSize);
                if (result == false && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
                {
                    sb.Capacity = requiredSize;
                    result = 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;
        }

        public static bool UninstallDevice(Guid classGuid, string instanceId)
        {
            SafeDeviceInfoSetHandle handle = null;
            bool result = false;

            try
            {
                // Get the handle to a device information set for all devices matching classGuid that are present on the system.
                handle = SetupDiGetClassDevs(ref classGuid, instanceId, IntPtr.Zero, SetupDiGetClassDevsFlags.AllClasses | SetupDiGetClassDevsFlags.DeviceInterface);

                if (handle.IsInvalid)
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // Get the device information data for each matching device.
                DeviceInfoDataNative data = GetDeviceInfoData(handle);

                // Find the index of our instance. i.e. the touchpad mouse - I have 3 mice attached...
                //int index = GetIndexOfInstance(handle, diData, instanceId);

                // TODO: Check the data structure first

                // Uninstall
                result = StartUninstallDevice(handle, data);
            }
            finally
            {
                if (handle != null)
                {
                    if (handle.IsClosed == false)
                    {
                        handle.Close();
                    }

                    handle.Dispose();
                }                
            }

            return result;
        }

        private static bool StartUninstallDevice(SafeDeviceInfoSetHandle handle, DeviceInfoDataNative data)
        {
            ClassInstallHeader header = new ClassInstallHeader();
            RemoveDeviceParameters removalParameters = new RemoveDeviceParameters();

            bool needsReboot;

            removalParameters.ClassInstallHeader.Size = Marshal.SizeOf(header);
            removalParameters.ClassInstallHeader.InstallFunction = DiFunction.Remove;
            removalParameters.Scope = Scope.Global;
            removalParameters.HwProfile = 0;

            bool result = SetupDiSetClassInstallParams(handle, ref data, ref removalParameters, Marshal.SizeOf(removalParameters));

            if (result == false)
                throw new Win32Exception();

            result = DiUninstallDevice(IntPtr.Zero, handle, ref data, 0, out needsReboot);

            // TODO: Check if need reboot

            if (result == false)
            {
                int error = Marshal.GetLastWin32Error();

                if (error == (int)SetupApiError.NotDisableable)
                    throw new ArgumentException("Device can't be disabled (programmatically or in Device Manager)");
                else if (error >= (int)SetupApiError.NoAssociatedClass && error <= (int)SetupApiError.OnlyValidateViaAuthenticode)
                    throw new Win32Exception("SetupAPI Error: " + ((SetupApiError)error).ToString());
                else
                    throw new Win32Exception();
            }

            return result;
        }

        public static void RemoveDevice(Guid classGuid, string instanceId)
        {
            SafeDeviceInfoSetHandle handle = null;

            try
            {
                // Get the handle to a device information set for all devices matching classGuid that are present on the system.
                handle = SetupDiGetClassDevs(ref classGuid, instanceId, IntPtr.Zero, SetupDiGetClassDevsFlags.AllClasses | SetupDiGetClassDevsFlags.DeviceInterface);

                if (handle.IsInvalid)
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // Get the device information data for each matching device.
                DeviceInfoDataNative data = GetDeviceInfoData(handle);

                // Find the index of our instance. i.e. the touchpad mouse - I have 3 mice attached...
                //int index = GetIndexOfInstance(handle, diData, instanceId);

                // Uninstall
                bool result = StartRemoveDevice(handle, data);
            }
            finally
            {
                if (handle != null)
                {
                    if (handle.IsClosed == false)
                    {
                        handle.Close();
                    }
                    handle.Dispose();
                }
            }
        }

        private static bool StartRemoveDevice(SafeDeviceInfoSetHandle handle, DeviceInfoDataNative data)
        {
            ClassInstallHeader header = new ClassInstallHeader();
            RemoveDeviceParameters removalParameters = new RemoveDeviceParameters();

            removalParameters.ClassInstallHeader.Size = Marshal.SizeOf(header);
            removalParameters.ClassInstallHeader.InstallFunction = DiFunction.Remove;
            removalParameters.Scope = Scope.Global;
            removalParameters.HwProfile = 0;

            bool result = SetupDiSetClassInstallParams(handle, ref data, ref removalParameters, Marshal.SizeOf(removalParameters));

            if (result == false)
                throw new Win32Exception();

            result = SetupDiCallClassInstaller(DiFunction.Remove, handle, ref data);

            if (result == false)
            {
                int error = Marshal.GetLastWin32Error();

                if (error == (int)SetupApiError.NotDisableable)
                    throw new ArgumentException("Device can't be disabled (programmatically or in Device Manager).");
                else if (error >= (int)SetupApiError.NoAssociatedClass && error <= (int)SetupApiError.OnlyValidateViaAuthenticode)
                    throw new Win32Exception("SetupAPI Error: " + ((SetupApiError)error).ToString());
                else
                    throw new Win32Exception();
            }

            return result;
        }
    }
}

Usage:

/////* CD-ROM as an example */////

// Found in the Device Manager under <Device> -> Properties -> Details -> Class Guid
Guid cdromClassGuid = new Guid("4d36e965-e325-11ce-bfc1-08002be10318");

// Found using WMI calls -> Disk -> Partitions -> LogicalDisks
// For the CD-ROM example: Device Manager under <Device> -> Properties -> Details -> Device Instance Path
string cdromInstancePath = @"SCSI\CDROM&VEN_MATSHITA&PROD_BD-RE_UJ260AF\4&315C1285&0&000000";

bool success = SetupApiWrapper.UninstallDevice(cdromClassGuid, cdromInstancePath);