Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ Do not rename a public type to get under the limit.

- Preserve the existing nullable reference type annotations and context (`<Nullable>enable</Nullable>` is set at project level).
- Do not enable or disable nullable in individual files unless requested.
- **ThrowHelper (required for BCL throws):** For new and changed code, throw framework exceptions only through `Krypton.Interop.ThrowHelper` (`Source/Krypton Components/Krypton.Interop/General/ThrowHelper.cs`). Prefer `ThrowIfNull` / `ThrowIfNullOrWhiteSpace` for guards, `value ?? ThrowHelper.ThrowArgumentNullException(value)` (or the generic `<T>` overloads) in expression contexts, and the matching `ThrowArgumentException` / `ThrowArgumentOutOfRangeException` / `ThrowInvalidOperationException` / `ThrowNotSupportedException` / `ThrowNotImplementedException` / `ThrowObjectDisposedException` / `ThrowInvalidCastException` / `ThrowWin32Exception` / `ThrowNullReferenceException` helpers when that is the contract. Do **not** write bare `throw new ArgumentNullException(...)`, `throw new ArgumentException(...)`, `throw new ArgumentOutOfRangeException(...)`, `throw new InvalidOperationException(...)`, and the other BCL types `ThrowHelper` already covers. `ThrowHelper` is `internal` in Interop and visible to sibling assemblies via `InternalsVisibleTo`; do not duplicate it, and do not add `ThrowHelper` APIs for product/domain exception types (for example `KryptonUpdateException`) into Interop. Domain or feature exceptions stay as typed `throw new …` (or a **local** cold-path helper next to that feature when the call sites are many). Apply to new and changed throw sites; do not mass-convert unrelated legacy `throw new` in files outside the task unless asked.
- No unneeded `try/catch` blocks if there's no catch handling
- Idioms: use null-propagation and object/collection initializers where consistent
- Prefer [switch expressions](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression) for simple value/type dispatch that only returns (or assigns) a value. Keep `switch` statements for complex control flow, multiple statements per arm, or side effects. Prefer a discard arm (`_ => ...`) when exhaustiveness matters. Use only pattern forms already common in this codebase (constant, type, discard, simple property/`when` guards as elsewhere); do not introduce newer pattern syntax that would fight **Public API → Compatibility**. Apply to new and changed code; do not mass-convert unrelated existing code unless asked.
Expand Down Expand Up @@ -830,6 +831,7 @@ When adding a **new** example project in [Standard-Toolkit-Demos](https://github
- **PNG** for a static default look of the example in **both** a light and a dark builtin theme (same baseline as Toolkit **UI Screenshots / GIFs**: `Microsoft365Blue` and `Microsoft365BlackDarkMode`). Do not shoot every theme.
- Prefer filenames that keep the pair obvious (`example-light.png` / `example-dark.png`, or `Example-light.png` / `Example-dark.png`). When the category README historically shows a single image, embed both (two image lines under the heading).
- **GIF** when motion is the point (toggle, toast, menu open, fade, scrollbar interaction), matching neighbours such as `KryptonToggleSwitchExample.gif` or `ToastNotificationExample.gif`. Capture light and dark when the motion is theme-sensitive; one GIF is enough when motion is geometry-only.
- Prefer PrintWindow / HWND capture of the example form (same idea as Toolkit **UI Screenshots / GIFs**); verify the image shows the demo, not the IDE.

#### Where to save the file

Expand Down
1 change: 1 addition & 0 deletions Documents/Changelog/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
- A download that drops or is cancelled stays on the progress window so it can be resumed or started again. The whole file is still checked before it is applied.
- Release notes open in their own window, Remind later asks for a date or skips that version, and the progress window can show file name, size, speed, and time remaining.
- The update manifest can limit how many days Remind later offers, and can allow or block postpone, skip, resume, and retry. A critical package blocks postpone unless `allowPostpone` is true and blocks skip unless `allowSkip` is true. `allowRetry` false hides Restart.
- The update manifest can add an optional banner (text, colours or gradient, image URL) on the prompt and notes windows, and an optional pulsing form border on the prompt, notes, and progress windows.
- To use, you will need to download the [Krypton.Standard.Toolkit](https://www.nuget.org/packages/Krypton.Standard.Toolkit) NuGet package, as this control is part of the `Krypton.Toolkit.Utilities` assembly.
- Implemented [#3806](https://github.com/Krypton-Suite/Standard-Toolkit/issues/3806), Windows XP Themes
- Windows XP visual-style Extra themes in `Krypton.Themes`: Luna Blue / Olive / Silver, Royale, Royale Noir, Zune, and Embedded, with a dedicated XP renderer in `Krypton.Toolkit` and typed bitmaps from `Krypton.Resources`.
Expand Down
79 changes: 50 additions & 29 deletions Scripts/UnitTests/Invoke-ApplicationUpdaterRecoveryScreenshot.ps1
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<#
.SYNOPSIS
Captures the updater progress window after an interrupted download.
Captures the updater progress window after an interrupted download in light and dark themes.

.DESCRIPTION
Loads the Debug net472 utilities build in-process (STA), shows the internal
progress form with Resume, Restart, and Close, and writes
Documents/PR/4669-application-updater-recovery.png with PrintWindow.
Loads the Debug net472 utilities build in-process (STA), shows the internal progress form
with Resume, Restart, and Close under Microsoft365Blue and Microsoft365BlackDarkMode, and
writes Documents/PR/4669-application-updater-recovery-light.png and *-dark.png with PrintWindow.

# UnitTest-CI: exclude

Expand All @@ -17,16 +17,19 @@ param(
[string]$Configuration = 'Debug',
[string]$TargetFramework = 'net472',
[string]$BinDir,
[string]$OutputPath
[string]$OutputDirectory
)

$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'UnitTestCommon.ps1')

$repoRoot = Get-UnitTestRepoRoot
$bin = Get-UnitTestBinDir -RepoRoot $repoRoot -Configuration $Configuration -TargetFramework $TargetFramework -BinDir $BinDir
if (-not $OutputPath) {
$OutputPath = Join-Path $repoRoot 'Documents\PR\4669-application-updater-recovery.png'
if (-not $OutputDirectory) {
$OutputDirectory = Join-Path $repoRoot 'Documents\PR'
}
if (-not (Test-Path -LiteralPath $OutputDirectory)) {
New-Item -ItemType Directory -Path $OutputDirectory | Out-Null
}

Register-UnitTestAssemblyResolver -BinDir $bin
Expand All @@ -36,6 +39,11 @@ Initialize-UnitTestNativeInput
[void][System.Reflection.Assembly]::LoadFrom((Join-Path $bin 'Krypton.Interop.dll'))
[void][System.Reflection.Assembly]::LoadFrom((Join-Path $bin 'Krypton.Resources.dll'))
[void][System.Reflection.Assembly]::LoadFrom((Join-Path $bin 'Krypton.Toolkit.dll'))
$themesDll = Join-Path $bin 'Krypton.Themes.dll'
if (-not (Test-Path -LiteralPath $themesDll)) {
throw "Missing $themesDll - build Krypton.Themes Debug $TargetFramework first."
}
[void][System.Reflection.Assembly]::LoadFrom($themesDll)
$utilities = [System.Reflection.Assembly]::LoadFrom((Join-Path $bin 'Krypton.Toolkit.Utilities.dll'))

[System.Windows.Forms.Application]::EnableVisualStyles()
Expand All @@ -46,27 +54,40 @@ if (-not $formType -or -not $stringsType) {
}

$flags = [System.Reflection.BindingFlags]'Instance,Public,NonPublic'
$strings = [System.Activator]::CreateInstance($stringsType)
$form = [System.Activator]::CreateInstance($formType)
[void]$formType.GetMethod('Bind', $flags).Invoke($form, @($strings))
$progressArgs = [object[]]::new(2)
$progressArgs[0] = [int64]45
$progressArgs[1] = [Nullable[int64]]100
[void]$formType.GetMethod('SetProgress', $flags).Invoke($form, $progressArgs)
[void]$formType.GetMethod('ShowRecovery', $flags).Invoke($form, @($strings.DownloadInterrupted, $true, $true, $strings))
$manager = New-Object Krypton.Toolkit.KryptonManager
$themes = @(
@{ Mode = [Krypton.Toolkit.PaletteMode]::Microsoft365Blue; Suffix = 'light' },
@{ Mode = [Krypton.Toolkit.PaletteMode]::Microsoft365BlackDarkMode; Suffix = 'dark' }
)

$form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
$form.Location = New-Object System.Drawing.Point 80, 80
$form.TopMost = $true
$form.Show()
$form.Activate()
$form.BringToFront()
[void][UnitTestNative]::SetForegroundWindow($form.Handle)
[System.Windows.Forms.Application]::DoEvents()
Start-Sleep -Milliseconds 500
[System.Windows.Forms.Application]::DoEvents()
foreach ($theme in $themes) {
$manager.GlobalPaletteMode = $theme.Mode
$strings = [System.Activator]::CreateInstance($stringsType)
$form = [System.Activator]::CreateInstance($formType)
[void]$formType.GetMethod('Bind', $flags).Invoke($form, @($strings, $null))
$progressArgs = [object[]]::new(2)
$progressArgs[0] = [int64]45
$progressArgs[1] = [Nullable[int64]]100
[void]$formType.GetMethod('SetProgress', $flags).Invoke($form, $progressArgs)
# ShowRecovery returns Task; start the recovery UI without awaiting the choice.
$null = $formType.GetMethod('ShowRecovery', $flags).Invoke($form, @($strings.DownloadInterrupted, $true, $true, $strings))
[System.Windows.Forms.Application]::DoEvents()

Save-UnitTestWindowPng -Form $form -Path $OutputPath
$form.Close()
$form.Dispose()
Write-Output "Wrote $OutputPath"
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
$form.Location = New-Object System.Drawing.Point 80, 80
$form.TopMost = $true
$form.Show()
$form.Refresh()
$form.Activate()
$form.BringToFront()
[void][UnitTestNative]::SetForegroundWindow($form.Handle)
[System.Windows.Forms.Application]::DoEvents()
Start-Sleep -Milliseconds 500
[System.Windows.Forms.Application]::DoEvents()

$outputPath = Join-Path $OutputDirectory "4669-application-updater-recovery-$($theme.Suffix).png"
Save-UnitTestWindowPng -Form $form -Path $outputPath
$form.Close()
$form.Dispose()
Write-Output "Wrote $outputPath"
}
Loading
Loading