Compare commits

...

4 Commits
1.14 ... 1.15

Author SHA1 Message Date
Matt Nadareski
fbc9d04782 Advanced Support (#172)
* Who doesn't like drives?

* Add another TODO

* Use built in stuff, it's quicker

* More special handling for floppies, easier this time

* Fix broken test

* Set active drive priority, String -> string

* Track reason for no scanning

* Update DIC version and release notes
2019-11-17 01:06:41 -05:00
Matt Nadareski
24b08dd245 Update BurnOutSharp 2019-10-25 20:37:08 -07:00
Matt Nadareski
c7ebe69b05 Update BurnOutSharp 2019-10-24 13:25:28 -07:00
Matt Nadareski
22ffda4b5a Fix copy protection scan by preferring 32-bit 2019-10-19 02:42:01 -07:00
18 changed files with 184 additions and 111 deletions

View File

@@ -1,3 +1,9 @@
### 1.15 (2019-11-16)
- Updated to DIC version 20191116
- Support non-optical, non-floppy stuff better
- Update protection scanning and fix some things
### 1.14 (2019-10-01)
- Updated to DIC version 20191001

View File

@@ -4,6 +4,7 @@
<TargetFrameworks>net462;net472;netcoreapp3.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputType>Exe</OutputType>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>

View File

@@ -5,12 +5,6 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Content Include="mspack.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<COMReference Include="IMAPI2">
@@ -34,13 +28,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BurnOutSharp" Version="1.3.8" />
<PackageReference Include="LessIO" Version="0.6.16" />
<PackageReference Include="libmspack4n" Version="0.9.10" />
<PackageReference Include="BurnOutSharp" Version="1.3.8.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="System.Management" Version="4.6.0" />
<PackageReference Include="UnshieldSharp" Version="1.4.2.3" />
<PackageReference Include="zlib.net" Version="1.0.4" />
</ItemGroup>
<ItemGroup>

View File

@@ -84,6 +84,17 @@
VideoNowColor,
}
/// <summary>
/// Drive type for dumping
/// </summary>
public enum InternalDriveType
{
Optical,
Floppy,
HardDisk,
Removable,
}
/// <summary>
/// Dump status for Redump
/// </summary>
@@ -419,6 +430,10 @@
// Unsorted Formats
Cartridge,
CED,
CompactFlash,
MMC,
SDCard,
FlashDrive,
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using System;
using System.IO;
using IMAPI2;
using DICUI.Data;
using Newtonsoft.Json;
@@ -10,6 +11,26 @@ namespace DICUI.Utilities
{
#region Cross-enumeration conversions
/// <summary>
/// Convert drive type to internal version, if possible
/// </summary>
/// <param name="driveType">DriveType value to check</param>
/// <returns>InternalDriveType, if possible, null on error</returns>
public static InternalDriveType? ToInternalDriveType(this DriveType driveType)
{
switch(driveType)
{
case DriveType.CDRom:
return InternalDriveType.Optical;
case DriveType.Fixed:
return InternalDriveType.HardDisk;
case DriveType.Removable:
return InternalDriveType.Removable;
default:
return null;
}
}
/// <summary>
/// Get the most common known system for a given MediaType
/// </summary>
@@ -452,6 +473,11 @@ namespace DICUI.Utilities
case MediaType.CDROM:
case MediaType.GDROM:
case MediaType.Cartridge:
case MediaType.HardDisk:
case MediaType.CompactFlash:
case MediaType.MMC:
case MediaType.SDCard:
case MediaType.FlashDrive:
return ".bin";
case MediaType.DVD:
case MediaType.HDDVD:

View File

@@ -1,4 +1,7 @@
namespace DICUI.Utilities
using System.IO;
using DICUI.Data;
namespace DICUI.Utilities
{
/// <summary>
/// Represents information for a single drive
@@ -6,47 +9,55 @@
public class Drive
{
/// <summary>
/// Windows drive letter
/// Represents drive type
/// </summary>
public char Letter { get; private set; }
public InternalDriveType? InternalDriveType { get; set; }
/// <summary>
/// Represents if it is a floppy drive
/// DriveInfo object representing the drive, if possible
/// </summary>
public bool IsFloppy { get; private set; }
public DriveInfo DriveInfo { get; private set; }
/// <summary>
/// Windows drive letter
/// </summary>
public char Letter { get { return DriveInfo?.Name[0] ?? '\0'; } }
/// <summary>
/// Media label as read by Windows
/// </summary>
public string VolumeLabel { get; private set; }
public string VolumeLabel
{
get
{
if (DriveInfo.IsReady)
{
if (string.IsNullOrWhiteSpace(DriveInfo.VolumeLabel))
return "track";
else
return DriveInfo.VolumeLabel;
}
else
{
return Template.DiscNotDetected;
}
}
}
/// <summary>
/// Drive partition format
/// </summary>
public string DriveFormat { get { return DriveInfo.DriveFormat; } }
/// <summary>
/// Represents if Windows has marked the drive as active
/// </summary>
public bool MarkedActive { get; private set; }
public bool MarkedActive { get { return DriveInfo.IsReady; } }
private Drive(char letter, string volumeLabel, bool isFloppy, bool markedActive)
public Drive(InternalDriveType? driveType, DriveInfo driveInfo)
{
this.Letter = letter;
this.IsFloppy = isFloppy;
this.VolumeLabel = volumeLabel;
this.MarkedActive = markedActive;
this.InternalDriveType = driveType;
this.DriveInfo = driveInfo;
}
/// <summary>
/// Create a new Floppy drive instance
/// </summary>
/// <param name="letter">Drive letter to use</param>
/// <returns>Drive object for a Floppy drive</returns>
public static Drive Floppy(char letter) => new Drive(letter, null, true, true);
/// <summary>
/// Create a new Optical drive instance
/// </summary>
/// <param name="letter">Drive letter to use</param>
/// <param name="volumeLabel">Media label, if it exists</param>
/// <param name="active">True if the drive is marked active, false otherwise</param>
/// <returns>Drive object for an Optical drive</returns>
public static Drive Optical(char letter, string volumeLabel, bool active) => new Drive(letter, volumeLabel, false, active);
}
}

View File

@@ -204,8 +204,8 @@ namespace DICUI.Utilities
CancelDumping();
// Validate we're not trying to eject a floppy disk
if (Drive.IsFloppy)
// Validate we're not trying to eject a non-optical
if (Drive.InternalDriveType != InternalDriveType.Optical)
return;
Process childProcess;
@@ -467,7 +467,10 @@ namespace DICUI.Utilities
/// <returns>True if the configuration is valid, false otherwise</returns>
internal bool ParametersValid()
{
return DICParameters.IsValid() && !(Drive.IsFloppy ^ Type == MediaType.FloppyDisk);
return DICParameters.IsValid()
&& !(Drive.InternalDriveType == InternalDriveType.Floppy ^ Type == MediaType.FloppyDisk)
&& !(Drive.InternalDriveType == InternalDriveType.HardDisk ^ Type == MediaType.HardDisk)
&& !(Drive.InternalDriveType == InternalDriveType.Removable ^ (Type == MediaType.CompactFlash || Type == MediaType.SDCard || Type == MediaType.FlashDrive));
}
#endregion
@@ -676,7 +679,7 @@ namespace DICUI.Utilities
layerbreak = (info.SizeAndChecksums.Size > 25025314816 ? "25025314816" : null);
// If we have a single-layer disc
if (String.IsNullOrWhiteSpace(layerbreak))
if (string.IsNullOrWhiteSpace(layerbreak))
{
info.CommonDiscInfo.MasteringRingFirstLayerDataSide = (AddPlaceholders ? Template.RequiredIfExistsValue : "");
info.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide = (AddPlaceholders ? Template.RequiredIfExistsValue : "");
@@ -733,7 +736,7 @@ namespace DICUI.Utilities
info.VersionAndEditions.Version = umdversion ?? "";
info.SizeAndChecksums.Size = umdsize;
if (!String.IsNullOrWhiteSpace(umdlayer))
if (!string.IsNullOrWhiteSpace(umdlayer))
info.SizeAndChecksums.Layerbreak = Int64.Parse(umdlayer ?? "-1");
}
@@ -1237,6 +1240,8 @@ namespace DICUI.Utilities
if (!File.Exists(DICPath))
return Result.Failure("Error! Could not find DiscImageCreator!");
// TODO: Ensure output path not the same as input drive OR DIC/DICUI location
return Result.Success();
}
@@ -1459,17 +1464,17 @@ namespace DICUI.Utilities
// Now we format everything we can
string protection = "";
if (!String.IsNullOrEmpty(region))
if (!string.IsNullOrEmpty(region))
protection += $"Region: {region}\n";
if (!String.IsNullOrEmpty(rceProtection))
if (!string.IsNullOrEmpty(rceProtection))
protection += $"RCE Protection: {rceProtection}\n";
if (!String.IsNullOrEmpty(copyrightProtectionSystemType))
if (!string.IsNullOrEmpty(copyrightProtectionSystemType))
protection += $"Copyright Protection System Type: {copyrightProtectionSystemType}\n";
if (!String.IsNullOrEmpty(encryptedDiscKey))
if (!string.IsNullOrEmpty(encryptedDiscKey))
protection += $"Encrypted Disc Key: {encryptedDiscKey}\n";
if (!String.IsNullOrEmpty(playerKey))
if (!string.IsNullOrEmpty(playerKey))
protection += $"Player Key: {playerKey}\n";
if (!String.IsNullOrEmpty(decryptedDiscKey))
if (!string.IsNullOrEmpty(decryptedDiscKey))
protection += $"Decrypted Disc Key: {decryptedDiscKey}\n";
return protection;
@@ -1897,7 +1902,7 @@ namespace DICUI.Utilities
serial = null; date = null;
// If the input header is null, we can't do a thing
if (String.IsNullOrWhiteSpace(segaHeader))
if (string.IsNullOrWhiteSpace(segaHeader))
return false;
// Now read it in cutting it into lines for easier parsing
@@ -1980,7 +1985,7 @@ namespace DICUI.Utilities
serial = null; version = null; date = null;
// If the input header is null, we can't do a thing
if (String.IsNullOrWhiteSpace(segaHeader))
if (string.IsNullOrWhiteSpace(segaHeader))
return false;
// Now read it in cutting it into lines for easier parsing

