/// <summary> /// Get the current media type from drive letter /// </summary> /// <param name="drive"></param> /// <returns></returns> /// <remarks> /// This may eventually be replaced by Aaru.Devices being able to be about 10x more accurate. /// This will also end up making it so that IMAPI2 is no longer necessary. Unfortunately, that /// will only work for .NET Core 3.1 and beyond. /// </remarks> public static (MediaType?, string) GetMediaType(Drive drive) { // Take care of the non-optical stuff first // TODO: See if any of these can be more granular, like Optical is if (drive.InternalDriveType == InternalDriveType.Floppy) { return(MediaType.FloppyDisk, null); } else if (drive.InternalDriveType == InternalDriveType.HardDisk) { return(MediaType.HardDisk, null); } else if (drive.InternalDriveType == InternalDriveType.Removable) { return(MediaType.FlashDrive, null); } // Get the current drive information string deviceId = null; bool loaded = false; try { // Get the device ID first var searcher = new ManagementObjectSearcher( "root\\CIMV2", $"SELECT * FROM Win32_CDROMDrive WHERE Id = '{drive.Letter}:\'"); foreach (ManagementObject queryObj in searcher.Get()) { deviceId = (string)queryObj["DeviceID"]; loaded = (bool)queryObj["MediaLoaded"]; } // If we got no valid device, we don't care and just return if (deviceId == null) { return(null, "Device could not be found"); } else if (!loaded) { return(null, "Device is not reporting media loaded"); } #if NET_FRAMEWORK MsftDiscMaster2 discMaster = new MsftDiscMaster2(); deviceId = deviceId.ToLower().Replace('\\', '#').Replace('/', '#'); string id = null; foreach (var disc in discMaster) { if (disc.ToString().Contains(deviceId)) { id = disc.ToString(); } } // If we couldn't find the drive, we don't care and return if (id == null) { return(null, "Device ID could not be found"); } // Create the required objects for reading from the drive MsftDiscRecorder2 recorder = new MsftDiscRecorder2(); recorder.InitializeDiscRecorder(id); MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data(); // If the recorder is not supported, just return if (!dataWriter.IsRecorderSupported(recorder)) { return(null, "IMAPI2 recorder not supported"); } // Otherwise, set the recorder to get information from dataWriter.Recorder = recorder; var media = dataWriter.CurrentPhysicalMediaType; return(media.IMAPIToMediaType(), null); #else // TODO: This entire .NET Core path still doesn't work // This may honestly require an entire import of IMAPI2 stuff and then try // as best as possible to get it working. return(null, "Media detection only supported on .NET Framework"); #endif } catch (Exception ex) { return(null, ex.Message); } }
/// <summary> /// Get the current system from drive /// </summary> /// <param name="drive"></param> /// <param name="defaultValue"></param> /// <returns></returns> public static KnownSystem?GetKnownSystem(Drive drive, KnownSystem?defaultValue) { // If drive or drive letter are provided, we can't do anything if (drive?.Letter == null) { return(defaultValue); } string drivePath = $"{drive.Letter}:\\"; // If we can't read the media in that drive, we can't do anything if (!Directory.Exists(drivePath)) { return(defaultValue); } // We're going to assume for floppies, HDDs, and removable drives // TODO: Try to be smarter about this if (drive.InternalDriveType != InternalDriveType.Optical) { return(KnownSystem.IBMPCCompatible); } // Audio CD if (drive.VolumeLabel.Equals("Audio CD", StringComparison.OrdinalIgnoreCase)) { return(KnownSystem.AudioCD); } // DVD-Audio if (Directory.Exists(Path.Combine(drivePath, "AUDIO_TS")) && Directory.EnumerateFiles(Path.Combine(drivePath, "AUDIO_TS")).Count() > 0) { return(KnownSystem.DVDAudio); } // DVD-Video and Xbox if (Directory.Exists(Path.Combine(drivePath, "VIDEO_TS")) && Directory.EnumerateFiles(Path.Combine(drivePath, "VIDEO_TS")).Count() > 0) { // TODO: Maybe add video track hashes to compare for Xbox and X360? if (string.Equals(drive.VolumeLabel, "SEP13011042072", StringComparison.OrdinalIgnoreCase)) { return(KnownSystem.MicrosoftXBOX); } return(KnownSystem.DVDVideo); } // HD-DVD-Video if (Directory.Exists(Path.Combine(drivePath, "HVDVD_TS")) && Directory.EnumerateFiles(Path.Combine(drivePath, "HVDVD_TS")).Count() > 0) { return(KnownSystem.HDDVDVideo); } // Sega Dreamcast if (File.Exists(Path.Combine(drivePath, "IP.BIN"))) { return(KnownSystem.SegaDreamcast); } // Sega Mega-CD / Sega-CD if (File.Exists(Path.Combine(drivePath, "_BOOT", "IP.BIN")) || File.Exists(Path.Combine(drivePath, "_BOOT", "SP.BIN")) || File.Exists(Path.Combine(drivePath, "_BOOT", "SP_AS.BIN")) || File.Exists(Path.Combine(drivePath, "FILESYSTEM.BIN"))) { return(KnownSystem.SegaCDMegaCD); } // Sega Saturn try { byte[] sector = drive?.ReadSector(0); if (sector != null) { if (sector.StartsWith(Interface.SaturnSectorZeroStart)) { return(KnownSystem.SegaSaturn); } } } catch { } // Sony PlayStation and Sony PlayStation 2 string psxExePath = Path.Combine(drivePath, "PSX.EXE"); string systemCnfPath = Path.Combine(drivePath, "SYSTEM.CNF"); if (File.Exists(systemCnfPath)) { // Check for either BOOT or BOOT2 var systemCnf = new IniFile(systemCnfPath); if (systemCnf.ContainsKey("BOOT")) { return(KnownSystem.SonyPlayStation); } else if (systemCnf.ContainsKey("BOOT2")) { return(KnownSystem.SonyPlayStation2); } } else if (File.Exists(psxExePath)) { return(KnownSystem.SonyPlayStation); } // Sony PlayStation 4 if (drive.VolumeLabel.Equals("PS4VOLUME", StringComparison.OrdinalIgnoreCase)) { return(KnownSystem.SonyPlayStation4); } // Sony PlayStation 5 if (drive.VolumeLabel.Equals("PS5VOLUME", StringComparison.OrdinalIgnoreCase)) { return(KnownSystem.SonyPlayStation5); } // V.Tech V.Flash / V.Smile Pro if (File.Exists(Path.Combine(drivePath, "0SYSTEM"))) { return(KnownSystem.VTechVFlashVSmilePro); } // VCD if (Directory.Exists(Path.Combine(drivePath, "VCD")) && Directory.EnumerateFiles(Path.Combine(drivePath, "VCD")).Count() > 0) { return(KnownSystem.VideoCD); } // Default return return(defaultValue); }
/// <summary> /// Get the current media type from drive letter /// </summary> /// <param name="drive"></param> /// <returns></returns> /// <remarks> /// https://stackoverflow.com/questions/11420365/detecting-if-disc-is-in-dvd-drive /// </remarks> public static MediaType?GetMediaType(Drive drive) { // Take care of the non-optical stuff first // TODO: See if any of these can be more granular, like Optical is if (drive.InternalDriveType == InternalDriveType.Floppy) { return(MediaType.FloppyDisk); } else if (drive.InternalDriveType == InternalDriveType.HardDisk) { return(MediaType.HardDisk); } else if (drive.InternalDriveType == InternalDriveType.Removable) { return(MediaType.FlashDrive); } // Get the DeviceID and MediaType from the current drive letter string deviceId = null; int mediaType = 0; try { // Get the device ID first var searcher = new ManagementObjectSearcher( "root\\CIMV2", $"SELECT * FROM Win32_CDROMDrive WHERE Id = '{drive.Letter}:\'"); foreach (ManagementObject queryObj in searcher.Get()) { deviceId = (string)queryObj["DeviceID"]; #region Possibly useful fields //foreach (var property in queryObj.Properties) //{ // Console.WriteLine(property); //} //// Capabilities list //ushort?[] capabilities = (ushort?[])queryObj["Capabilities"]; //// Internal name of the device //string caption = (string)queryObj["Caption"]; //// Flags for the file system, see FileSystemFlags //uint? fileSystemFlagsEx = (uint?)queryObj["FileSystemFlagsEx"]; //// "CD Writer" doesn't fit https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-cdromdrive //string mediaTypeString = (string)queryObj["MediaType"]; //// Internal name of the device (Seems like a duplicate of Caption) //string name = (string)queryObj["Name"]; //// Full device ID for the drive (Seems like duplicate of DeviceID) //string pnpDeviceId = (string)queryObj["PNPDeviceId"]; //// Size of the loaded media (extrapolate disc type from this?) //ulong? size = (ulong?)queryObj["Size"]; #endregion } // If we got no valid device, we don't care and just return if (deviceId == null) { return(null); } #if NET_FRAMEWORK MsftDiscMaster2 discMaster = new MsftDiscMaster2(); deviceId = deviceId.ToLower().Replace('\\', '#'); string id = null; foreach (var disc in discMaster) { if (disc.ToString().Contains(deviceId)) { id = disc.ToString(); } } // If we couldn't find the drive, we don't care and return if (id == null) { return(null); } // Otherwise, we get the media type, if any MsftDiscRecorder2 recorder = new MsftDiscRecorder2(); recorder.InitializeDiscRecorder(id); MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data(); dataWriter.Recorder = recorder; var media = dataWriter.CurrentPhysicalMediaType; if (media != IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_UNKNOWN) { return(media.IMAPIToMediaType()); } return(null); #else // TODO: This entire .NET Core path still doesn't work // This may honestly require an entire import of IMAPI2 stuff and then try // as best as possible to get it working. // Now try to get the physical media associated searcher = new ManagementObjectSearcher( "root\\CIMV2", $"SELECT * FROM Win32_PhysicalMedia"); foreach (ManagementObject queryObj in searcher.Get()) { foreach (var property in queryObj.Properties) { Console.WriteLine(property); } mediaType = (int)(queryObj["MediaType"] ?? 0); } return(((PhysicalMediaType)mediaType).ToMediaType()); #endif } catch { // We don't care what the error was return(null); } }