stride3d/stride · error · DirectoryNotFoundException

Could not locate "Program Files" folder.

Error message

Could not locate "Program Files" folder.

What it means

Thrown by WinPixNative.LoadPixGpuCapturer (via GetLatestWinPixGpuCapturerPath) when Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) returns an empty string, so the PIX GPU capturer DLL cannot be located. This only runs on the PIX GPU-capture path, typically in debug builds.

Solutions

  1. Ensure the application runs on Windows with the standard Program Files folder available (SYSTEMDRIVE\Program Files / %ProgramFiles%).
  2. Disable PIX GPU capture (remove the capture trigger / PIX interop) on platforms where it cannot work.
  3. Install Microsoft PIX so the path can be resolved and validated once the folder is found.

Example fix

// before: PIX capture enabled unconditionally
GraphicsDeviceFactory.EnableGPUCaptureAssertions = true;
// after: guard for Windows PIX availability
if (OperatingSystem.IsWindows() && Platform.IsWindowsDesktop)
    GraphicsDeviceFactory.EnableGPUCaptureAssertions = true;
Defensive patterns

Strategy: fallback

Validate before calling

if (!OperatingSystem.IsWindows())
{
    log.Info("PIX GPU capture unsupported on this OS; skipping");
    return;
}
var pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
if (string.IsNullOrEmpty(pf)) { log.Warn("Program Files not resolvable; PIX capture skipped"); return; }

Type guard

bool CanUsePixCapture() => OperatingSystem.IsWindows()
    && !string.IsNullOrEmpty(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles));

Try / catch

try { WinPixNative.Initialize(); }
catch (DirectoryNotFoundException ex) { log.Warn("PIX capture unavailable: " + ex.Message); }

Prevention

When it happens

Trigger: Enabling PIX GPU capture (via a debugger/Profiler attached capture request) on a system where the Program Files environment variable/special folder is not resolvable — e.g. running on non-Windows, a sandbox, or an environment with redirected/missing system folders.

Common situations: Capturing on Linux/macOS where the WinPIX path makes no sense; running under a service account or container with stripped environment variables; CI machines without standard Windows folder layout.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/cc5e569d9cf6f4a0. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Direct3D12/WinPixNative.cs:84

    ///   This method is typically called before initializing GPU capture or profiling with Microsoft PIX.
    ///   If the DLL is already loaded, calling this method has no effect.
    /// </remarks>
    public static void LoadPixGpuCapturer()
    {
        IntPtr moduleHandle = GetModuleHandle(CapturerDllName);
        if (moduleHandle == IntPtr.Zero)
        {
            LoadLibrary(GetLatestWinPixGpuCapturerPath());
        }

        //
        // Helper to locate the latest installed "WinPixGpuCapturer.dll".
        //
        static string GetLatestWinPixGpuCapturerPath()
        {
            string programFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
            if (string.IsNullOrEmpty(programFilesPath))
                throw new DirectoryNotFoundException("Could not locate \"Program Files\" folder.");

            string pixInstallationPath = Path.Combine(programFilesPath, "Microsoft PIX");
            if (!Directory.Exists(pixInstallationPath))
                throw new DirectoryNotFoundException($"Microsoft PIX not found under \"{programFilesPath}\".");

            string newestVersionFound = null;

            // Enumerate all subdirectories, looking for the one with the highest version number
            foreach (var dir in Directory.EnumerateDirectories(pixInstallationPath))
            {
                var dirName = Path.GetFileName(dir);
                if (string.IsNullOrEmpty(dirName))
                    continue;

                if (newestVersionFound is null || string.CompareOrdinal(newestVersionFound, dirName) < 0)
                {
                    newestVersionFound = dirName;
                }

View on GitHub (pinned to 96fad776d2)