View File

@@ -459,8 +459,10 @@ namespace DICUI.Utilities
}
// Force Unit Access
if (Command == DICCommand.BluRay
if (Command == DICCommand.Audio
|| Command == DICCommand.BluRay
|| Command == DICCommand.CompactDisc
|| Command == DICCommand.Data
|| Command == DICCommand.DigitalVideoDisc
|| Command == DICCommand.Swap
|| Command == DICCommand.XBOX)
@@ -700,7 +702,7 @@ namespace DICUI.Utilities
private bool ValidateAndSetParameters(string parameters)
{
// The string has to be valid by itself first
if (String.IsNullOrWhiteSpace(parameters))
if (string.IsNullOrWhiteSpace(parameters))
return false;
// Now split the string into parts for easier validation
@@ -1209,12 +1211,12 @@ namespace DICUI.Utilities
case DICFlagStrings.ForceUnitAccess:
if (parts[0] != DICCommandStrings.Audio
&& parts[0] != DICCommandStrings.BluRay
&& parts[0] != DICCommandStrings.CompactDisc
&& parts[0] != DICCommandStrings.DigitalVideoDisc
&& parts[0] != DICCommandStrings.Data
&& parts[0] != DICCommandStrings.GDROM
&& parts[0] != DICCommandStrings.XBOX)
&& parts[0] != DICCommandStrings.BluRay
&& parts[0] != DICCommandStrings.CompactDisc
&& parts[0] != DICCommandStrings.DigitalVideoDisc
&& parts[0] != DICCommandStrings.Data
&& parts[0] != DICCommandStrings.GDROM
&& parts[0] != DICCommandStrings.XBOX)
return false;
else if (!DoesExist(parts, i + 1))
{

View File

@@ -236,6 +236,7 @@ namespace DICUI.Utilities
types.Add(MediaType.CDROM);
types.Add(MediaType.DVD);
types.Add(MediaType.FloppyDisk);
types.Add(MediaType.HardDisk);
break;
// https://en.wikipedia.org/wiki/Amiga
@@ -254,6 +255,7 @@ namespace DICUI.Utilities
types.Add(MediaType.CDROM);
types.Add(MediaType.DVD);
types.Add(MediaType.FloppyDisk);
types.Add(MediaType.HardDisk);
break;
// https://en.wikipedia.org/wiki/PC-8800_series
@@ -700,9 +702,13 @@ namespace DICUI.Utilities
/// </remarks>
public static List<Drive> CreateListOfDrives()
{
var drives = new List<Drive>();
// Get all supported drive types
var drives = DriveInfo.GetDrives()
.Where(d => d.DriveType == DriveType.CDRom || d.DriveType == DriveType.Fixed || d.DriveType == DriveType.Removable)
.Select(d => new Drive(Converters.ToInternalDriveType(d.DriveType), d))
.ToList();
// Get the floppy drives
// Get the floppy drives and set the flag from removable
try
{
ManagementObjectSearcher searcher =
@@ -716,7 +722,7 @@ namespace DICUI.Utilities
if (mediaType != null && ((mediaType > 0 && mediaType < 11) || (mediaType > 12 && mediaType < 22)))
{
char devId = queryObj["DeviceID"].ToString()[0];
drives.Add(Drive.Floppy(devId));
drives.ForEach(d => { if (d.Letter == devId) { d.InternalDriveType = InternalDriveType.Floppy; } });
}
}
}
@@ -725,14 +731,7 @@ namespace DICUI.Utilities
// No-op
}
// Get the optical disc drives
List<Drive> discDrives = DriveInfo.GetDrives()
.Where(d => d.DriveType == DriveType.CDRom)
.Select(d => Drive.Optical(d.Name[0], (d.IsReady ? (string.IsNullOrWhiteSpace(d.VolumeLabel) ? "disc" : d.VolumeLabel) : Template.DiscNotDetected), d.IsReady))
.ToList();
// Add the two lists together and order
drives.AddRange(discDrives);
// Order the drives by drive letter
drives = drives.OrderBy(i => i.Letter).ToList();
return drives;
@@ -741,20 +740,29 @@ namespace DICUI.Utilities
/// <summary>
/// Get the current media type from drive letter
/// </summary>
/// <param name="driveLetter"></param>
/// <param name="drive"></param>
/// <returns></returns>
/// <remarks>
/// https://stackoverflow.com/questions/11420365/detecting-if-disc-is-in-dvd-drive
/// </remarks>
public static MediaType? GetMediaType(char? driveLetter)
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 from the current drive letter
string deviceId = null;
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + driveLetter + ":\'");
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + drive.Letter + ":\'");
var collection = searcher.Get();
foreach (ManagementObject queryObj in collection)
@@ -820,6 +828,11 @@ namespace DICUI.Utilities
if (!Directory.Exists(drivePath))
return null;
// 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;
// Sega Dreamcast
if (File.Exists(Path.Combine(drivePath, "IP.BIN")))
{
@@ -888,6 +901,10 @@ namespace DICUI.Utilities
case MediaType.CDROM:
case MediaType.DVD:
case MediaType.FloppyDisk:
case MediaType.HardDisk:
case MediaType.CompactFlash:
case MediaType.SDCard:
case MediaType.FlashDrive:
case MediaType.HDDVD:
return Result.Success("{0} ready to dump", type.LongName());
@@ -930,9 +947,9 @@ namespace DICUI.Utilities
return string.Join("\n", found.Select(kvp => kvp.Key + ": " + kvp.Value).ToArray());
}
catch
catch (Exception ex)
{
return "Path could not be scanned!";
return $"Path could not be scanned! {ex}";
}
}
}

