Skip to content

Commit 3e19042

Browse files
adamgellclaude
andcommitted
fix(release): self-contained WinAppSDK client + MSI-only installers
The v1.0.0-beta.1 client crashed on launch with "microsoft.windowsappruntime .bootstrap.dll was not found" on any machine without the Windows App SDK runtime installed. Two faults, both fixed: - The stage step copied only app.exe, dropping the runtime DLLs the build places beside it. Now copy the whole client build output (minus Rust artifacts) and rename the exe. - The client was framework-dependent (needs the runtime installed system-wide). Add a `self-contained` cargo feature: build.rs bundles the full WinAppSDK runtime next to the exe and main.rs skips the bootstrapper (which otherwise keeps a load-time dependency on the bootstrap shim). Release builds pass `--features self-contained`. Verified locally: the self-contained exe launches and opens its window with no runtime pre-installed; dumpbin confirms the bootstrap DLL is no longer a load-time import. Also drop the MSIX output. mpdev wraps the package in its x64 Package Support Framework launcher (to inject the Syncfusion env var), so the arm64 MSIX ships an x64 PsfLauncher64.exe + a VFS\ProgramFilesX64 payload and fails to install with 0x80070005. Ship signed MSI + portable zip for both arches instead; revisit MSIX later. The MSI's SmartScreen prompt is cert-reputation, not a signing fault. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 7306cce commit 3e19042

5 files changed

Lines changed: 40 additions & 15 deletions

File tree

