Utilities

Smaller building blocks for real applications and toolboxes: file integrity, screenshot and photo export, microphone capture, and the app-loop control an application needs to behave well on the system.

File integrity and checksums

SharpProspero.Security computes message digests and checksums with no system module, so a tool can verify a downloaded file against a published checksum or compare two files. The algorithms are Sha256, Sha1, Md5 and Crc32.

using SharpProspero.Security;

string sum = Sha256.HashFileHex("/data/game.pkg");   // lowercase hex
bool ok = sum == published;

uint crc = Crc32.ComputeFileValue("/data/archive.bin");

Each digest also works on a block of bytes (Sha256.Hash, Sha256.HashHex) or a stream of chunks:

var hash = new Sha256();
hash.Update(part1);
hash.Update(part2);
byte[] digest = hash.Finish();

Prefer Sha256 to guard against tampering; Md5 and Sha1 are for matching sums that other tools publish, and Crc32 is a fast check for accidental corruption.

Screenshots and photo export

A drawing surface encodes to a file for a screenshot or an export. PNG is lossless and best for interface captures; JPEG is far smaller and best for photographic content. Load the encode module first.

using var pngEnc = SystemModule.Load(SystemModuleId.PngEnc);
PngEncoder.Save(surface, "/data/screenshot.png");

using var jpegEnc = SystemModule.Load(SystemModuleId.JpegEnc);
JpegEncoder.Save(surface, "/data/photo.jpg", quality: 90);   // quality 1..100

Both also return the encoded bytes directly (PngEncoder.Encode, JpegEncoder.Encode) for sending over the network or storing elsewhere.

System capture

ShareCapture captures the whole finished screen, the application together with the system overlays, and saves it to the console’s capture gallery. It is the game-DVR capture the share button drives: use it to grab a 2K or 4K screenshot, or to save the last several seconds of output as a video clip. This differs from encoding a drawing surface, which captures only what the application itself drew.

using var share = ShareCapture.Start();
share.CaptureScreenshot(ScreenshotFormat.Png4K);   // saved to the gallery in the background
share.CaptureRecentClip(secondsBack: 30);          // save the last 30 seconds as a clip

Captures are asynchronous: each call returns a request id and the image or clip is written in the background. Block(ShareFeature.Screenshot) prevents capture while a sensitive screen is shown, and Allow re-enables it; SetScreenshotOverlay adds a watermark to captured screenshots.

Live capture of the finished screen (advanced)

SystemAvCapture reads the live system-composited audio and video — the finished screen the whole system draws, together with its audio — for a recorder or a stream, rather than saving a gallery clip. It is an advanced, privileged surface: the capture service runs behind a system channel and the process must hold the authority to reach it, which a plain application sandbox does not, so opening it there fails with a permission error. Treat it as best-effort.

using SharpProspero.Interop.AvCapture;
using SharpProspero.Platform;

using var capture = SystemAvCapture.Open();
capture.OpenVideo(Avcap2VideoConfig.Create());
capture.Start();
while (recording)
{
    if (capture.TryReadVideo(out Avcap2VideoFrameInfo frame) && frame.IsValid)
        Encode(frame);          // a privileged consumer reads the frame planes
}
capture.Stop();

For a recording path that needs no elevated privilege, save a gallery clip with ShareCapture above, or encode the application’s own frames with the image encoders. Use SystemAvCapture only when the whole finished screen, including other applications and the system overlays, must be captured live.

Microphone capture

AudioInDevice captures 16-bit samples from the microphone for a voice recorder, a level meter, or speech input. It mirrors audio output: open a port, then pull one block per call, each call blocking until a block is captured.

using SharpProspero.Audio;

using var mic = AudioInDevice.OpenMicrophone(userId);
short[] block = new short[mic.SamplesPerBlock];
while (recording)
{
    mic.Read(block);
    // append block to a buffer, measure its level, or feed it onward
}

IsSilent reports when the input is muted at the hardware or by the system.

WAV audio files

WavAudio reads and writes 16-bit PCM WAV files with no system module, so a sound loads straight into the shape the audio port plays and a microphone recording writes straight back out. A file becomes a PcmAudio — the interleaved samples, the sample rate and the channel count.