View File

@@ -27,7 +27,7 @@ namespace DICUI.Web
public string GetLastFilename()
{
// Try to extract the filename from the Content-Disposition header
if (!String.IsNullOrEmpty(this.ResponseHeaders["Content-Disposition"]))
if (!string.IsNullOrEmpty(this.ResponseHeaders["Content-Disposition"]))
return this.ResponseHeaders["Content-Disposition"].Substring(this.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 9).Replace("\"", "");
return null;

Binary file not shown.

View File

@@ -1,15 +0,0 @@
using DICUI.Utilities;
using Xunit;
namespace DICUI.Test.Utilities
{
public class DriveTest
{
[Fact]
public void DriveConstructorsTest()
{
Assert.True(Drive.Floppy('a').IsFloppy);
Assert.False(Drive.Optical('d', "test", true).IsFloppy);
}
}
}

View File

@@ -1,4 +1,5 @@
using DICUI.Data;
using System.IO;
using DICUI.Data;
using DICUI.Utilities;
using Xunit;
@@ -18,7 +19,9 @@ namespace DICUI.Test
var env = new DumpEnvironment
{
DICParameters = new Parameters(parameters),
Drive = isFloppy ? Drive.Floppy(letter) : Drive.Optical(letter, "", true),
Drive = isFloppy
? new Drive(InternalDriveType.Floppy, new DriveInfo(letter.ToString()))
: new Drive(InternalDriveType.Optical, new DriveInfo(letter.ToString())),
Type = mediaType,
};

View File

@@ -6,6 +6,7 @@
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<Prefer32Bit>true</Prefer32Bit>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>

View File

@@ -51,8 +51,8 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.13")]
[assembly: AssemblyFileVersion("1.13.0.0")]
[assembly: AssemblyVersion("1.15")]
[assembly: AssemblyFileVersion("1.15.0.0")]
// Anything marked as internal can be used by the test methods
[assembly: InternalsVisibleTo("DICUI.Test")]

View File

@@ -192,12 +192,12 @@ namespace DICUI.Windows
// this is used to optimize the work since we need to process A LOT of text
struct Matcher
{
private readonly String prefix;
private readonly string prefix;
private readonly Regex regex;
private readonly int start;
private readonly Action<Match> lambda;
public Matcher(String prefix, String regex, Action<Match> lambda)
public Matcher(string prefix, string regex, Action<Match> lambda)
{
this.prefix = prefix;
this.regex = new Regex(regex);

View File

@@ -332,12 +332,23 @@ namespace DICUI.Windows
if (DriveLetterComboBox.Items.Count > 0)
{
int index = _drives.FindIndex(d => d.MarkedActive);
// Check for active optical drives first
int index = _drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Optical);
// Then we check for floppy drives
if (index == -1)
index = _drives.FindIndex(d => d.MarkedActive && d.InternalDriveType == InternalDriveType.Floppy);
// Then we try all other drive types
if (index == -1)
index = _drives.FindIndex(d => d.MarkedActive);
// Set the selected index
DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0);
StatusLabel.Content = "Valid drive found! Choose your Media Type";
CopyProtectScanButton.IsEnabled = true;
// Get the current optical disc type
// Get the current media type
if (!_options.SkipSystemDetection && index != -1)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect system for drive {0}.. ", _drives[index].Letter);
@@ -354,7 +365,7 @@ namespace DICUI.Windows
// Only enable the start/stop if we don't have the default selected
StartStopButton.IsEnabled = (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem) != KnownSystem.NONE;
ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", _drives.Count, String.Join(", ", _drives.Select(d => d.Letter)));
ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", _drives.Count, string.Join(", ", _drives.Select(d => d.Letter)));
}
else
{
@@ -679,14 +690,14 @@ namespace DICUI.Windows
{
// Get the drive letter from the selected item
Drive drive = DriveLetterComboBox.SelectedItem as Drive;
if (drive == null || drive.IsFloppy)
if (drive == null)
return;
// Get the current optical disc type
// Get the current media type
if (!_options.SkipMediaTypeDetection)
{
ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter);
_currentMediaType = Validators.GetMediaType(drive.Letter);
_currentMediaType = Validators.GetMediaType(drive);
ViewModels.LoggerViewModel.VerboseLogLn(_currentMediaType == null ? "unable to detect." : ("detected " + _currentMediaType.LongName() + "."));
}
}
@@ -728,11 +739,11 @@ namespace DICUI.Windows
string trimmedPath = _env.DICParameters.Filename?.Trim('"') ?? string.Empty;
string outputDirectory = Path.GetDirectoryName(trimmedPath);
string outputFilename = Path.GetFileName(trimmedPath);
if (!String.IsNullOrWhiteSpace(outputDirectory))
if (!string.IsNullOrWhiteSpace(outputDirectory))
OutputDirectoryTextBox.Text = outputDirectory;
else
outputDirectory = OutputDirectoryTextBox.Text;
if (!String.IsNullOrWhiteSpace(outputFilename))
if (!string.IsNullOrWhiteSpace(outputFilename))
OutputFilenameTextBox.Text = outputFilename;
else
outputFilename = OutputFilenameTextBox.Text;

View File

@@ -1,5 +1,5 @@
# version format
version: 1.14-{build}
version: 1.15-{build}
# pull request template
pull_requests:
@@ -32,11 +32,11 @@ build:
# post-build step
after_build:
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/3674664/DiscImageCreator_20191001.zip
- ps: appveyor DownloadFile https://github.com/saramibreak/DiscImageCreator/files/3854216/DiscImageCreator_20191116.zip
- ps: appveyor DownloadFile https://archive.org/download/subdump_fua_0x28/subdump_fua_0x28.zip
- 7z e DiscImageCreator_20191001.zip -oDICUI\bin\Debug\net462\Programs Release_ANSI\*
- 7z e DiscImageCreator_20191001.zip -oDICUI\bin\Debug\net472\Programs Release_ANSI\*
- 7z e DiscImageCreator_20191001.zip -oDICUI\bin\Debug\netcoreapp3.0\Programs Release_ANSI\*
- 7z e DiscImageCreator_20191116.zip -oDICUI\bin\Debug\net462\Programs Release_ANSI\*
- 7z e DiscImageCreator_20191116.zip -oDICUI\bin\Debug\net472\Programs Release_ANSI\*
- 7z e DiscImageCreator_20191116.zip -oDICUI\bin\Debug\netcoreapp3.0\Programs Release_ANSI\*
- 7z e subdump_fua_0x28.zip -oDICUI\bin\Debug\net462 *
- mv DICUI\bin\Debug\net462\subdump_fua_0x28.exe DICUI\bin\Debug\net462\subdump.exe
- 7z e subdump_fua_0x28.zip -oDICUI\bin\Debug\net472 *