DeviceClass : IDisposable

// UsbEject version 1.0 March 2006
// written by Simon Mourier <email: simon [underscore] mourier [at] hotmail [dot] com>

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace UsbEject.Library
{
    /// <summary>
    /// A generic base class for physical device classes.
    /// </summary>
    public abstract class DeviceClass : IDisposable
	{
		private IntPtr _deviceInfoSet;
		private Guid _classGuid;
        private List<Device> _devices;

		protected DeviceClass(Guid classGuid)
			:this(classGuid, IntPtr.Zero)
		{
		}

        internal virtual Device CreateDevice(DeviceClass deviceClass, Native.SP_DEVINFO_DATA deviceInfoData, string path, int index)
        {
            return new Device(deviceClass, deviceInfoData, path, index);
        }

        /// <summary>
        /// Initializes a new instance of the DeviceClass class.
        /// </summary>
        /// <param name="classGuid">A device class Guid.</param>
        /// <param name="hwndParent">The handle of the top-level window to be used for any user interface or IntPtr.Zero for no handle.</param>
		protected DeviceClass(Guid classGuid, IntPtr hwndParent)
		{
			_classGuid = classGuid;

			_deviceInfoSet = Native.SetupDiGetClassDevs(ref _classGuid, 0, hwndParent, Native.DIGCF_DEVICEINTERFACE | Native.DIGCF_PRESENT);
			if (_deviceInfoSet.ToInt32() == Native.INVALID_HANDLE_VALUE)
				throw new Win32Exception(Marshal.GetLastWin32Error());
		}

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
		public void Dispose()
		{
			if (_deviceInfoSet != IntPtr.Zero)
			{
				Native.SetupDiDestroyDeviceInfoList(_deviceInfoSet);
				_deviceInfoSet = IntPtr.Zero;
			}
		}

        /// <summary>
        /// Gets the device class's guid.
        /// </summary>
		public Guid ClassGuid
		{
			get
			{
				return _classGuid;
			}
		}

        /// <summary>
        /// Gets the list of devices of this device class.
        /// </summary>
        public List<Device> Devices
        {
            get
            {
                if (_devices == null)
                {
                    _devices = new List<Device>();
			        int index = 0;
                    while (true)
                    {
                        Native.SP_DEVICE_INTERFACE_DATA interfaceData = new Native.SP_DEVICE_INTERFACE_DATA();

                        if (!Native.SetupDiEnumDeviceInterfaces(_deviceInfoSet, null, ref _classGuid, index, interfaceData))
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != Native.ERROR_NO_MORE_ITEMS)
                                throw new Win32Exception(error);
                            break;
                        }

                        Native.SP_DEVINFO_DATA devData = new Native.SP_DEVINFO_DATA();
                        int size = 0;
                        if (!Native.SetupDiGetDeviceInterfaceDetail(_deviceInfoSet, interfaceData, IntPtr.Zero, 0, ref size, devData))
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != Native.ERROR_INSUFFICIENT_BUFFER)
                                throw new Win32Exception(error);
                        }

                        IntPtr buffer = Marshal.AllocHGlobal(size);
                        Native.SP_DEVICE_INTERFACE_DETAIL_DATA detailData = new Native.SP_DEVICE_INTERFACE_DETAIL_DATA();
                        detailData.cbSize = Marshal.SizeOf(typeof(Native.SP_DEVICE_INTERFACE_DETAIL_DATA));
                        Marshal.StructureToPtr(detailData, buffer, false);

                        if (!Native.SetupDiGetDeviceInterfaceDetail(_deviceInfoSet, interfaceData, buffer, size, ref size, devData))
                        {
                            Marshal.FreeHGlobal(buffer);
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }

                        IntPtr pDevicePath = (IntPtr)((int)buffer + Marshal.SizeOf(typeof(int)));
                        string devicePath = Marshal.PtrToStringAuto(pDevicePath);
                        Marshal.FreeHGlobal(buffer);

                        Device device = CreateDevice(this, devData, devicePath, index);
                        _devices.Add(device);

                        index++;
                    }
                    _devices.Sort();
                }
                return _devices;
            }
        }

        internal Native.SP_DEVINFO_DATA GetInfo(int dnDevInst)
        {
            StringBuilder sb = new StringBuilder(1024);
            int hr = Native.CM_Get_Device_ID(dnDevInst, sb, sb.Capacity, 0);
            if (hr != 0)
                throw new Win32Exception(hr);

            Native.SP_DEVINFO_DATA devData = new Native.SP_DEVINFO_DATA();
            devData.cbSize = Marshal.SizeOf(typeof(Native.SP_DEVINFO_DATA));
            if (!Native.SetupDiOpenDeviceInfo(_deviceInfoSet, sb.ToString(), IntPtr.Zero, 0, devData))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            return devData;
        }

        internal string GetProperty(Native.SP_DEVINFO_DATA devData, int property, string defaultValue)
        {
            if (devData == null)
                throw new ArgumentNullException("devData");

            int propertyRegDataType = 0;
            int requiredSize;
            int propertyBufferSize = 1024;

            IntPtr propertyBuffer = Marshal.AllocHGlobal(propertyBufferSize);
            if (!Native.SetupDiGetDeviceRegistryProperty(_deviceInfoSet,
                devData,
                property,
                out propertyRegDataType,
                propertyBuffer,
                propertyBufferSize,
                out requiredSize))
            {
                Marshal.FreeHGlobal(propertyBuffer);
                int error = Marshal.GetLastWin32Error();
                if (error != Native.ERROR_INVALID_DATA)
                    throw new Win32Exception(error);
                return defaultValue;
            }

            string value = Marshal.PtrToStringAuto(propertyBuffer);
            Marshal.FreeHGlobal(propertyBuffer);
            return value;
        }

        internal int GetProperty(Native.SP_DEVINFO_DATA devData, int property, int defaultValue)
        {
            if (devData == null)
                throw new ArgumentNullException("devData");

            int propertyRegDataType = 0;
            int requiredSize;
            int propertyBufferSize = Marshal.SizeOf(typeof(int));

            IntPtr propertyBuffer = Marshal.AllocHGlobal(propertyBufferSize);
            if (!Native.SetupDiGetDeviceRegistryProperty(_deviceInfoSet,
                devData,
                property,
                out propertyRegDataType,
                propertyBuffer,
                propertyBufferSize,
                out requiredSize))
            {
                Marshal.FreeHGlobal(propertyBuffer);
                int error = Marshal.GetLastWin32Error();
                if (error != Native.ERROR_INVALID_DATA)
                    throw new Win32Exception(error);
                return defaultValue;
            }

            int value = (int)Marshal.PtrToStructure(propertyBuffer, typeof(int));
            Marshal.FreeHGlobal(propertyBuffer);
            return value;
        }

        internal Guid GetProperty(Native.SP_DEVINFO_DATA devData, int property, Guid defaultValue)
        {
            if (devData == null)
                throw new ArgumentNullException("devData");

            int propertyRegDataType = 0;
            int requiredSize;
            int propertyBufferSize = Marshal.SizeOf(typeof(Guid));

            IntPtr propertyBuffer = Marshal.AllocHGlobal(propertyBufferSize);
            if (!Native.SetupDiGetDeviceRegistryProperty(_deviceInfoSet,
                devData,
                property,
                out propertyRegDataType,
                propertyBuffer,
                propertyBufferSize,
                out requiredSize))
            {
                Marshal.FreeHGlobal(propertyBuffer);
                int error = Marshal.GetLastWin32Error();
                if (error != Native.ERROR_INVALID_DATA)
                    throw new Win32Exception(error);
                return defaultValue;
            }

            Guid value = (Guid)Marshal.PtrToStructure(propertyBuffer, typeof(Guid));
            Marshal.FreeHGlobal(propertyBuffer);
            return value;
        }

	}
}

你可能感兴趣的:(DeviceClass : IDisposable)