using SharpProspero.Audio;

PcmAudio clip = WavAudio.Load("/app0/assets/beep.wav");
using var audio = AudioOutDevice.OpenStereo();
audio.Output(clip.Samples);            // play it

// Save a recording:
WavAudio.Save("/data/recording.wav", new PcmAudio(recorded, 48000, 2));

PcmAudio reports its FrameCount and DurationMilliseconds. Only uncompressed 16-bit mono or stereo is handled, which is the format the audio ports use, so what is read is always ready to play.

Keeping the console awake and reacting to the system

SystemControl gives an application the app-loop control it needs. During a long operation with no controller activity, call KeepAwake periodically so the console does not shut down on its idle timer.

using SharpProspero.Platform;

while (installing)
{
    SystemControl.KeepAwake();
    // do a slice of work
}

Poll TryReceiveEvent each frame to react to system events, such as resuming from sleep, where time and inputs may have moved on:

while (SystemControl.TryReceiveEvent(out SystemEventType type))
{
    if (type == SystemEventType.Resume)
        ResyncClock();
}

Other members read whether the application is in the background (IsInBackground), the display’s safe area for laying out important content (DisplaySafeAreaRatio), and take the audio output for the module alone (SilenceBackgroundMedia / RestoreBackgroundMedia). LoadExecutable replaces the running module with another, for chain-loading. The console’s name is available from SystemParameters.SystemName.

Logging

SharpProspero.Diagnostics gives a module a small logging facility: choose a minimum level, add one or more sinks, and write leveled messages. Messages below the minimum, or when no sink is attached, cost almost nothing, and a failing sink never throws back to the caller.

using SharpProspero.Diagnostics;

Log.MinimumLevel = LogLevel.Debug;
Log.AddSink(FileLogSink.Open("/data/app.log"));   // appends lines to a file
Log.AddSink(new ConsoleLogSink());                // and to the development console

Log.Information("started");
Log.Error($"load failed: 0x{code:X8}");

Each line is written as HH:mm:ss.fff LVL message. FileLogSink appends to a file the user can read back after a run and is disposed at shutdown; ConsoleLogSink writes to standard output, which appears on the development console when one is attached. Implement ILogSink to send logs somewhere else, such as over the network.

Settings files

IniFile keeps a module’s own configuration in a small INI-style file, with no system module. Values live under named sections as key = value lines, and a leading ; or # marks a comment — a format the user can also read and edit. Load a file, read and write typed values, save it back.

using SharpProspero.Storage;

IniFile settings = IniFile.Load("/data/app.ini");
int volume = settings.GetInt("audio", "volume", 80);
bool fullscreen = settings.GetBool("display", "fullscreen", true);

settings.Set("audio", "volume", 90);
settings.Save("/data/app.ini");

GetString, GetInt and GetBool each take a fallback for a missing value, so a first run with no file still gets sensible defaults. Load returns an empty store when the file is absent.

Optical disc

DiscDrive reaches the Blu-ray drive. There is no dedicated disc service, so it works through the file system and the raw device node, and both need the module to run with enough privilege to reach the drive, which a plain application sandbox does not have — treat the reads as best-effort.

When the system has recognised a disc it mounts its filesystem under DiscDrive.MountPoint (/mnt/disc), which is browsed with the ordinary file APIs:

if (DiscDrive.IsDiscMounted)
    foreach (DirectoryEntry entry in DiscDrive.EnumerateFiles())
        Show(entry.Name);

The raw block device is opened for a sector-level read or a full dump:

using var disc = DiscDrive.OpenDevice();               // /dev/cd0
long total = disc.DumpTo("/data/disc.iso", onProgress: bytes => Report(bytes));

DumpTo reads the device to a file until the end; Read and Seek do positioned reads. What the device returns is the drive’s raw content, so for a commercial disc the readable files are the ones the system has already mounted under /mnt/disc, not the raw sectors.


Copyright © SvenGDK 2026. Distributed under the GPL-3.0-or-later license.

This site uses Just the Docs, a documentation theme for Jekyll.