.github/workflows/cmprojectx-codesign.yml

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ jobs:
196196
Start-Process msiexec.exe -ArgumentList "/i `"$msi`" /quiet /norestart" -Wait
197197
"C:\Program Files\Master Packager Ltd\Master Packager Dev" | Out-File -FilePath $env:GITHUB_PATH -Append -Encoding utf8
198198
199-
- name: Build Rust client
200-
run: cargo build --release --package app --target ${{ matrix.rust_target }}
199+
- name: Build Rust client (self-contained Windows App SDK runtime)
200+
run: cargo build --release --package app --target ${{ matrix.rust_target }} --features self-contained
201201

202202
- name: Publish .NET sidecar (self-contained)
203203
run: >-
@@ -243,7 +243,18 @@ jobs:
243243
run: |
244244
$bundle = Join-Path $PWD "staging/IntuneCommander-$($env:VERSION)-${{ matrix.arch }}"
245245
New-Item -ItemType Directory -Force -Path $bundle | Out-Null
246-
Copy-Item "target/${{ matrix.rust_target }}/release/app.exe" (Join-Path $bundle "IntuneCommander.exe") -Force
246+
# Copy the ENTIRE self-contained client output — app.exe PLUS the bundled Windows App SDK
247+
# runtime DLLs, the ~80 language folders, and resources.pri. Copying only app.exe ships a
248+
# client that crashes on launch with "microsoft.windowsappruntime.bootstrap.dll not found"
249+
# on any machine without the runtime. Exclude Rust build artifacts; rename exe to the product.
250+
$rel = "target/${{ matrix.rust_target }}/release"
251+
$skipDir = @('deps','build','.fingerprint','incremental','examples')
252+
$skipExt = @('.pdb','.d','.rlib','.rmeta','.exp','.lib')
253+
Get-ChildItem -LiteralPath $rel | Where-Object {
254+
if ($_.PSIsContainer) { $skipDir -notcontains $_.Name }
255+
else { ($skipExt -notcontains $_.Extension) -and ($_.Name -ne '.cargo-lock') }
256+
} | Copy-Item -Destination $bundle -Recurse -Force
257+
Rename-Item (Join-Path $bundle "app.exe") "IntuneCommander.exe" -Force
247258
Copy-Item "publish/service" (Join-Path $bundle "sidecar") -Recurse -Force
248259
New-Item -ItemType Directory -Force -Path (Join-Path $bundle "docs") | Out-Null
249260
Copy-Item "docs/RUNBOOK.md" (Join-Path $bundle "docs") -Force
@@ -264,7 +275,7 @@ jobs:
264275
Set-Content (Join-Path $bundle "Start-IntuneCommander.cmd") $launcher -Encoding ascii
265276
"bundle_dir=$bundle" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
266277
267-
- name: Build signed MSI + MSIX (mpdev)
278+
- name: Build signed MSI (mpdev)
268279
shell: pwsh
269280
env:
270281
IC_BUNDLE_DIR: ${{ steps.stage.outputs.bundle_dir }}
@@ -288,17 +299,15 @@ jobs:
288299
- name: Verify installer output
289300
shell: pwsh
290301
run: |
291-
foreach ($ext in 'msi','msix') {
302+
foreach ($ext in @('msi')) {
292303
$f = "publish/installer/IntuneCommander-$($env:VERSION)-${{ matrix.arch }}.$ext"
293304
if (-not (Test-Path $f)) { Get-ChildItem publish/installer; throw "Expected installer not found: $f" }
294305
}
295306
296307
- name: Attest build provenance
297308
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
298309
with:
299-
subject-path: |
300-
publish/installer/IntuneCommander-${{ env.VERSION }}-${{ matrix.arch }}.msi
301-
publish/installer/IntuneCommander-${{ env.VERSION }}-${{ matrix.arch }}.msix
310+
subject-path: publish/installer/IntuneCommander-${{ env.VERSION }}-${{ matrix.arch }}.msi
302311

303312
- name: Upload workflow artifacts
304313
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -314,7 +323,6 @@ jobs:
314323
run: |
315324
$assets = @(
316325
"publish/installer/IntuneCommander-$($env:VERSION)-${{ matrix.arch }}.msi",
317-
"publish/installer/IntuneCommander-$($env:VERSION)-${{ matrix.arch }}.msix",
318326
"publish/installer/IntuneCommander-$($env:VERSION)-win-${{ matrix.arch }}.zip"
319327
)
320328
gh release upload $env:TAG_NAME @assets --clobber

app/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ edition = "2024"
77
license.workspace = true
88
authors.workspace = true
99

10+
[features]
11+
# Release builds enable this to bundle the Windows App SDK runtime next to the
12+
# exe (self-contained — runs on a machine with no runtime installed). Dev builds
13+
# omit it and stay framework-dependent (faster; uses the installed runtime).
14+
# build.rs and main.rs both key off it and MUST stay in sync.
15+
self-contained = []
16+
1017
[dependencies]
1118
api-types = { path = "../crates/api-types" }
1219
serde_json.workspace = true

app/build.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
fn main() {
2-
// Link against the installed Windows App SDK runtime (2.0.1+) rather than
3-
// bundling it. Mirrors crates/samples/reactor/framework-dependent and the
4-
// Phase 0 reactor-gate.
5-
windows_reactor_setup::as_framework_dependent();
2+
// With `--features self-contained` (release builds), bundle the entire Windows
3+
// App SDK runtime next to the exe so the client runs on a clean machine with no
4+
// runtime pre-installed. main.rs must skip the bootstrapper in that mode.
5+
// Without the feature (dev builds), stay framework-dependent: link against the
6+
// installed Windows App SDK runtime (mirrors the Phase 0 reactor-gate).
7+
if std::env::var_os("CARGO_FEATURE_SELF_CONTAINED").is_some() {
8+
windows_reactor_setup::as_self_contained();
9+
} else {
10+
windows_reactor_setup::as_framework_dependent();
11+
}
612
}

app/src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ fn main() -> Result<()> {
9595
// Start (or reuse) the .NET sidecar — the app owns its lifecycle, so there's no
9696
// separate process to launch. Held for the app's lifetime; killed on exit.
9797
let _sidecar = sidecar::ensure_running();
98-
// Initialize the Windows App SDK bootstrapper before touching any WinUI types.
98+
// Framework-dependent builds must initialize the Windows App SDK bootstrapper to
99+
// locate the installed runtime before touching any WinUI types. Self-contained
100+
// builds bundle the runtime and MUST NOT call it (no bootstrap shim is shipped,
101+
// and the call would re-introduce a load-time dependency on it) — see build.rs.
102+
#[cfg(not(feature = "self-contained"))]
99103
let _bootstrap_handle = bootstrap()?;
100104
App::new()
101105
.title("IntuneCommander")

packaging/installer.mpdev.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://www.masterpackager.com/support-master-packager-dev/mpdev-schema.json",
3-
"outputTypes": [ "msi", "msix" ],
3+
"outputTypes": [ "msi" ],
44
"outputDirectory": "publish\\installer",
55
"outputFileName": "IntuneCommander-$.version-x64",
66
"packageName": "IntuneCommander",

0 commit comments

Comments
 (0)