Adds x64 and ARM64 build support and extends the release pipeline to publish all three architectures (x86/x64/arm64). Ships as 3.4.0.
EarTrumpet.csproj: Platforms now includes x86;x64;arm64. RuntimeIdentifier/PlatformTarget are conditionally set per $(Platform) (win-x86→win-x64→win-arm64), with X86/X64/ARM64 define constants. New Debug|x64/Release|x64/Debug|arm64/Release|arm64 property blocks output to Build\Debug-x64/Build\Release-x64/Build\Debug-arm64/Build\Release-arm64.EarTrumpet.vs15.sln: adds Debug|x64/Release|x64/VSDebug|x64 and Debug|arm64/Release|arm64/VSDebug|arm64 solution configurations for EarTrumpet. EarTrumpet.ColorTool (a legacy non-SDK dev utility whose only platform PropertyGroups are Debug|x86/Release|x86) and EarTrumpet.Package (x86-only Store packaging, AppxBundlePlatforms=x86) are excluded from the x64/arm64 configurations rather than given mappings they cannot honour — otherwise a solution build fails with "The BaseOutputPath/OutputPath property is not set for project 'EarTrumpet.ColorTool.csproj' ... Platform='arm64'". Neither ships in the installer or the portable ZIP.Ntdll.cs: adds x64/ARM64 SYSTEM_PROCESS_INFORMATION layout (64-bit pointer alignment: ImageName at 56, UniqueProcessId as IntPtr at 80).User32.cs: x64/ARM64 use GetWindowLongPtr/SetWindowLongPtr instead of the 32-bit-only GetWindowLong/SetWindowLong.WindowExtensions.cs: introduces GetWindowStyle/SetWindowStyle helpers that dispatch to the correct P/Invoke per architecture.DesktopAppInfo.cs: UniqueProcessId comparison uses ToInt32() on 64-bit.Code that was only ever exercised as x86 and misbehaves once 64-bit builds ship. IntPtr.ToInt32() throws OverflowException whenever bit 31 is set — regardless of the checked/unchecked context — and 64-bit Windows zero-extends DWORD-sized values into a LONG_PTR/UINT_PTR.
UpdateService.cs: asset selection matched EndsWith("-setup.exe"), which no arch-suffixed asset satisfies. Once a release ships the six-asset layout, every x64 and ARM64 install would silently update itself to the x86 build, overwriting the native install in place. Selection is now driven by RuntimeInformation.ProcessArchitecture, falling back to the unsuffixed x86 asset so releases that ship x86 only still update.ShellNotifyIcon.cs: the notify-icon callback packs the context-menu anchor into wParam as MAKEWPARAM(x, y). Keyboard invocation sends (-1,-1), and monitors above the primary have a negative y, so wParam arrives as 0x00000000FFFFxxxx and the decode threw before HasValidContextMenuPoint — the guard written for exactly that case — could ever run.WindowExtensions.cs: same hazard on GetWindowLongPtr(GWL_STYLE), where WS_POPUP sets bit 31. No WPF Window in this app currently produces WS_POPUP, so the two call sites are safe today, but the helper is general and the failure would be silent until it is not.installer.iss: architecture selected via /DArch=x86|x64|arm64, each mapping to its build dir, ArchitecturesAllowed, and output name. Adds ArchitecturesInstallIn64BitMode for x64/arm64 — without it DefaultDirName={autopf} resolves through {commonpf32}, so an all-users install would put the native build in Program Files (x86) with its registry writes redirected into Wow6432Node. AppId is now explicit at the value Inno previously derived from AppName, so existing installs keep their uninstall entry and the three architectures upgrade in place instead of coexisting as separate entries.build-portable.ps1: new -Arch parameter. Validates the build output exists — previously a missing build dir was a non-terminating error that produced a ~200-byte ZIP holding only portable.marker, and exited 0.release.ps1: builds all three architectures, runs ISCC three times, builds the three portable ZIPs (previously collected as release assets but never actually produced — gh release create would have aborted on missing files with the tag already pushed), computes per-arch SHA256, rewrites the chocolatey and winget checksums, and uploads all six assets. Build/ISCC/gh exit codes are now checked, every asset is asserted present before the tag is pushed, checksum rewriting is re-runnable instead of a silent no-op on the second run, and the ISCC path is discovered (6.x under Program Files (x86), 7.x per-user under %LOCALAPPDATA%\Programs, or PATH) rather than pinned, with -InnoSetup to override. Step 1 now builds EarTrumpet\EarTrumpet.csproj with dotnet build instead of the whole solution with msbuild: that project is what produces the shipped binaries, it is SDK-style, and it drops the dependency on a Developer Command Prompt and on the MSIX packaging workload .wapproj requires.3.4.0/ with per-arch InstallerUrl/InstallerSha256; winget picks the matching architecture automatically. The published 3.3.1/ manifest is restored to the hash that is actually live.PROCESSOR_ARCHITEW6432. choco.exe is a 32-bit process, so PROCESSOR_ARCHITECTURE reads x86 under ARM64 emulation, and Chocolatey's own Get-OSArchitectureWidth forces 32-bit whenever it sees ARM64 — meaning url64bit is never selected there and ARM64 machines would otherwise get the x86 installer.Ships as 3.4.0 rather than re-releasing 3.3.1, whose x86 assets are already published — rebuilding them from changed sources would invalidate the hash existing users already have, and the manifests had been pointed at v3.3.1 URLs for x64/arm64 installers that do not exist there. GitVersion.yml is bumped along with the rest: App.PackageVersion comes from the assembly version, so leaving it at 3.3.1 while tagging v3.4.0 would make every install report an older version than the release it just installed and be offered the same update forever.
Release|x86, Release|x64, Release|arm64 all build clean — 0 errors, 0 warnings, with TreatWarningsAsErrors on.Platform=arm64 previously failed on ColorTool's unset OutputPath and on the wapproj's missing Microsoft.DesktopBridge.props; both are gone after the exclusion.0x014C (I386), 0x8664 (AMD64), 0xAA64 (ARM64).SYSTEM_PROCESS_INFORMATION offsets were verified against a live NtQuerySystemInformation walk: 244 entries traversed against 244 real processes, image names and the self-PID correct.build-portable.ps1 exercised for all three architectures plus its missing-build-dir guard.Not covered: the installers were compiled but not run, so the Program Files / uninstall-entry behaviour of ArchitecturesInstallIn64BitMode and AppId is reasoned from the Inno Setup docs rather than observed. Cross-architecture upgrade over an existing 3.3.1 install is likewise untested.
Workflows from forks require approval
CI will not run on this pull request until someone with write access on the target repository approves workflows for commit 70356d6. Secrets stay withheld for fork PRs.
Waiting for a target-repo writer to approve.
Sign in to comment.