diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef9294a..3a229c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,6 +60,21 @@ jobs: path: publish/ProDHCPServer.exe if-no-files-found: error + # A test-signed MSIX (placeholder identity) proves the Store package builds, installs and starts. + - name: Build test-signed MSIX + shell: pwsh + run: tools/build-msix.ps1 -Exe publish/ProDHCPServer.exe -Version "0.1.${{ github.run_number }}" -OutFile msix/ProDHCPServer-test.msix -TestSign + + - name: MSIX smoke test (install, start with settings open, uninstall) + shell: pwsh + run: tools/msix-smoke-test.ps1 -Package msix/ProDHCPServer-test.msix -OutDir screenshots + + - uses: actions/upload-artifact@v4 + with: + name: ProDHCPServer-msix-test + path: msix/ + if-no-files-found: error + # Keep the latest screenshots on a throwaway branch so they can be viewed without downloading artifacts. - name: Publish screenshots to the ci-screenshots branch if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53bd1f9..9ee6601 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,6 +68,21 @@ jobs: Set-Content -NoNewline -Encoding ascii "dist/$name.sha256" "$hash $name`n" Get-ChildItem dist + # The Store package to upload in Partner Center. It stays unsigned: the Store signs it. Its identity comes from + # the repository variables STORE_IDENTITY_NAME, STORE_PUBLISHER and STORE_PUBLISHER_DISPLAY_NAME + # (Settings > Secrets and variables > Actions > Variables), copied from Partner Center > Product identity. + - name: Build the Microsoft Store package + if: vars.STORE_IDENTITY_NAME != '' + shell: pwsh + env: + STORE_IDENTITY_NAME: ${{ vars.STORE_IDENTITY_NAME }} + STORE_PUBLISHER: ${{ vars.STORE_PUBLISHER }} + STORE_PUBLISHER_DISPLAY_NAME: ${{ vars.STORE_PUBLISHER_DISPLAY_NAME }} + run: > + tools/build-msix.ps1 -Exe publish/ProDHCPServer.exe -Version ${{ steps.version.outputs.version }} + -OutFile "store/ProDHCPServer-$($env:TAG)-x64.msix" + -IdentityName $env:STORE_IDENTITY_NAME -Publisher $env:STORE_PUBLISHER -PublisherDisplayName $env:STORE_PUBLISHER_DISPLAY_NAME + - name: Create or update the draft release shell: pwsh env: @@ -89,5 +104,6 @@ jobs: name: release-${{ env.TAG }} path: | dist/ + store/ screenshots/ if-no-files-found: ignore diff --git a/PRIVACY.md b/PRIVACY.md new file mode 100644 index 0000000..c637b08 --- /dev/null +++ b/PRIVACY.md @@ -0,0 +1,24 @@ +# ProDHCPServer privacy policy + +Last updated: 27 October 2026 + +ProDHCPServer is a DHCP server and device finder that runs on your own Windows laptop. It has no account, no analytics, no advertising and no telemetry. It doesn't send anything about you or your devices to the developer or to anyone else. + +## What it keeps on your laptop + +- Your settings and saved profiles, in `%LOCALAPPDATA%\ProDHCPServer`. +- A backup of your network adapter's settings while a session runs (and after a crash, until they are put back), in `%ProgramData%\ProDHCPServer`. +- Crash reports, in `%ProgramData%\ProDHCPServer`. They stay on the laptop unless you send one yourself. +- The session log, in memory. It is only saved to a file if you press **Export log**. + +These files and an exported log contain network details such as IP addresses, MAC addresses and device names from the network you plug into. None of it leaves the laptop unless you share an exported file yourself. + +## What it sends over the network + +- On the network you plug the laptop into: DHCP replies, pings, ARP and the discovery requests that find AV devices (for example mDNS, and UPnP requests that read a device's description from the device itself). This traffic stays on that local network. +- The copy downloaded from GitHub checks GitHub's public API for a newer release when it starts, if you leave that turned on in Settings > Updates. GitHub sees your IP address, as with any website. The Microsoft Store copy doesn't do this; the Store handles its updates. +- Links in the app (for example to the Npcap download or a release page) open in your web browser. + +## Contact + +Questions about this policy: open an issue at https://github.com/cookingwithsimon/ProDHCPServer/issues. diff --git a/README.md b/README.md index 0d48bae..0316a1b 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,12 @@ Most AV kit ships set to DHCP, and on a bench or a fresh site there's usually no 2. Double-click it. Windows asks for administrator rights, because changing adapter settings and serving DHCP require them. 3. The exe isn't code-signed yet, so the first time Windows SmartScreen says "Windows protected your PC". Click **More info**, then **Run anyway**. +### Updates + +When the laptop has internet, ProDHCPServer checks GitHub for a newer release a few seconds after it starts. If there is one, a green banner offers **Install and restart**: it downloads the new exe, checks it against the SHA-256 published with the release, swaps it in place of the old one and restarts. The server has to be stopped first. Nothing is changed if any step fails, and the previous exe is deleted the next time the app starts. + +On an isolated AV network the check simply doesn't happen. Turn the start-up check off, or check by hand, under Settings > Updates. On a work laptop that only runs approved programs, Windows may block the new version from starting; the app then puts the old one back and says so. + ## Using it 1. Connect the device to your laptop's Ethernet port (directly or through a small switch) and power it on. @@ -104,9 +110,10 @@ Each phase ends with a hardware test pass on real AV equipment before the next o | What | Where | |---|---| -| Your settings (last adapter, profile in use, look and theme) | `%LOCALAPPDATA%\ProDHCPServer\settings.json` | +| Your settings (last adapter, profile in use, look and theme, update check) | `%LOCALAPPDATA%\ProDHCPServer\settings.json` | | Your profiles | `%LOCALAPPDATA%\ProDHCPServer\profiles.json` | | Adapter backup (only while a session runs, or after a crash) | `%ProgramData%\ProDHCPServer\adapter-backup.json` | +| The previous version, for a moment after an update | `ProDHCPServer.exe.old` next to the exe, deleted on the next start | While serving, the app also adds two Windows Firewall rules for this exe only: one so it can receive DHCP traffic (UDP 67 and 68), and one on wired adapters so it can hear devices announcing themselves (mDNS, UPnP, vendor discovery). Both are removed on Stop. @@ -131,9 +138,10 @@ dotnet publish src/ProDHCPServer.App -c Release -r win-x64 -o publish | `src/ProDHCPServer.App` | The WPF app: UI, elevation prompt, crash handling. | | `tests/` | Core unit tests (run anywhere) and Windows integration tests (run on the Windows CI runner and never change adapter settings). | | `docs/` | Hardware test checklists for each phase, the sources for the discovery protocols (`vendor-discovery.md`), and the screenshots used in this README (taken by the CI smoke test). | -| `tools/` | CI smoke test (launches the app and takes screenshots) and the manufacturer list updater (`python3 tools/update-oui.py`). | +| `tools/` | CI smoke tests (launch the exe and the MSIX package and take screenshots), the MSIX packager (`build-msix.ps1`) and the manufacturer list updater (`python3 tools/update-oui.py`). | +| `packaging/msix/` | The Microsoft Store package manifest and tile images. See [docs/microsoft-store.md](docs/microsoft-store.md). | -**CI.** Every push and pull request runs the **Build and test** workflow on Windows: build, Core and Windows tests, publish the exe, and a smoke test that screenshots the app in light and dark mode. The exe and screenshots are uploaded as run artifacts, so you can try a build from any branch before it's released. +**CI.** Every push and pull request runs the **Build and test** workflow on Windows: build, Core and Windows tests, publish the exe, and a smoke test that screenshots the app in light and dark mode. It also builds a test-signed MSIX, installs it on the runner and starts it. The exe, the test MSIX and the screenshots are uploaded as run artifacts, so you can try a build from any branch before it's released. **Contributing.** Work happens on branches with pull requests into `main`. See [CLAUDE.md](CLAUDE.md) for the project rules (they apply to people too), and use the PR template's checklist. Formatting follows `.editorconfig`; check it with `dotnet format whitespace ProDHCPServer.sln --verify-no-changes`. diff --git a/docs/hardware-test-msix.md b/docs/hardware-test-msix.md new file mode 100644 index 0000000..7c376de --- /dev/null +++ b/docs/hardware-test-msix.md @@ -0,0 +1,45 @@ +# Microsoft Store package (MSIX) test + +About 30 minutes on the **unmanaged** laptop (not the work laptop), with one AV device or any DHCP client and a switch or cable. Run this before the first Store submission. + +It tests the Store package with a throwaway test certificate, because only the Store can sign the real one. The point is to check that the packaged app behaves like the exe: the admin prompt, the firewall rule and putting the adapter back. + +## Setup + +1. Download the `ProDHCPServer-msix-test` artifact from this PR's latest **Build and test** run (Actions tab > run > Artifacts) and unzip it. It has `ProDHCPServer-test.msix` and `ProDHCPServer-test.cer`. +2. If the GitHub exe is running, close it. +3. Trust the test certificate: open **PowerShell as administrator** in the unzipped folder and run + `Import-Certificate -FilePath .\ProDHCPServer-test.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople` + +Tick each box. If something fails, export the log (**Export…** above the log) and send me the file, or a photo of the message. + +## 1. Install and start + +- [ ] Double-click `ProDHCPServer-test.msix`. The App Installer window shows ProDHCPServer with **Install**. Install it. +- [ ] Start **ProDHCPServer** from the Start menu. The app's own "Administrator rights needed" window appears first. +- [ ] Press **Restart as administrator**. The Windows UAC prompt appears; choose **Yes**. The main window opens. +- [ ] Open Settings (gear, or Ctrl+,) and scroll to **Updates**. It says "The Microsoft Store installs updates for this copy", with no Check now button and no tick box. +- [ ] Close the app and start it again from Start. Your look and dark/light choice are remembered. + +## 2. Serve DHCP + +- [ ] Choose the wired adapter and press **Start**. It starts serving with no firewall or port 67 error. +- [ ] Plug in the device (or power-cycle it). It gets an address and shows in the list with its manufacturer and ping. +- [ ] Open **Windows Defender Firewall with Advanced Security** > Inbound Rules. The two "ProDHCPServer" rules are there and their program is under `C:\Program Files\WindowsApps\`. +- [ ] Press **Stop**. The adapter goes back to how it was (check `ipconfig`), and the two firewall rules are gone. + +## 3. Find devices + +- [ ] Run the device finder on a device with a static IP. It appears, and **Reach it** works. +- [ ] If Npcap is installed, the switch port shows. If not, the app says Npcap is missing. + +## 4. Crash recovery + +- [ ] Press **Start**, then end ProDHCPServer in Task Manager (Details tab > ProDHCPServer.exe > End task). +- [ ] Start it again from Start. It offers **Restore adapter**; press it, and check `ipconfig`. + +## 5. Uninstall + +- [ ] Settings > Apps > Installed apps > ProDHCPServer > Uninstall. +- [ ] In the administrator PowerShell, remove the test certificate: + `Get-ChildItem Cert:\LocalMachine\TrustedPeople | Where-Object Subject -eq 'CN=ProDHCPServer Test' | Remove-Item` diff --git a/docs/hardware-test-updates.md b/docs/hardware-test-updates.md new file mode 100644 index 0000000..2299de7 --- /dev/null +++ b/docs/hardware-test-updates.md @@ -0,0 +1,47 @@ +# Update checker test + +About 15 minutes on the unmanaged laptop, with internet. No AV devices needed. + +The updater can only update to a release that's already published on GitHub, so this test updates a test build to the newest published release (v1.1.0). v1.1.0 doesn't have the updater itself, so after the update it leaves `ProDHCPServer.exe.old` behind; delete it by hand at the end. + +Download `ProDHCPServer.exe` from this PR's latest **Build and test** run (Actions tab → run → Artifacts → `ProDHCPServer-win-x64`) and put it in a folder of its own, for example `C:\Tools\ProDHCPServer\`. Click **More info → Run anyway** on the SmartScreen warning. + +Tick each box. If something fails, use **Export log…** and send me the file. + +## 1. Test builds don't nag + +- [ ] Start the app with internet. After 10 seconds there is **no** green update banner (test builds only check when asked). +- [ ] Open Settings (gear, or Ctrl+,) and scroll to **Updates**. It says "This is test build 0.1.… It doesn't check for updates by itself; use Check now." + +## 2. Offline + +- [ ] Unplug or turn off the internet connection (Wi-Fi off, no network cable to the internet). +- [ ] Press **Check now**. Within about 10 seconds it says "Couldn't reach GitHub to check for updates. That's normal on an isolated AV network…". No error banner, no popup. +- [ ] The app otherwise works as normal: **Start** and **Stop** a session on a device or an empty port. + +## 3. Check and skip + +- [ ] Reconnect the internet. Press **Check now**. It says "Version 1.1.0 is available. You have test build 0.1.…", and the green banner appears at the top of the main window with **Install and restart**, **What's new**, **Not now** and **Skip this version**. +- [ ] **What's new** opens the release page in your normal browser. +- [ ] **Not now** hides the banner. + +## 4. Can't install while serving + +- [ ] Press **Check now** again so the banner is back, then **Start** the server. +- [ ] **Install and restart** is greyed out and the banner says "Stop the server first: installing restarts ProDHCPServer." +- [ ] Press **Stop**. **Install and restart** becomes clickable. + +## 5. Install + +- [ ] Press **Install and restart**. The banner shows "Downloading 1.1.0… nn%" with a progress bar, then the window closes and ProDHCPServer opens again by itself within a few seconds, with **no** UAC prompt. +- [ ] The log's first line says "ProDHCPServer 1.1.0 started (administrator)." +- [ ] In the folder, `ProDHCPServer.exe` is the new version (right-click → Properties → Details → Product version 1.1.0) and `ProDHCPServer.exe.old` is the test build. Close the app and delete the `.old` file. + +## Later, once a release with the updater is out + +When the release after this one is published, run the earlier release with the updater and check: + +- [ ] A few seconds after start, the green banner appears without pressing anything. +- [ ] **Skip this version**, then restart the app: no banner. **Check now** in Settings still offers it. +- [ ] Untick **Check for a new version when ProDHCPServer starts**, restart: no check in the log. +- [ ] After **Install and restart**, the log says "started (administrator) after updating." and `ProDHCPServer.exe.old` is gone within a few seconds. diff --git a/docs/microsoft-store.md b/docs/microsoft-store.md new file mode 100644 index 0000000..ebaf4b4 --- /dev/null +++ b/docs/microsoft-store.md @@ -0,0 +1,124 @@ +# Publishing ProDHCPServer in the Microsoft Store + +The Store signs MSIX packages itself, so a Store copy runs on laptops without SmartScreen's "Windows protected your PC" warning and without a code-signing certificate of our own. The GitHub exe carries on as before, unsigned. + +Facts below were checked against Microsoft's pages on 27 October 2026 (Store policies version 7.20, effective 22 October 2026). Sources are listed at the end. + +## The one thing that could stop it: administrator rights + +ProDHCPServer needs administrator rights for everything it does (changing adapter settings, firewall rules, listening on UDP port 67). Microsoft's packaging guide says apps that need elevation "won't be accepted into the Store". The capability that allows it, `allowElevation`, is "subject to approval under strict criteria", and Microsoft asks developers to email **reportapp@microsoft.com** with a detailed justification **before** submitting. + +So the first step is that email (draft below). Everything else in this guide only matters if Microsoft agrees. + +A Store listing of the plain exe doesn't avoid this: for an exe or MSI, policy 10.2.9 requires it to be signed with a certificate from a trusted certificate authority, which is what we're trying to avoid. + +## What the repository already does + +- **Every push** (Build and test workflow) builds a test MSIX with a placeholder identity, signs it with a throwaway certificate, installs it on the Windows runner, starts it, screenshots it (`msix-settings.png`) and uninstalls it. The package and its `.cer` are in the run's `ProDHCPServer-msix-test` artifact, for the hardware test (`docs/hardware-test-msix.md`). +- **The Release workflow** also builds the real Store package, `ProDHCPServer-vX.Y.Z-x64.msix`, once the three repository variables below are set. It's unsigned on purpose (the Store signs it) and lands in the run's `release-vX.Y.Z` artifact, not on the GitHub release page. +- **A Store copy doesn't update itself.** It detects that it's running from an MSIX package, hides the GitHub update check and Install button, and Settings > Updates says the Store installs updates. +- **Privacy policy:** `PRIVACY.md`, required for desktop apps by policy 10.5.1. Its URL is https://github.com/cookingwithsimon/ProDHCPServer/blob/main/PRIVACY.md once merged. + +## Steps only you can do + +### 1. Create the developer account (free) + +Registration is free for individuals. It needs a personal Microsoft account and an ID check (photo of a government ID plus a selfie). No credit card. + +1. Go to [Partner Center](https://partner.microsoft.com/dashboard) and sign up for the Microsoft Store as an **Individual** developer. (A company account is also free now, but needs business verification; an individual account is enough.) +2. Choose the publisher display name carefully: it shows on the Store page, for example "Simon Henley". + +### 2. Ask Microsoft about admin rights + +Send the email below from the address on your developer account. Wait for a yes before submitting. + +> **To:** reportapp@microsoft.com +> **Subject:** allowElevation justification for a new desktop app: ProDHCPServer +> +> Hello, +> +> I'm preparing to submit ProDHCPServer, a free desktop (WPF, full trust) app packaged as MSIX, and I'd like approval to use the allowElevation restricted capability. +> +> What the app does: it's a portable DHCP server for audio-visual field technicians. A technician plugs a laptop into a projector, display or control processor that has no network yet, presses Start, and the app gives the device an IP address so it can be configured. It also finds devices that already have a static address. +> +> Why it needs administrator rights (there's no unelevated alternative for these): +> - It changes the Ethernet adapter's IPv4 settings to a static address for the session, and puts the original settings back when the session stops, the app closes or after a crash. +> - It listens on UDP port 67 (DHCP server) and adds an inbound Windows Firewall rule for its own exe while serving, removed on stop. +> - It adds static ARP entries so a device can be reached before it has replied. +> +> How it elevates: it starts unelevated, explains in plain words why it needs administrator rights, and only then restarts itself with the standard UAC prompt. It installs no driver and no service. Packet capture for switch-port details (LLDP/CDP) is optional and uses Npcap only if the user has installed it separately. +> +> Source code: https://github.com/cookingwithsimon/ProDHCPServer +> Privacy policy: https://github.com/cookingwithsimon/ProDHCPServer/blob/main/PRIVACY.md +> +> Could you tell me whether this use would be approved, or what you'd need from me? +> +> Thanks, +> Simon + +### 3. Reserve the name + +Partner Center > **Apps and games** > **New product** > **MSIX or PWA app**, and reserve **ProDHCPServer**. Reserving is free and holds the name while you wait for Microsoft's answer. + +### 4. Copy the package identity into GitHub + +In Partner Center, open the app > **Product management** > **Product identity**. Copy three values into the repository's variables (GitHub > the repo > **Settings** > **Secrets and variables** > **Actions** > **Variables** tab > **New repository variable**). They're not secret. + +| Variable | Partner Center value | +|---|---| +| `STORE_IDENTITY_NAME` | Package/Identity/Name | +| `STORE_PUBLISHER` | Package/Identity/Publisher (starts with `CN=`) | +| `STORE_PUBLISHER_DISPLAY_NAME` | Package/Properties/PublisherDisplayName | + +### 5. Build the Store package + +Run **Actions** > **Release** > **Run workflow** with the version, as for any release (add `.github/release-notes/vX.Y.Z.md` first). When it finishes, download the run's `release-vX.Y.Z` artifact; the `.msix` is in its `store` folder. + +Each Store submission needs a higher version than the last one, so make a new release for each. + +### 6. Fill in the submission + +In Partner Center, start a submission for ProDHCPServer: + +- **Pricing and availability:** Free. Markets as you like. +- **Properties:** category **Developer tools** (or **Utilities & tools**), and the privacy policy URL from above. +- **Age ratings:** answer the questionnaire. It's a utility with no user content or chat. +- **Packages:** upload the `.msix` from step 5. +- **Store listing:** description below, plus screenshots. The CI smoke-test screenshots (`main-dark.png`, `main-light.png`, `settings-dark.png` on the `ci-screenshots` branch) are a good start. +- **Submission options > Restricted capabilities:** Partner Center asks why the package uses `runFullTrust` and `allowElevation`. Suggested text: + - *runFullTrust:* "ProDHCPServer is a full-trust WPF desktop app." + - *allowElevation:* "Changing the Ethernet adapter's IP settings, serving DHCP on UDP port 67 and adding a firewall rule need administrator rights. The app asks once at start with the standard UAC prompt. Discussed with reportapp@microsoft.com on [date]." +- **Notes for certification:** "No account or hardware needed to test. Start the app, choose Yes on the UAC prompt, choose a wired adapter and press Start. With nothing plugged in it shows 'Waiting for a device'. Npcap is optional; without it the app says so and only the switch-port details are missing." + +Submit. Certification can take several business days, and Microsoft emails the result. + +### Store description (draft) + +The first line is required: policy 10.2.4 says a dependency on other software must be disclosed at the start of the description. + +> Switch-port details (LLDP/CDP) need Npcap, a free separate download from npcap.com. Everything else works without it. +> +> ProDHCPServer is a portable DHCP server for AV field technicians. Plug your laptop into a projector, display, DSP or control processor, press Start, and see straight away whether it got an IP address, and if not, why. +> +> - Serves DHCP on the wired adapter you pick, and puts your adapter's settings back when you stop, close the app or after a crash. +> - Shows each device's manufacturer, address and a live ping graph. +> - Finds devices that already have a static IP and reaches their subnet in one click. +> - Saved profiles for subnet, pool, lease time and DHCP options (router, DNS, NTP, option 43/66/150 and custom options). +> - Plain-English status and troubleshooting, and a session log you can export. +> +> Needs administrator rights, because it changes adapter settings and serves DHCP. + +## What stays the same, and what to watch + +- The GitHub release exe keeps its own update checker. Store copies get updates from the Store. +- Npcap can't be bundled, because MSIX packages can't install drivers, so the app still offers the npcap.com link. +- Untested until the MSIX hardware test: whether the elevated restart from an MSIX install behaves exactly like the exe, and whether the firewall rule works with the app's install path under `C:\Program Files\WindowsApps`. Run `docs/hardware-test-msix.md` on the unmanaged laptop before submitting. +- Microsoft's packaging guide also discourages starting command-line tools, and the app runs `netsh` for adapter and firewall changes. Policy 7.20 doesn't forbid it, but certification might ask about it. + +## Sources + +- [Free developer registration for individual developers on Microsoft Store](https://blogs.windows.com/windowsdeveloper/2025/09/10/free-developer-registration-for-individual-developers-on-microsoft-store/) (Windows Developer Blog, September 2025) +- [Publish to Microsoft Store as a company, now with free registration](https://blogs.windows.com/windowsdeveloper/2026/05/07/publish-to-microsoft-store-as-a-company-now-with-free-registration-and-faster-onboarding/) (Windows Developer Blog, May 2026) +- [Microsoft Store Policies](https://learn.microsoft.com/windows/uwp/publish/store-policies), version 7.20: 10.2.3, 10.2.4, 10.2.9, 10.5.1, 10.6 +- [App capability declarations](https://learn.microsoft.com/windows/apps/package-and-deploy/app-capability-declarations): allowElevation and runFullTrust +- [Prepare to package a desktop application](https://learn.microsoft.com/windows/msix/desktop/desktop-to-uwp-prepare): elevation and command-line utilities diff --git a/packaging/msix/AppxManifest.xml b/packaging/msix/AppxManifest.xml new file mode 100644 index 0000000..efb9847 --- /dev/null +++ b/packaging/msix/AppxManifest.xml @@ -0,0 +1,50 @@ + + + + + + + + ProDHCPServer + $PublisherDisplayName$ + Images\StoreLogo.png + Portable DHCP server for AV field technicians. + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/msix/Images/Square150x150Logo.png b/packaging/msix/Images/Square150x150Logo.png new file mode 100644 index 0000000..101f62f Binary files /dev/null and b/packaging/msix/Images/Square150x150Logo.png differ diff --git a/packaging/msix/Images/Square44x44Logo.png b/packaging/msix/Images/Square44x44Logo.png new file mode 100644 index 0000000..7932c26 Binary files /dev/null and b/packaging/msix/Images/Square44x44Logo.png differ diff --git a/packaging/msix/Images/StoreLogo.png b/packaging/msix/Images/StoreLogo.png new file mode 100644 index 0000000..5dc3d20 Binary files /dev/null and b/packaging/msix/Images/StoreLogo.png differ diff --git a/packaging/msix/Images/Wide310x150Logo.png b/packaging/msix/Images/Wide310x150Logo.png new file mode 100644 index 0000000..9c811b3 Binary files /dev/null and b/packaging/msix/Images/Wide310x150Logo.png differ diff --git a/src/ProDHCPServer.App/App.xaml.cs b/src/ProDHCPServer.App/App.xaml.cs index 7a3dbce..0f2a78b 100644 --- a/src/ProDHCPServer.App/App.xaml.cs +++ b/src/ProDHCPServer.App/App.xaml.cs @@ -42,7 +42,10 @@ protected override void OnStartup(StartupEventArgs e) return; } - _singleInstance = new Mutex(true, @"Global\ProDHCPServer.SingleInstance", out bool first); + _singleInstance = new Mutex(true, SingleInstanceName, out bool first); + // Started by an update: the previous version is still closing, so give it time to let go. + bool updated = e.Args.Contains(UpdateViewModel.UpdatedFlag); + if (!first && updated) first = WaitForPreviousVersion(_singleInstance); if (!first) { MessageBox.Show("ProDHCPServer is already running. Two copies would fight over the adapter, so this one will close.", @@ -52,7 +55,9 @@ protected override void OnStartup(StartupEventArgs e) } _log = new SessionLog(); - _log.Add(LogSeverity.Info, LogCategory.App, $"ProDHCPServer {Version} started (administrator)."); + _log.Add(LogSeverity.Info, LogCategory.App, updated + ? $"ProDHCPServer {Version} started (administrator) after updating." + : $"ProDHCPServer {Version} started (administrator)."); var adapters = new WindowsAdapterControl(); var sessions = new AdapterSessionManager(adapters, new FileSessionStore(Path.Combine(DataFolder, "adapter-backup.json"))); _controller = new ServerController(adapters, sessions, _log, Version); @@ -78,6 +83,27 @@ protected override void OnStartup(StartupEventArgs e) window.Show(); } + private const string SingleInstanceName = @"Global\ProDHCPServer.SingleInstance"; + + /// + /// Lets go of the one-copy lock just before an update starts the new version, so it can start even if + /// it's an older build without . undoes it. + /// + public void ReleaseSingleInstance() + { + _singleInstance?.ReleaseMutex(); + _singleInstance?.Dispose(); + _singleInstance = null; + } + + public void RetakeSingleInstance() => _singleInstance ??= new Mutex(true, SingleInstanceName, out _); + + private static bool WaitForPreviousVersion(Mutex mutex) + { + try { return mutex.WaitOne(TimeSpan.FromSeconds(30)); } + catch (AbandonedMutexException) { return true; } // it exited without releasing: the mutex is ours now + } + private void OnUiException(object sender, DispatcherUnhandledExceptionEventArgs e) { // Keep running: show the error rather than vanish with the adapter half-configured. diff --git a/src/ProDHCPServer.App/MainWindow.xaml b/src/ProDHCPServer.App/MainWindow.xaml index 34fd4f9..1c7e74a 100644 --- a/src/ProDHCPServer.App/MainWindow.xaml +++ b/src/ProDHCPServer.App/MainWindow.xaml @@ -144,6 +144,35 @@ + + + + + + + + +