Як я завів WPF-застосунок у winget і Microsoft Store — і баг автозапуску, що вилазить тільки в MSIX

💡 Усі статті, обговорення, новини про .NET — в одному місці. Приєднуйтесь до .NET спільноти!

Я підтримую CapyBro — невеликий open-source застосунок для Windows (.NET 8 / WPF), що переписує чи перекладає виділений текст за допомогою AI по глобальному хоткею. Цього тижня він отримав два апгрейди дистрибуції, і один із них витягнув на поверхню баг, якого взагалі не видно, поки не запакуєш застосунок. Ділюся обома — раптом ви теж пакуєте десктопний .NET.

1. Тепер є у winget

winget install RomanTykhonenko.CapyBro

PR у microsoft/winget-pkgs змерджили після стандартної автовалідації плюс перегляду живого модератора (New-Package завжди дивиться людина). Кілька нотаток, що зекономлять вам час:

  • Маніфест я генерував через wingetcreate — він сам робить схему, SHA256 і device-flow авторизацію, щоб відкрити PR. Набагато менше шансів помилитись, ніж писати YAML руками.
  • Мій NSIS-інсталер без підпису — і все одно пройшов валідацію чисто, без warning-лейблів. winget не вимагає code signing, щоб потрапити в реєстр. (SmartScreen при першому запуску — окрема історія для кінцевого юзера, не воротар winget.)
  • Від подачі до мерджу — кілька днів. Бот робить основну роботу, ти переважно чекаєш на модератора.

Оновлення потім — однорядково:

wingetcreate update RomanTykhonenko.CapyBro --version <X> --urls <url> --submit

2. Баг автозапуску, який існує тільки в запакованому застосунку

Збірка для Microsoft Store запакована в MSIX. Звичайний .exe робить автозапуск класикою: пише в HKCU\Software\Microsoft\Windows\CurrentVersion\Run. Працює, так їздило роками.

Усередині MSIX-пакета це тихо перестає працювати. Записи в цей Run-ключ віртуалізуються в приватну в’юху пакета, і Windows не шанує віртуалізований Run-запис для старту при вході. Тобто юзер вмикає «Запускати при вході», застосунок слухняно пише ключ, рапортує успіх... і ніколи не стартує при наступному вході. Жодної помилки, нічого в логах.

Фікс — визначати в рантаймі, чи ти запакований, і перемикати backend:

  • Детект: P/Invoke GetCurrentPackageFullName. Повертає APPMODEL_ERROR_NO_PACKAGE, коли unpackaged, і успіх — коли packaged. Один цей boolean і обирає реалізацію.
  • Packaged-backend: WinRT-API Windows.ApplicationModel.StartupTask + розширення windows.startupTask у маніфесті (з uap10:Parameters, щоб передати той самий silent-прапор, що й .exe). Тепер startup-записом володіє ОС — юзер навіть може тоглити його з Параметри → Застосунки автозапуску.
  • Unpackaged-backend: оригінальний писач Run-ключа, незмінний.

Загорнути це за IStartupTaskBackend, який обирається рантайм-перевіркою, означало, що .exe зберіг свою точну стару поведінку, і лише Store-білд отримав новий шлях — нульовий ризик зламати те, що вже працювало.

Каверза в каверзі: підтягування WinRT-проєкції (Windows.ApplicationModel.*) піднімає TFM до чогось типу net8.0-windows10.0.17763.0 і тягне за собою чималу SDK-проєкцію. Я не хотів, щоб легкий .exe ніс це на собі, тож проєкт мультитаргетиться: звичайний Win32-білд виключає WinRT-файли через #if, і лише packaged-таргет їх компілює.

3. Нативний ARM64

Перепаковуючи, я додав нативну ARM64-збірку (win-arm64, ReadyToRun, крос-компіляція на x64-хості) другим пакетом у тій самій Store-сабмішн. WPF працює нативно на ARM64 .NET 8, тож юзери Surface / Snapdragon тепер минають шар x64-емуляції. Чесне застереження: ARM-заліза я не маю, тож воно поїхало smoke-тестованим на боці збірки, але не на реальному пристрої — якщо ви на Windows-on-ARM, я був би щиро вдячний за перевірку.

winget для CLI-народу; Store-білд, що реально автостартує й працює нативно на ARM64. Код під MIT, якщо схочете поколупати: github.com/phantasmat2018/capy-bro · capybro.app. З радістю відповім на питання по winget чи MSIX у коментарях.

👍ПодобаєтьсяСподобалось1
До обраногоВ обраному1
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Підписатись на коментарі