BCUninstaller/Bulk-Crap-Uninstaller · error · IOException
Not a Windows .exe file.
Error message
Not a Windows .exe file.
What it means
Thrown by FilesystemTools.CheckExecutableMachineType(string filename) when filename does not end in ".exe" (case-insensitive, invariant culture). The method reads the PE header at offset 0x3C, which only exists in Windows PE executables; non-.exe files are rejected up front with IOException rather than being misparsed.
Source
Thrown at source/KlocTools/Tools/FilesystemTools.cs:25
using System.IO;
using System.Management;
using System.Runtime.InteropServices;
using Klocman.Extensions;
namespace Klocman.Tools
{
public static class FilesystemTools
{
/// <summary>
/// Check the architecture of the executable. E.g. 64bit.
/// Returns Unknown if the architecture is unsupported or not specified.
/// </summary>
/// <param name="filename">Full path to the executable file.</param>
public static MachineType CheckExecutableMachineType(string filename)
{
if (!filename.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{
throw new IOException("Not a Windows .exe file.");
}
using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
stream.Position = 0x3c;
var fileData = new byte[1024];
var bytesRead = stream.Read(fileData, 0, 1024);
for (var i = 0; i < bytesRead; i++)
{
// Look for the PE signature (PE\0\0)
if (i + 5 >= bytesRead) break;
if (fileData[i] != 0x50) continue;
if (fileData[i + 1] != 0x45 || fileData[i + 2] != 0 || fileData[i + 3] != 0) continue;
// Join two bytes representing the architecture
var machineId = fileData[i + 5] << 8 | fileData[i + 4];View on GitHub (pinned to 608321de98)
Solutions
- Verify the extension is .exe before calling, or branch to a DLL-aware PE reader if you need DLL support.
- Validate user input at the UI layer and restrict the open dialog filter to *.exe.
- If you genuinely need machine type for a DLL, copy/extend the PE-parsing logic without the extension gate.
Example fix
// before
var mt = FilesystemTools.CheckExecutableMachineType(path); // path may be .dll
// after
if (!path.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
return MachineType.Unknown;
var mt = FilesystemTools.CheckExecutableMachineType(path); Defensive patterns
Strategy: validation
Validate before calling
if (!filename.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
return MachineType.Unknown;
var mt = FilesystemTools.CheckExecutableMachineType(filename); Type guard
static bool IsExePath(string path)
=> path != null && path.EndsWith(".exe", StringComparison.OrdinalIgnoreCase); Try / catch
try { return FilesystemTools.CheckExecutableMachineType(path); }
catch (IOException) { return MachineType.Unknown; } Prevention
- Restrict file pickers to *.exe when architecture detection is required.
- Confirm the extension before invoking rather than relying on the throw.
- If DLL support is needed, implement a dedicated PE reader without the extension gate.
When it happens
Trigger: Calling CheckExecutableMachineType with a path whose extension is not .exe — e.g. a .dll, .com, .scr, or a path with no extension. Note: .dll files DO contain PE headers but are still rejected because of this guard.
Common situations: User-selected file that is actually a DLL or a shortcut, file with no extension, path computed from a string that lost its extension, or assuming the tool works on any PE image.
Related errors
- Path does not point to a valid .reg file
- Win32_Directory.Compress returned {ret}
- Process name can't be null or empty
- Path is too short/invalid
- Minimum value must be lower than or equal to the maximum val
AI-assisted analysis of BCUninstaller/Bulk-Crap-Uninstaller@608321de98 (2026-08-13).
Data as JSON: /api/errors/bf05e6badde96226.
Report an issue: GitHub.