internal static IEnumerable <DeviceInfo> EnumerateDevicesInternal(SafeHandle safeHandle, string hostName, DeviceGuid deviceInterfaceGuid) { bool callerHandle = safeHandle != null; Guid deviceGuid = new Guid(Utils.GetEnumDescription(deviceInterfaceGuid)); // CM_Connect_Machine() // MSDN Note: Beginning in Windows 8 and Windows Server 2012 functionality to access remote machines has been removed. // You cannot access remote machines when running on these versions of Windows. // http://msdn.microsoft.com/en-us/library/windows/hardware/ff537948%28v=vs.85%29.aspx SafeCmConnectMachineHandle safeMachineHandle; int lastError = NativeMethods.CM_Connect_Machine(Path.LocalToUncInternal(Host.GetUncName(hostName), false, false, false, false), out safeMachineHandle); if (safeMachineHandle.IsInvalid) { safeMachineHandle.Close(); NativeError.ThrowException(lastError, Resources.HandleInvalid); } using (safeMachineHandle) { // Start at the "Root" of the device tree of the specified machine. if (!callerHandle) { safeHandle = NativeMethods.SetupDiGetClassDevsEx(ref deviceGuid, IntPtr.Zero, IntPtr.Zero, NativeMethods.SetupDiGetClassDevsExFlags.Present | NativeMethods.SetupDiGetClassDevsExFlags.DeviceInterface, IntPtr.Zero, hostName, IntPtr.Zero); } if (safeHandle.IsInvalid) { safeHandle.Close(); NativeError.ThrowException(Marshal.GetLastWin32Error(), Resources.HandleInvalid); } try { uint memberInterfaceIndex = 0; NativeMethods.SpDeviceInterfaceData deviceInterfaceData = CreateDeviceInterfaceDataInstance(); // Start enumerating Device Interfaces. while (NativeMethods.SetupDiEnumDeviceInterfaces(safeHandle, IntPtr.Zero, ref deviceGuid, memberInterfaceIndex++, ref deviceInterfaceData)) { lastError = Marshal.GetLastWin32Error(); if (lastError != Win32Errors.NO_ERROR) { NativeError.ThrowException(lastError, hostName); } NativeMethods.SpDeviceInfoData deviceInfoData = CreateDeviceInfoDataInstance(); NativeMethods.SpDeviceInterfaceDetailData deviceInterfaceDetailData = GetDeviceInterfaceDetailDataInstance(safeHandle, deviceInterfaceData, deviceInfoData); // Get device interace details. if (!NativeMethods.SetupDiGetDeviceInterfaceDetail(safeHandle, ref deviceInterfaceData, ref deviceInterfaceDetailData, NativeMethods.DefaultFileBufferSize, IntPtr.Zero, ref deviceInfoData)) { lastError = Marshal.GetLastWin32Error(); if (lastError != Win32Errors.NO_ERROR) { NativeError.ThrowException(lastError, hostName); } } // Create DeviceInfo instance. // Set DevicePath property of DeviceInfo instance. DeviceInfo deviceInfo = new DeviceInfo(hostName) { DevicePath = deviceInterfaceDetailData.DevicePath }; // Current InstanceId is at the "USBSTOR" level, so we // need up "move up" one level to get to the "USB" level. uint ptrPrevious; // CM_Get_Parent_Ex() // Note: Using this function to access remote machines is not supported // beginning with Windows 8 and Windows Server 2012, as this functionality has been removed. // http://msdn.microsoft.com/en-us/library/windows/hardware/ff538615%28v=vs.85%29.aspx lastError = NativeMethods.CM_Get_Parent_Ex(out ptrPrevious, deviceInfoData.DevInst, 0, safeMachineHandle); if (lastError != Win32Errors.CR_SUCCESS) { NativeError.ThrowException(lastError, hostName); } // Now we get the InstanceID of the USB level device. using (SafeGlobalMemoryBufferHandle safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize)) { // CM_Get_Device_ID_Ex() // Note: Using this function to access remote machines is not supported beginning with Windows 8 and Windows Server 2012, // as this functionality has been removed. // http://msdn.microsoft.com/en-us/library/windows/hardware/ff538411%28v=vs.85%29.aspx lastError = NativeMethods.CM_Get_Device_ID_Ex(deviceInfoData.DevInst, safeBuffer, (uint)safeBuffer.Capacity, 0, safeMachineHandle); if (lastError != Win32Errors.CR_SUCCESS) { NativeError.ThrowException(lastError, hostName); } // CA2001:AvoidCallingProblematicMethods IntPtr buffer = IntPtr.Zero; bool successRef = false; safeBuffer.DangerousAddRef(ref successRef); // MSDN: The DangerousGetHandle method poses a security risk because it can return a handle that is not valid. if (successRef) { buffer = safeBuffer.DangerousGetHandle(); } safeBuffer.DangerousRelease(); if (buffer == IntPtr.Zero) { NativeError.ThrowException(Resources.HandleDangerousRef); } // CA2001:AvoidCallingProblematicMethods // Add to instance. deviceInfo.InstanceId = Marshal.PtrToStringUni(buffer); } #region Get Registry Properties using (SafeGlobalMemoryBufferHandle safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize)) { uint regType; string dataString; // CA2001:AvoidCallingProblematicMethods IntPtr buffer = IntPtr.Zero; bool successRef = false; safeBuffer.DangerousAddRef(ref successRef); // MSDN: The DangerousGetHandle method poses a security risk because it can return a handle that is not valid. if (successRef) { buffer = safeBuffer.DangerousGetHandle(); } safeBuffer.DangerousRelease(); if (buffer == IntPtr.Zero) { NativeError.ThrowException(Resources.HandleDangerousRef); } // CA2001:AvoidCallingProblematicMethods uint safeBufferCapacity = (uint)safeBuffer.Capacity; if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.BaseContainerId, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { dataString = Marshal.PtrToStringUni(buffer); if (!Utils.IsNullOrWhiteSpace(dataString)) { deviceInfo.BaseContainerId = new Guid(dataString); } } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.ClassGuid, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { dataString = Marshal.PtrToStringUni(buffer); if (!Utils.IsNullOrWhiteSpace(dataString)) { deviceInfo.ClassGuid = new Guid(dataString); } } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Class, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.Class = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.CompatibleIds, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.CompatibleIds = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.DeviceDescription, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.DeviceDescription = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Driver, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.Driver = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.EnumeratorName, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.EnumeratorName = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.FriendlyName, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.FriendlyName = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.HardwareId, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.HardwareId = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.LocationInformation, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.LocationInformation = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.LocationPaths, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.LocationPaths = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Manufacturer, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.Manufacturer = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.PhysicalDeviceObjectName, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.PhysicalDeviceObjectName = Marshal.PtrToStringUni(buffer); } if (NativeMethods.SetupDiGetDeviceRegistryProperty(safeHandle, ref deviceInfoData, NativeMethods.SetupDiGetDeviceRegistryPropertyEnum.Service, out regType, safeBuffer, safeBufferCapacity, IntPtr.Zero)) { deviceInfo.Service = Marshal.PtrToStringUni(buffer); } } #endregion // Get Registry Properties yield return(deviceInfo); // Get new structure instance. deviceInterfaceData = CreateDeviceInterfaceDataInstance(); } } finally { // Handle is ours, dispose. if (!callerHandle && safeHandle != null) { safeHandle.Close(); } } } }
internal static IEnumerable <DeviceInfo> EnumerateDevicesCore(string hostName, DeviceGuid deviceGuid, bool getAllProperties) { if (Utils.IsNullOrWhiteSpace(hostName)) { hostName = Environment.MachineName; } // CM_Connect_Machine() // MSDN Note: Beginning in Windows 8 and Windows Server 2012 functionality to access remote machines has been removed. // You cannot access remote machines when running on these versions of Windows. // http://msdn.microsoft.com/en-us/library/windows/hardware/ff537948%28v=vs.85%29.aspx SafeCmConnectMachineHandle safeMachineHandle; var lastError = NativeMethods.CM_Connect_Machine(Host.GetUncName(hostName), out safeMachineHandle); NativeMethods.IsValidHandle(safeMachineHandle, lastError); var classGuid = new Guid(Utils.GetEnumDescription(deviceGuid)); // Start at the "Root" of the device tree of the specified machine. using (safeMachineHandle) using (var safeHandle = NativeMethods.SetupDiGetClassDevsEx(ref classGuid, IntPtr.Zero, IntPtr.Zero, NativeMethods.SetupDiGetClassDevsExFlags.Present | NativeMethods.SetupDiGetClassDevsExFlags.DeviceInterface, IntPtr.Zero, hostName, IntPtr.Zero)) { NativeMethods.IsValidHandle(safeHandle, Marshal.GetLastWin32Error()); uint memberInterfaceIndex = 0; var interfaceStructSize = (uint)Marshal.SizeOf(typeof(NativeMethods.SP_DEVICE_INTERFACE_DATA)); var dataStructSize = (uint)Marshal.SizeOf(typeof(NativeMethods.SP_DEVINFO_DATA)); // Start enumerating device interfaces. while (true) { var interfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA { cbSize = interfaceStructSize }; var success = NativeMethods.SetupDiEnumDeviceInterfaces(safeHandle, IntPtr.Zero, ref classGuid, memberInterfaceIndex++, ref interfaceData); lastError = Marshal.GetLastWin32Error(); if (!success) { if (lastError != Win32Errors.NO_ERROR && lastError != Win32Errors.ERROR_NO_MORE_ITEMS) { NativeError.ThrowException(lastError, hostName); } break; } // Create DeviceInfo instance. var diData = new NativeMethods.SP_DEVINFO_DATA { cbSize = dataStructSize }; var deviceInfo = new DeviceInfo(hostName) { DevicePath = GetDeviceInterfaceDetail(safeHandle, ref interfaceData, ref diData).DevicePath }; if (getAllProperties) { deviceInfo.InstanceId = GetDeviceInstanceId(safeMachineHandle, hostName, diData); SetDeviceProperties(safeHandle, deviceInfo, diData); } else { SetMinimalDeviceProperties(safeHandle, deviceInfo, diData); } yield return(deviceInfo); } } }