Releases: purelogiccode/BatchConvertToCHD
Release list
release_3.4.2
Bug Fixes
ToolTip/Popup crash on some Windows systems
Fixed the WPF-internal crash (FileNotFoundException from PopupSecurityHelper.ForceMsaaToUiaBridge) that occurred when a tooltip or popup tried to open on systems where the Windows accessibility bridge (MSAA → UIA) cannot be loaded — e.g. broken/missing UIAutomationCore.dll or third-party accessibility/security software. This was an OS-level condition the application cannot act on: the tooltip simply never appeared. It is now suppressed gracefully instead of being reported as an application crash.
chdman conversion failures now show the real error
When chdman rejected an input file it printed the actual cause before its generic Fatal error occurred: N exit summary — but the app only surfaced the last line. The error picker now skips the exit summary and reports the real cause, so the log tells you why a conversion failed (e.g. an unrecognized track type, a missing bin file, an unsupported format).
chdman fallback extraction
If the built-in CHD reader cannot decode a CHD — a corrupt file or an A/V (laserdisc) CHD (Dragon's Lair, Cliff Hanger, Mach 3, Firefox, Cube Quest, …) — the app now retries automatically with chdman instead of failing with a cryptic Failed to read hunk 0: Chderrdecompressionerror message:
- Disc CHDs fall back to
extractcd/extractdvd/extracthd(cue/bin, iso, img). - Laserdisc CHDs (no CD/DVD/HDD metadata) fall back to
extractld(AVI, MAME 0.285+) orextractraw(raw dump) on older chdman builds.
No more leftover temp files after failed extractions
Failed extractions no longer leave _extract_temp_* debris behind in your output folder. Leftover files are cleaned up automatically (locked files are skipped with a warning).
Quieter, more accurate bug reporting
Known user-data and environment conditions — corrupt files, chdman's own crashes and exit summaries, rate limits — no longer generate bug reports. CHDSharp and PBPSharp extraction failures are still reported, with debug details (file size, disc index/count, numeric error codes): both readers are under active development, and their extraction failures are exactly the signal needed to fix them.
Hardened PBP extraction (PBPSharp)
The built-in PBP (PlayStation EBOOT) reader received a robustness pass:
- Multi-disc header validation — the fixed magic values of the
PSTITLEIMG000000header are now checked, so corrupted/foreign multi-disc PBPs are rejected with a clear error instead of failing later with a vague one. - SFO validation — the SFO metadata magic is verified; a corrupt SFO region now reports
CorruptFileinstead of parsing garbage. - Empty ISO index — discs without ISO data (PSP applications, truncated files) are rejected cleanly instead of crashing with an out-of-range exception.
- Corrupt block lengths — negative/oversized index lengths can no longer crash the reader; they map to proper error codes.
- Read-only contract — the library's package description now states explicitly that it can open and extract PBP files but cannot create or modify them.
Maintenance
- Updated
Meziantou.Analyzerto 3.0.151 (build-time only, no runtime impact).
Tests
- 590 tests, all passing (new tests covering the error-line selection, extraction messages, chdman fallback command building, the refined bug-report filters, and the PBPSharp validation/error paths).
Full Changelog: release_3.4.1...release_3.4.2
release_3.4.1
Meaningful conversion errors
When chdman fails, the application now reports the real error line instead of a progress line. Previously, failures could surface as Failed to convert '...': Compressing, 0.0% complete... (ratio=100.0%) — the actual error (e.g. couldn't find bin file [...]) was buried at the end of chdman's output and is now correctly selected.
Resilient file moves
Moves performed after verification (into Success/Failed folders), during multi-track extraction, and when moving the final CHD into place now retry automatically with backoff (~45 seconds) when the file is briefly locked by antivirus software or the Windows file indexer. Transient locks no longer fail a verification move or abort a disc extraction midway.
Better PBP failure diagnostics
Failed to extract PBP file: <name> reports now include the underlying PBPSharp reason (e.g. Failed to open PBP file: ...), so the real cause is diagnosable instead of a bare filename.
Less bug-report noise
The automatic bug-reporting pipeline no longer treats user-data conditions as application bugs. Corrupt or unopenable CHD files (Not a valid CHD file, Invalid or corrupt data, Cannot open file), partial extractions, and missing referenced files remain visible in the in-app log but are no longer submitted as bug reports.
Cleaner temp-folder fallback
Selected temp root ... is not writable, falling back to system temp is now an informational message — the graceful fallback is expected behavior, not an error, and no longer generates bug reports.
Project wiki
A complete documentation wiki was added under docs/ — 14 pages covering the user guide, architecture, conversion pipeline, extraction & verification, services and utilities references, the bug-reporting system, the embedded libraries (CCDSharp/CSOSharp/PBPSharp), testing, application data, and troubleshooting. The wiki is also deployable to GitHub Pages via a bundled workflow.
🔧 Updates
| Component | From | To |
|---|---|---|
| SharpCompress | 0.50.3 | 0.50.4 |
| Meziantou.Analyzer (build-time) | 3.0.138 | 3.0.141 |
Full Changelog: release_3.4.0...release_3.4.1
release_3.4.0
Fixed: "couldn't find bin file []" — UTF-8 BOM cues now convert
Many cue sheets floating around the web were saved with a UTF-8 BOM (three invisible bytes at the start of the file). chdman's cue parser does not skip the BOM, so it never recognizes the first FILE directive and reports:
ERROR: couldn't find bin file []
…even though every .bin file is sitting right next to the cue. This was the most common conversion failure reported for v3.3.0.
Now: the app detects the BOM, strips it, and hands chdman a clean canonical cue — the conversion succeeds. When the bin files are on the same drive, they are referenced in place via relative paths (no multi-hundred-MB copies to temp). On other drives, the existing safe copy-based path is used.
MP3 audio tracks — cue/bin/mp3 and cue/iso/mp3 sets
chdman cannot read MP3 tracks ("Unhandled track type MP3"), so MP3 audio tracks are now automatically decoded to WAV before conversion:
cue/bin/mp3andcue/iso/mp3sets (common in Neo Geo CD and older PS1 rips) just work — point the app at the cue file.- Decoded WAVs are normalized to
chdman's exact requirements: 44.1 kHz, stereo, 16-bit PCM. Mono or 22.05 kHz MP3 rips (speech-heavy games) are resampled and upmixed automatically — previously those produced WAVschdmanrejects. - Fallback decoder: if Windows Media Foundation is unavailable (e.g. Windows N / Server Core editions), decoding falls back to the built-in ACM MP3 decoder.
- If an MP3 track is corrupt and cannot be decoded, you get a clear, actionable message instead of a confusing
chdmanerror.
Technical note:
chdman's WAVE track support is strict — exactly 44100 Hz, stereo, 16-bit. Any other format is rejected ("unsupported samplerate / only stereo / only 16"). The app guarantees this format for every decoded track.
Smarter archive handling
Cues, GDI and TOC files extracted from .zip/.7z/.rar archives are now validated before conversion. If the referenced data files are missing from the archive (incomplete download, separate bin archive, CRC-skipped entries), the entry is skipped with a clear warning — instead of failing deep inside chdman with a cryptic "couldn't find bin file [path]" error.
Better PBP handling
PBP files that are PSP applications (homebrew EBOOT.PBPs like OpenLara or Newton Voyage — no PlayStation disc image inside) are now detected and skipped with an informative message, instead of a generic "Failed to extract PBP file" error.
🛠️ Also in this release
- 557 automated tests, including end-to-end conversions through the real
chdmanbinary for BOM cues andcue/bin/mp3/cue/iso/mp3sets.
Full Changelog: release_3.3.0...release_3.4.0
release_3.3.0
Highlights
- Non-ASCII cue sheets now convert correctly. Korean, Russian, and Japanese-named game files (e.g.
진설 사무라이 스피리츠 무사도열전.cue,Буря в пустыне-Vermilion Desert.cue) previously failed withcouldn't find bin filebecause the cue text encoding was misdetected. The app now detects the real encoding (UTF-8, Shift-JIS, Korean CP949, Cyrillic CP1251, GBK, Latin-1 and more) by matching referenced file names against the actual files on disk. - MP3 audio tracks are handled automatically. Rips that use MP3 audio tracks (common in Neo Geo CD and older PS1 sets —
Fatal Fury,King of Fighters,Metal Slug,Super Sidekicks,Silent Hilland friends) previously failed withUnhandled track type MP3. The app now decodes MP3 tracks to WAV before conversion using Windows Media Foundation. - bin-only archives convert without a cue. Archives containing only a
.binfile now get an auto-generated single-track cue (MODE2/2352, with an automaticMODE1/2352retry) instead of failing with "No supported primary files found in archive." - Smarter track-name resolution. Referenced files are resolved case-insensitively and zero-padding-tolerantly — a cue referencing
(Track 02).binfinds(Track 2).binon disk and vice versa.
Bug Fixes
CUE / TOC conversion failures ("couldn't find bin file")
- Fixed the biggest failure cluster across all reports: cues whose text was not UTF-8, cues with unquoted/malformed
FILElines, and cues referencing files that differ only by case or zero-padding. - When a cue needs it, the app now builds a self-contained, ASCII-safe working set (canonicalized cue + all referenced files) before handing it to chdman — previously only the
.cuefile was copied, which guaranteed failure for non-ASCII names. - If a conversion still fails with
couldn't find bin file, the log now lists the actual files present in the input folder so the problem is diagnosable at a glance.
MP3 audio track rejection
Unhandled track type MP3failures are gone: MP3 tracks are decoded to 16-bit PCM WAV (NAudio / Media Foundation) and the cue is rewritten before conversion. WAVE and AIFF tracks are untouched (chdman already supports them).
Archives
No supported primary files found in archive.is resolved for bin-only archives (auto-generated cue, see Highlights).- Multi-part RAR archives with a missing volume now show a specific message telling you to download all parts, instead of a generic "corrupted or unsupported format" error.
Disc images
- Non-sector-aligned images (corrupt/truncated
.isofiles) are flagged with a clear early warning. The app no longer waits for a full failed conversion to tell you the file is bad.
File deletion
- "Failed to delete original file" reports are addressed: deletion now retries for up to ~45 seconds with backoff (handles transient locks from antivirus or Explorer), and the read-only attribute is cleared automatically when it blocks deletion.
Diagnostics & reporting
- Disconnected network drives/shares (e.g.
\\NAS\...) now produce a clear "network location unavailable" message instead of a generic file-access error. - Data-side failures (corrupt archives, missing RAR volumes, unavailable network locations, non-sector-aligned images) are no longer sent to the bug-report API — only genuine application errors are reported.
- GitHub rate-limit responses during update checks are handled gracefully and no longer surface as bug reports.
Under the Hood
- Encoding detection engine for cue/toc text: BOM → strict UTF-8 → legacy code pages, filtered to losslessly decodable candidates and scored by filesystem resolution.
- Cue normalization pipeline: canonical UTF-8 rewrite (quoted
FILElines, resolved names, CRLF), used both before conversion and by the dependency validator, so valid cues are no longer rejected by a case-sensitive existence check. - Temporary-directory lifecycle hardening: work directories are guaranteed to be cleaned up on success, cancellation, timeout, and failure paths.
- Retry semantics: deletion retries only on transient lock errors; permanent failures (e.g. access denied) fail fast.
Full Changelog: release_3.2.0...release_3.3.0
release_3.2.0
File System Monitoring
A new input-folder watcher now tracks file deletions, renames, and creations during batch conversion. When a file cannot be found during processing, the log provides contextual diagnostics — telling you whether the file was deleted, renamed, or simply never observed by the monitor. This eliminates guesswork when files disappear mid-batch.
Improved Sector Size Validation
The sector-size integrity check now validates against multiple standard sector sizes (2048, 2324, 2336, 2352) instead of only 2048. Additionally, text-based descriptor files (.cue, .gdi, .toc) are correctly excluded from binary sector alignment checks, preventing false "corrupt file" errors on valid multi-track discs.
Better Error Diagnostics
- Missing
chdman.exeerrors now include a direct download link to the official releases page. - CCDSharp conversion errors for missing
.imgfiles now provide a clear hint about the sidecar file requirement. - Archive extraction "file not found" messages are logged at the appropriate level instead of as warnings.
Bug Report Filtering Refined
The exclusion-pattern list for automated bug reports has been expanded and centralized in BugReportService, preventing noise from expected conditions (missing chdman, corrupt archives, sector-misaligned files, etc.) from flooding the bug report API.
Dependency Updates
- Meziantou.Analyzer:
3.0.125→3.0.136across all projects. - Various test assertions updated to use explicit
StringComparer.Ordinalfor compliance with static analysis rules.
Full Changelog: release_3.1.0...release_3.2.0
release_3.1.0
New Features
Improved CloneCD (.ccd) Support
- Full CloneCD disc image conversion support via the new CCDSharp library
.ccdfiles are now converted to CHD by generating a CUE/BIN pair from the.ccd/.imgset and then passing through chdman- CloneCD files inside archives (
.zip,.7z,.rar) are automatically detected and converted - When processing archives,
.imgfiles that belong to a CloneCD set are no longer independently converted (avoiding duplicate output) - Original
.ccd,.img,.sub, and.cdtfiles are cleaned up when "Delete originals" is enabled
CSOSharp (replaces maxcso.exe)
- CSO/CISO decompression is now handled by the CSOSharp library
- Supports both CSO v1 (deflate/zlib) and CSO v2/ZSO (LZ4) formats
- Removes the
maxcso.exedependency — no more x64-only limitation for CSO files - ARM64 users can now process
.csofiles (previously unavailable)
PBPSharp (replaces psxpackager.exe)
- PBP extraction is now handled by the PBPSharp library
- Supports single-disc and multi-disc PBP files with full SFO metadata parsing
- Generates CUE sheets that match the original psxpackager output
- Removes the
psxpackager.exedependency
Improvements
CHD Conversion
- Non-ASCII file paths (Japanese, Chinese, etc.) are now handled by copying files to a temporary ASCII-safe path before conversion, avoiding chdman encoding issues
- Automatic retry with
createdvdwhen chdman reports "Unrecognized track type" on acreatecdattempt - Added
-us 2352flag for.rawfiles to specify the sector size explicitly - Improved error reporting when chdman exits with a non-zero code but produces a valid output file
- Added file size validation (must be divisible by sector size 2048) before conversion to catch corrupt files early
- Non-ASCII file paths in CUE/GDI/TOC files are now handled with encoding fallback (Shift-JIS, GB2312, Windows-1252)
Robustness
KillChdmanProcessesmethod added to clean up lingering chdman processes when file deletion retries are exhausted- File operation retry count increased from 3 to 5
- Disk space warnings are now logged as informational messages instead of warnings (reducing false bug reports)
- Bug report API sink now filters out informational messages (disk space, rate-limiting, etc.)
- Updated SharpCompress from 0.50.0 to 0.50.1
Code Quality
- Replaced
objectlock fields with the newLocktype for improved thread safety semantics - Replaced
string.Contains()andstring ==comparisons with explicitStringComparison.Ordinalthroughout - Replaced
Task.Run()fire-and-forget patterns with_ = Task.Run()discard to suppress CS4014 warnings - Added
.ConfigureAwait(false)to library-level async calls - Reduced public API surface: many classes and members changed from
publictointernal - Added Meziantou.Analyzer for code analysis
UI
- Simplified status bar: removed MAXCSO and PSXPACKAGER dependency indicators (no longer needed)
- Updated About window links to reference CSOSharp, PBPSharp, and CCDSharp
Bug Fixes
- Fixed PBP magic value validation and SFO offset parsing in PBPSharp
- Fixed CUE/GDI/TOC file reading for non-UTF-8 encodings (added fallback through Shift-JIS, GB2312, Windows-1252)
- Fixed
int.TryParsecall to useCultureInfo.InvariantCulturefor timeout parsing - Fixed
ex.Message.Contains()to useStringComparison.Ordinalfor consistent behavior
Dependencies Removed
| Removed | Replaced By |
|---|---|
maxcso.exe |
CSOSharp library |
psxpackager.exe |
PBPSharp library |
Resources/BASE.PBP, Resources/DATA.PSP, etc. |
No longer needed (PBPSharp handles extraction) |
Full Changelog: release_3.0.0...release_3.1.0
release_3.0.0
What's New in v3.0.0
Major Changes
CHDSharp Integration — No More chdman for Extraction & Verification
CHD verification and extraction now use the CHDSharp library instead of spawning external chdman.exe processes. This means:
- Faster verification — in-process checksum validation (SHA1/MD5) without process overhead
- Faster extraction — direct sector reads via CHDSharp instead of subprocess I/O
- Fewer dependencies —
chdman.exeis now only needed for conversion (creating new CHD files) - Better error messages — precise CHD error codes instead of parsing console output
WPF-UI Modern Theme
The entire UI has been migrated to WPF-UI v4.3.0:
- Mica backdrop — native Windows 11 acrylic effect on the main window and About dialog
- Rounded corners — modern window chrome on Windows 11
- Consistent button styling — Primary, Success, Danger, Info appearances replace hand-rolled templates
- Symbol icons — vector icons replace bitmap PNG images for toolbar buttons
- Dark theme — enforced at startup for a consistent look
- Title bar integration — custom content drawn in the window title bar area
New Features
- Logs button — Opens the AppData logs folder directly from the title bar
- SSL certificate tolerance — Name-mismatch errors (common with proxies/firewalls) are logged as warnings instead of blocking connections
- 7za fallback for ZIP — If the built-in .NET ZIP extractor fails (e.g. Deflate64, LZMA, PPMd compression), the app falls back to
7za.exe - Per-file timeout for PBP extraction — PSXPackager now respects the same timeout limit as CHD conversion
- PSXPackager error capture — stdout/stderr are captured and shown on extraction failure
- Access keys — All buttons now have keyboard shortcuts (Alt+underlined letter)
Improvements
- Thread safety — Stat counters now use
volatileandInterlocked.Increment;SafeFireAndForgetwrapper logs task failures - Bug report sink — Fires on Warning level (was Error-only); uses interlocked flag to prevent API flood
- Path sanitization — Two additional mojibake ellipsis variants detected (Shift-JIS, Windows-1251); names that become all-underscores fall back to a GUID
- Archive error messages — Unsupported compression methods (Deflate64, LZMA, PPMd) now produce clear guidance
- GDI resource cleanup — ScreenshotService properly releases GDI handles in a
finallyblock - File operation retries —
TryDeleteFileAsyncandTryDeleteDirectoryAsyncnow retry up to 3 times - CRC error detection —
IsCrcErrorExceptionchecks both HRESULT and message content - Cancellation awareness — Operation summary uses "canceled" vs "completed" based on actual outcome
- Release notes rendering —
\r\nsequences in GitHub release bodies are now properly converted to newlines - Log directory — Moved from app folder to
%LocalAppData%\BatchConvertToCHD\logs - Mutex ownership — Handles
AbandonedMutexExceptionfrom crashed previous instances - GitHub rate limit detection — Also handles HTTP 429 (Too Many Requests) in addition to 403
Internals & Refactoring
HttpClientinjection —UpdateService,StatsService, andBugReportServiceacceptHttpClientvia constructor for testabilityPbpExtractionResult— Sealed class withinit-only propertyBugReportService.SendBugReportAsync— Made virtual for test mockingArchiveService—ExtractZipWith7ZaFallbackAsyncextracted as a dedicated methodMainWindow.xaml.cs— MonolithicProcessSingleFileForConversionAsyncrefactored into specialized helpers (ProcessCsoFileForConversionAsync,ProcessArchiveFileForConversionAsync,ProcessPbpFileForConversionAsync,ValidateDependentFilesAsync,TryDirectConversionAsync,TryRetryConversionViaTempCopyAsync,HandleConversionResultAsync)- XML documentation added across service classes and models
Updated Dependencies
| Package | Old | New |
|---|---|---|
| CHDSharp | — | 1.2.0 (new) |
| WPF-UI | — | 4.3.0 (new) |
| Microsoft.NET.Test.Sdk | 18.7.0 | 18.8.1 |
SharpCompress 0.50.0, Serilog 4.4.0, xUnit 2.9.3 unchanged.
Breaking Changes
- The
DropShadowEffectglow on the terminal log has been removed.
Full Changelog: release_2.11.0...release_3.0.0
release_2.11.0
Structured Logging (Serilog)
- Integrated Serilog for structured, file-based logging with automatic daily rotation (7-day retention)
- All warnings and errors are now captured in
logs\BatchConvertToCHD-*.logfiles for easier troubleshooting - Added
BugReportApiSinkthat automatically reports Warning+ events to the bug report API
Improved Archive Extraction Resilience
- Zip archives that fail due to file locks are now retried up to 3 times before falling back to a temp copy
- General IOException handling for locked archives now provides clear, actionable error messages instead of crashing
- SharpCompress updated from v0.49.1 to v0.50.0
Enhanced Error Suppression
- Suppressed
OutOfMemoryExceptionfrom WPF'sPresentationCore(DUCE.Channel/HwndTarget) during window resize when system memory is low - Added
COMExceptionhandling for folder browser dialogs to prevent rare crashes on some system configurations
Temp Directory Improvements
- Temp root directories are now validated for write access before use, automatically falling back to system temp if the selected drive is read-only
- Better disk space checks with clear GB-format messages
Robustness Improvements
- Enhanced error logging across all services (Update, Stats, Screenshot, Archive, GameFileParser, PathUtils)
- Screenshot capture is now fully wrapped in error handling and won't crash if GDI calls fail
- All exception handlers now log to file in addition to the in-app log viewer
Full Changelog: release_2.10.0...release_2.11.0
release_2.10.0
Improved: Archive Error Handling
- Corrupt or incomplete archives now show clear, user-friendly error messages with guidance on how to resolve the issue ("re-download or re-copy the file").
- Exit code 2 from
7za.exe(corrupt/invalid archive) is now correctly detected and reported. - Added detection and suppression of bug reports for expected corruption scenarios (CRC errors, incomplete archives, unsupported formats).
- Fixed a thread-safety issue in
ArchiveServicewhere parallel process output lines could collide in the output buffer. Directory.CreateDirectorynow skips the call when the directory already exists — reduces unnecessary filesystem overhead during extraction.- Added
IndexOutOfRangeExceptionas a recognized corruption signal during archive extraction.
Improved: Update Checks
- GitHub server errors (5xx) are now handled gracefully — the update check is skipped without filing a bug report.
- Network-level failures (DNS, SSL) also skip bug reports, since they're environmental, not application bugs.
Improved: Error Reporting
- IO errors during GDI/BIN/CUE file parsing (e.g., device not ready) no longer generate bug reports — these are hardware/environmental issues.
- WPF internal
GlyphTypefacefont rendering errors are now suppressed — caused by system fonts with invalid paths and not actionable by the application.
Changed: UI
- Options panels in all three tabs (Convert, Verify, Extract) are now collapsible expanders, reducing visual clutter.
- Unified color palette — all buttons now use a consistent teal theme, and the log terminal uses white text for improved readability.
- Button text now uses black foreground with a disabled-text fallback via
DataTrigger, ensuring consistent rendering across all button styles.
Internal
Microsoft.NET.Test.Sdkupdated to 18.7.0.- New tests for corrupt archive handling, CRC error detection, update server errors, and exception classifier mutual exclusivity.
Full Changelog: release_2.9.0...release_2.10.0
release_2.9.0
New Features
- 7-Zip fallback extraction for .7z archives — When SharpCompress fails to extract a
.7zfile, the application now automatically retries using the bundled7za.exetool. This improves compatibility with archives that SharpCompress cannot handle. - ARM64 support for 7-Zip — Added
7za_arm64.exefor ARM64 systems, selected automatically on ARM64 processors. - Smarter temporary directory selection — The application now prefers drives that have enough free space for the operation, rather than simply picking the drive with the most total free space. Network drives are also excluded from temp directory selection.
Improvements
- Retry logic for archive extraction — File writes during extraction now retry up to 3 times on transient I/O errors (e.g., network drops).
- Disk space pre-checks before fallback copy — When retrying a failed conversion via a temp directory copy, the application now calculates the required space and verifies the temp drive has enough room before starting the copy.
- Fewer false bug reports — Disk space errors are no longer reported as bugs. The application now detects these and shows a clear message instead.
- Better error messages for invalid archives — Improved detection and reporting of corrupt, incomplete, or unsupported archive files.
- Updated SharpCompress to 0.49.1.
Bug Fixes
- Fixed unreachable error handler for invalid archives — A catch block for
InvalidFormatExceptionwas being shadowed by a generic exception handler and would never execute. Invalid archives now correctly return an "invalid or incomplete" error message.
Full Changelog: release_2.8.0...release_2.9.0