GUI на Windows — выбор стека
GUI на Windows — выбор стека
О чём эта глава
Если у проекта в Rust появляется требование "нужно полноценное окно на рабочем столе Windows", быстро встаёт вопрос выбора стека. Вариантов много, и у каждого свой компромисс по скорости разработки, интеграции с ОС и поддержке.
GUI (Graphical User Interface) — окна, кнопки, поля ввода, меню. На Windows интерфейс можно строить по-разному: через системные API Microsoft, через кроссплатформенные библиотеки на Rust или через гибрид (логика на Rust, картинка в WebView).
Цель статьи — помочь выбрать стек и понять логику выбора. Для старта в Rust разумнее первая программа и при необходимости веб-API на Axum; GUI подключают, когда продукту действительно нужен desktop-интерфейс.
Обзор: приложения на Rust · фреймворки · нативный код: FFI.
Базовые термины
| Термин | Простыми словами |
|---|---|
| Нативный UI | Рисует система Windows (кнопки выглядят как в других программах ОС). |
| Собственный рендер | Фреймворк сам рисует интерфейс (OpenGL, WGPU, свой движок). |
| WebView | В окне встроен мини-браузер (HTML/CSS/JS), Rust — "бэкенд". |
| HWND | Идентификатор окна в Win32. |
| Цикл сообщений | Бесконечный цикл: ОС присылает события (клик, закрытие), программа их обрабатывает. |
| COM / WinRT | Модель объектов Microsoft для современных API (WinUI, часть системных служб). |
Карта вариантов
| Подход | Плюсы | Минусы |
|---|---|---|
| Win32 / windows-rs | максимальная интеграция с ОС, без лишних слоёв | много кода, ручной цикл сообщений, много unsafe |
| WinUI 3 / WinRT | современный Fluent, Microsoft Store | в основном Windows, крутая кривая COM |
| Tauri | знакомый HTML/CSS, относительно малый установщик | WebView2, настройка IPC и прав |
| Slint / Iced / egui | UI на Rust, кроссплатформа | свой виджетный набор, реже "родные" контролы |
| Dioxus + WebView | React-подобная модель | молодая экосистема, API меняется |
Когда имеет смысл нативный API (Win32, windows-rs)
Подходит, если нужно:
- встроить Rust-модуль в существующее Win32-приложение;
- вызвать редкий системный API без готовой safe-обёртки;
- минимальный размер и нулевая зависимость от WebView.
Типичная схема: crate windows или windows-sys даёт объявления функций; тонкий слой unsafe изолируют в одном модуле; бизнес-логика остаётся на safe Rust (FFI и дисциплина). Цикл GetMessage / DispatchMessage держат в одном месте; обработчики WM_* остаются короткими.
Для первого знакомства с языком ручной Win32 — тяжёлый старт. Сначала освойте Cargo и ownership, затем возвращайтесь к нативному UI при явной необходимости.
Когда Tauri или другой WebView
- команда уже пишет интерфейс на React / Vue / Svelte;
- нужен установщик под Windows, macOS и Linux из одной кодовой базы;
- важны автообновления, системные диалоги, разграничение прав.
Rust отвечает за файлы, сеть, криптографию, работу с ОС; UI живёт в изолированном WebView. Безопасность строят на явном списке команд (capabilities): JavaScript не получает произвольный доступ к диску — только то, что вы экспортировали в Rust.
На Windows Tauri опирается на WebView2 (движок Edge Chromium). На свежих Windows 10/11 runtime часто уже установлен; иначе нужен bootstrap-установщик Microsoft. Это компромисс: полный Electron не тащите, но компонент WebView2 остаётся зависимостью.
Команда Rust в Tauri (IPC):
#[tauri::command]
fn read_config() -> Result<String, String> {
std::fs::read_to_string("config.json").map_err(|e| e.to_string())
}
{
"permissions": [
"core:default",
"fs:allow-read-text-file"
]
}
Разбор:
#[tauri::command]экспортирует Rust-функцию для вызова из JavaScript.read_configчитает файл и возвращаетResult, чтобы ошибки были явными.- JS не получает прямой доступ к диску: только через разрешённые команды.
- Блок
permissionsв capabilities ограничивает, что можно делать из UI. - Такой подход снижает риск произвольного доступа к файловой системе.
Когда Slint, Iced, egui
- интерфейс должен выглядеть одинаково на Linux, macOS и Windows;
- нельзя или нежелательно тянуть Chromium/WebView2;
- HMI, встраиваемые панели, внутренние утилиты.
| Фреймворк | Идея |
|---|---|
| Slint | декларативные .slint-файлы, компиляция в Rust |
| Iced | архитектура в духе Elm, рендер через wgpu/OpenGL |
| egui | immediate mode — удобно для редакторов и отладочных панелей |
"Immediate mode" в egui значит: каждый кадр вы заново описываете, какие кнопки нарисовать; состояние храните сами. Подходит для инструментов, где важна скорость разработки, а не пиксель-перфект как у системных диалогов.
Минимальный пример egui (eframe):
Код ITЗагрузка примера кода…
Разбор:
eframe::run_nativeсоздаёт окно и запускает UI-цикл.MyAppхранит состояние интерфейса (clicks).updateвызывается каждый кадр и перерисовывает панель.ui.button(...).clicked()обрабатывает нажатие кнопки.ui.label(...)показывает текущее значение счётчика.
Подключение:
cargo add eframe
Разбор:
- Команда добавляет зависимость в
Cargo.tomlи скачивает crate. - После этого можно сразу собирать и запускать GUI-пример.
- Для Windows обычно достаточно стандартного toolchain Rust.
- Версию
eframeлучше фиксировать осознанно при переходе в продакшен. - Это самый быстрый способ получить живое окно для прототипа.
Практическая рекомендация по сценарию
- Утилита или прототип — egui (
eframe) или Iced: быстрый старт, одинcargo add. - Продукт с веб-командой — Tauri.
- Промышленный HMI, встраиваемые экраны — Slint.
- Интеграция в Win32/COM legacy — windows-rs + FFI.
- Microsoft Store, Fluent, глубокая интеграция с Windows 11 — WinUI 3 (отдельная траектория; опыт C#/C++ с XAML сильно помогает).
Частые ошибки
| Симптом | Вероятная причина | Что сделать |
|---|---|---|
| WebView2 missing | на машине нет runtime | установить WebView2 Runtime или bootstrap из документации Tauri |
Паника в Win32 unsafe | неверный HWND или вызов не из UI-потока | проверить поток создания окна; Win32 UI обычно однопоточный |
| Tauri IPC denied | команда не в allowlist capabilities | добавить команду в конфиг capabilities |
| Размытый egui на 4K | DPI scaling | настроить with_pixels_per_point в eframe |
Что попробовать руками
- egui — проект
eframe, одно окно с кнопкой (cargo add eframe). - Tauri — шаблон
create-tauri-app, сравните размер установки с Electron. - Логику без UI сначала вынесите в библиотеку и проверьте через Axum или тесты — UI подключите позже.
Разделение "ядро без UI" + desktop-оболочка:
// crates/core/src/lib.rs
pub fn build_report(input: &str) -> String {
format!("Отчёт: {}", input.trim())
}
// ui/main.rs (egui/tauri/win32 — неважно)
let text = core::build_report("заказ #42");
Разбор:
- Бизнес-логика живёт в отдельном crate и не зависит от GUI-фреймворка.
- UI-слой только отображает результат и обрабатывает события пользователя.
- Один и тот же
coreможно тестировать unit-тестами и через HTTP API. - При смене стека (egui -> Tauri) переписывается в основном UI-обвязка.
- Это снижает стоимость экспериментов со стеком на раннем этапе.
Критерии выбора для команды
Перед стартом полезно зафиксировать несколько критериев, чтобы решение было инженерным, а не "по вкусу":
| Критерий | Что спросить |
|---|---|
| Команда | кто будет делать UI: web-разработчики или системные разработчики |
| Сроки | нужен быстрый MVP или долгий продуктовый цикл |
| Платформы | только Windows или сразу Windows/macOS/Linux |
| Деплой | корпоративный MSI, Store, portable-архив |
| Интеграция с ОС | нужны ли deep-link, tray, COM, системные уведомления, драйверы |
Эта таблица помогает обосновать выбор стека перед архитекторами и продуктом.
Поддержка и эксплуатация
У desktop-приложений много полевых нюансов:
- автообновления и откат версии при неудачном релизе;
- сбор crash-логов и телеметрии;
- проверка подписи бинарников;
- политика обновления WebView2 в корпоративной сети.
Эти вопросы влияют на выбор стека не меньше, чем синтаксис API.
Мини-чек-лист перед началом разработки
- Выбран baseline Windows (10/11, версия сборки).
- Описан способ установки и обновления.
- Согласован формат логов и канал отправки ошибок.
- Ядро логики вынесено в отдельный crate без UI.
- Есть пилотный экран и замер запуска на слабой машине.
Если пройти этот список в начале, проект по GUI обычно проходит интеграцию заметно спокойнее.
Связанные материалы
- Экосистема приложений
- Фреймворки и инструменты
- FFI на практике
- Системное программирование
- Тестирование