- Hệ sinh thái phát triển ứng dụng native trên Windows, do sự đứt gãy framework và việc tái thiết kế lặp đi lặp lại kéo dài suốt nhiều thập kỷ, đến năm 2025 vẫn chưa mang lại năng suất phát triển thực chất
- Từ Win32, MFC, WinForms, WPF, WinRT, UWP cho tới WinUI 3, dù đã trải qua 7 giai đoạn chuyển đổi framework UI, vẫn có rất nhiều trường hợp mà chỉ dùng API mới nhất thì ngay cả chức năng cơ bản cũng không thể triển khai được
- Những tính năng thường ngày như biểu tượng khay hệ thống, chặn phím tắt toàn cục vẫn phải phụ thuộc vào lời gọi Win32 thông qua P/Invoke, làm phai nhạt ý nghĩa của việc áp dụng framework hiện đại
- Ngay cả khi build một ứng dụng tiện ích đơn giản bằng biên dịch .NET AOT, vẫn tạo ra binary lớn hơn 9 MiB, và chứng chỉ ký mã để phân phối MSIX là một rào cản thực tế với chi phí $200–300 mỗi năm
- Việc chính các ứng dụng chủ lực của Microsoft như VS Code, Outlook, Start Menu đều được xây dựng bằng công nghệ web cho thấy phát triển native trên Windows không còn là ưu tiên ngay cả bên trong Microsoft
Bối cảnh: đã làm gì
- Trong quá trình phát triển ứng dụng tiện ích chỉ dành cho Windows “Display Blackout”, những vấn đề của môi trường phát triển ứng dụng native hiện tại đã bộc lộ rõ
- Ứng dụng này cung cấp chức năng phủ lớp màu đen để tắt hai màn hình bên trái và phải khi chơi game trong môi trường nhiều màn hình
- Các chức năng cần thiết gồm liệt kê màn hình, tính toán biên, xử lý phím tắt toàn cục, hiển thị biểu tượng khay hệ thống, tự khởi động cùng hệ thống, lưu cài đặt
- Dù đã có script AutoHotkey và ứng dụng trên Microsoft Store, tác giả vẫn thử tự phát triển để học tập và cải thiện UI
- Kết quả là xác nhận rằng môi trường phát triển ứng dụng native trên Windows cực kỳ phức tạp và kém hiệu quả
Lịch sử lập trình Windows
- Ban đầu, lựa chọn duy nhất là Win32 API dựa trên C, và API này đến nay vẫn còn hiệu lực
- MFC dựa trên C++ bổ sung lớp trừu tượng hướng đối tượng như class và template lên trên Win32
- Với .NET 1.0 (2002), ngôn ngữ C#, VM bytecode JIT, quản lý bộ nhớ tự động xuất hiện; Windows Forms là lớp bọc cho API cửa sổ và control của Win32
- WPF của .NET 3.0 (2006) giới thiệu ngôn ngữ đánh dấu XAML và là nỗ lực đầu tiên nhằm giảm phụ thuộc vào Win32 bằng render control dựa trên GPU
- WinRT của Windows 8 (2012) đưa vào mô hình ứng dụng sandbox, nhắm tới hợp nhất desktop, tablet và phone, nhưng cấu trúc XAML lại khác WPF một cách tinh vi nên gây thêm hỗn loạn
- UWP của Windows 10 (2015) nới lỏng một phần hạn chế sandbox nhưng vẫn không đạt được mức quyền desktop như WPF; một số tính năng hệ điều hành (push notification, live tile, phân phối qua Microsoft Store) vẫn bị giới hạn cho WinRT/UWP
- Đây là nguyên nhân khiến các ứng dụng cũ như Chrome, Microsoft Office phải dùng kiến trúc gượng gạo kiểu bridge WinRT/UWP kết nối qua IPC
- Windows App SDK của Windows 11 (2021) mở các tính năng vốn dành riêng cho WinRT/UWP cho cả ứng dụng C++ chuẩn và .NET, đồng thời bao gồm thư viện control dựa trên XAML mới là WinUI 3
- Tóm tắt tiến hóa framework UI:
> Win32 C APIs → MFC → WinForms → WPF → WinRT XAML → UWP XAML → WinUI 3
Thế tiến thoái lưỡng nan khi chọn cách phát triển
- Có ba con đường để phát triển ứng dụng WinUI 3:
- C++: binary gọn nhẹ, interop dễ với Win32 C API — nhưng không có an toàn bộ nhớ
- C#/XAML + phân phối phụ thuộc framework: ngay cả trên Windows 11 mới nhất cũng chỉ cài sẵn .NET 4.8.1, nên khi cài lần đầu sẽ hiện hộp thoại tải thư viện .NET, mang lại trải nghiệm người dùng rất tệ
- C#/XAML + .NET AOT: nhúng toàn bộ runtime .NET (VM, GC, thư viện chuẩn) vào binary — ngay cả ứng dụng đơn giản cũng tạo ra binary trên 9 MiB
- Nỗ lực duy trì binding cho Rust (
windows-app-rs) đã bị lưu trữ (archived) - Cách phân phối cũng là một nỗi đau chọn lựa:
- Định dạng MSIX yêu cầu chứng chỉ ký mã, với chi phí $200–300 mỗi năm nếu sống ngoài Mỹ
- Sideload không ký yêu cầu những lệnh PowerShell khó hiểu chỉ dùng được trong terminal quản trị
- Đăng ký lên Microsoft Store bị từ chối với lý do không cung cấp “giá trị độc đáo và bền vững”
Những tính năng mà ngay cả SDK hiện đại cũng không làm được
| Tính năng | Windows App SDK có hỗ trợ không |
|---|---|
| Liệt kê màn hình | Hỗ trợ một phần (foreach loop không dùng được, phát hiện thay đổi cần P/Invoke) |
| Đặt cửa sổ đen không kích hoạt | Hỗ trợ một phần (non-activating cần P/Invoke) |
| Chặn phím tắt bàn phím toàn cục | Không thể — cần P/Invoke |
| Tự khởi động cùng hệ thống | Có thể (có API tích hợp với cài đặt hệ thống) |
| Lưu cài đặt bền vững | Có thể |
| Biểu tượng khay hệ thống + menu | Không thể — cần P/Invoke, kiểu menu không chuẩn hóa |
- Kiểu menu của biểu tượng khay hệ thống khác nhau ở từng ứng dụng, không có chuẩn nhất quán trên toàn hệ điều hành
- Trong quá trình từ WPF sang WinUI 3, ngay cả tính năng cơ bản như tự điều chỉnh kích thước cửa sổ cũng đã biến mất
Những giới hạn mang tính cấu trúc của interop giữa C# và Win32
- Công cụ P/Invoke hiện đại CsWin32 có lỗi không thể bọc đúng chuỗi bên trong struct
- Tài liệu CsWin32 nêu rõ rằng kiểu tham số cơ bản của Win32 API là
[optional, out], nhưng C# không có cách biểu đạt tự nhiên, nên phải sinh ra hai phiên bản của cùng một method - Đến nay, gần 20 năm sau khi WPF ra mắt (2006), phần boilerplate để viết class phục vụ data binding UI hầu như không được cải thiện
- Vẫn phải lặp đi lặp lại việc chuyển mọi property thành cặp getter/setter, thêm guard khi cùng giá trị, gọi sự kiện phát sinh thay đổi
- Trong suốt 20 năm, C# không bổ sung giải pháp ở cấp độ ngôn ngữ tương đương decorator/proxy của JavaScript
- Changelog của CsWin32 nghèo nàn và dự án vẫn chưa vượt qua phiên bản 1.0, nên trông có vẻ có khả năng bị bỏ dở trong vài năm tới
Kết luận: vì sao Electron mới là câu trả lời
- Hiện tại Microsoft không ưu tiên phát triển ứng dụng native
- Trình theo dõi issue liên quan đầy lỗi và báo cáo nhưng gần như không có phản hồi từ kỹ sư Microsoft
- Changelog của Windows App SDK chủ yếu xoay quanh việc thêm API machine learning
- Việc các ứng dụng chủ lực của Microsoft như VS Code, Outlook, Start Menu đều được xây dựng bằng công nghệ web là bằng chứng rõ ràng
- Cộng đồng đang chuyển sang các framework UI bên thứ ba như Avalonia, Uno Platform
- Chúng kế thừa triết lý WPF và tăng cường hỗ trợ đa nền tảng
- Ở thời điểm hiện tại, framework dựa trên web như Electron hay Tauri là lựa chọn thực tế hơn
- Tổ hợp TypeScript/React/CSS cho năng suất cao hơn C#/XAML
- Đồng thời vẫn truy cập được Win32 API
-
Tauri** sử dụng** WebView hệ thống** nên**không cần bundle Chromium
- Runtime WebView2 cập nhật mỗi 4 tuần, trong khi .NET hệ thống bị cố định ở 4.8.1
- Nếu Microsoft thúc đẩy cải thiện Windows App SDK và đơn giản hóa hệ thống phân phối thì vẫn có khả năng phục hồi
- Nhưng hiện tại đa số nhà phát triển không còn kỳ vọng
- Kết lại bằng nhận định: “tôi sẽ chọn web stack”
- Thông báo gần đây của Microsoft về cam kết tập trung vào chất lượng Windows có nhắc tới việc sẽ dùng WinUI 3 nhiều hơn trên toàn bộ hệ điều hành, nhưng chưa rõ liệu điều đó có dẫn tới cải thiện thực chất hay không
3 bình luận
Nhờ được chuẩn hóa bằng Electron nên vậy...
Không biết bao giờ mới có WYSIWYG cho WinUI 3 nữa.
Ý kiến trên Hacker News
Tôi cũng nghĩ giống nhiều người khác rằng cứ bám vào Win32 là đúng
Từ góc nhìn của người đã phát triển với Win32 suốt thời gian dài, những tính năng cần thiết đều có thể triển khai đầy đủ trong một file thực thi độc lập dưới 8KB
Liệt kê màn hình, tạo cửa sổ, hook phím tắt, đăng ký chạy cùng hệ thống, lưu thiết lập, hiển thị biểu tượng khay hệ thống... tất cả đều làm được chỉ với vài lệnh gọi API cỡ vài trăm byte
Nhưng đến năm 2026 mà còn viết dự án mới bằng ngôn ngữ không an toàn bộ nhớ (C++) thì khá lỗi thời
Tuy vậy, nếu là ứng dụng hầu như không nhận đầu vào không đáng tin cậy thì cũng không nhất thiết phải bị cuốn theo tuyên truyền
_UNICODE, bạn có thể làm cùng một thứ trong .NET Framework với một nửa thời gianTôi nghĩ phong trào “NoFramework” nên quay lại để đưa chúng ta trở về thời RAD
Nhưng chọn C++ cho dự án mới thì vẫn nên cân nhắc kỹ
Bạn vẫn có thể dùng Win32 từ các ngôn ngữ an toàn bộ nhớ — ví dụ windows-rs
Hồi đó Borland Delphi là công cụ phổ biến nhất
Nếu không phải ứng dụng WinRT, UAP hay UWP sẵn có thì nên tránh WinUI 3.0 và WinAppSDK
Tốt hơn là tiếp tục dùng các công nghệ đã được kiểm chứng như Win32, MFC, WinForms, WPF,
còn nếu ở ngoài hệ sinh thái Microsoft thì có thể cân nhắc Qt, VCL, Firemonkey, Avalonia, Uno, ImGUI...
WinUI 3.0 tệ đến mức ngay cả Microsoft cũng đang tính chuyển nó sang cộng đồng dưới dạng mã nguồn mở
Sau đó WinJS chuyển thành framework web mã nguồn mở nên hỗ trợ chính thức cũng bị cắt
Bài blog liên quan
Tôi là lập trình viên nhúng, và việc làm chương trình GUI Win32 để giao tiếp với thiết bị vẫn rất dễ
Mã thời XP vẫn chạy nguyên vẹn trên Windows 11, và ngay cả khi mở dự án VC6 bằng Visual Studio 2022 thì vẫn build bình thường
Kiểu tương thích ngược này rất khó thấy ở nền tảng khác
Cocoa của Apple có cấu trúc thì “thanh lịch” nhưng thực tế lại phức tạp và tài liệu cũng không thân thiện
Win32 API thuần vẫn là một lựa chọn thực dụng
Nếu tự làm một wrapper kiểu MFC bằng C++ thì có thể hoàn thành trong 2~3 tuần, và sau đó bạn sẽ có toàn quyền kiểm soát
Nhờ khả năng tương thích ngược mạnh mẽ của Microsoft, các ứng dụng dựa trên Win32 ổn định về lâu dài
Có thể xem một ví dụ đã được cập nhật hơn 10 năm tại đây
Màu hệ thống và control bị hard-code nên xung đột với giao diện tối
Chỉ một số phần UI như menu, hộp thoại thông báo, hộp thoại chọn file... hỗ trợ dark mode nên tổng thể thiếu nhất quán
Có thể tham khảo thảo luận liên quan trong bài này
Hiện nó vẫn đang được duy trì dưới dạng mã nguồn mở và đã có đến phiên bản 10
Theo kinh nghiệm từng làm nhiều ứng dụng Windows,
(1) Win32 API tuy cũ nhưng cực kỳ ổn định, và
(2) nên tránh các UI toolkit do Microsoft sở hữu — cuối cùng rồi cũng sẽ cần mức kiểm soát kiểu Win32
Trong 20 năm qua, phần lớn công nghệ UI do Microsoft tạo ra thực chất đều là biến thể của WPF
Nếu họ tiếp tục phát triển WPF thì có lẽ giờ nó đã trở thành chuẩn mực của phát triển UI
Từ góc nhìn người dùng, ứng dụng native thì nhanh và tốt, nhưng quá trình phát triển đúng là một mớ hỗn độn phức tạp
Đây cũng là lý do các ứng dụng như Outlook và Teams ngày càng tệ hơn
Rất khó bắt chước cảm giác native ở các mặt như focus, điều hướng bàn phím...
Tham khảo dự án Electrobun
Tôi không đồng ý với câu “làm dự án mới bằng C++ là tội ác”
Với GUI, hiệu năng và khả năng kiểm soát quan trọng hơn độ an toàn, và C++ vẫn là ngôn ngữ đã được kiểm chứng
Qt vẫn là một trong những framework GUI tốt nhất vào năm 2026, và có tích hợp các tính năng an toàn bộ nhớ
Tôi thắc mắc vì sao .NET runtime mới nhất không được cài sẵn trong Windows 11
Điều này trông như một ví dụ nữa cho thấy Microsoft đã từ bỏ trải nghiệm người dùng nhất quán
nên việc phân phối tất cả qua Windows Update là không thực tế
Thay vào đó có thể phát hành file thực thi độc lập được biên dịch AOT (khoảng 9MiB)
Nó nhỏ và hiệu quả hơn Electron rất nhiều
Giờ đóng gói kèm DLL vẫn tốt hơn
nên khó tích hợp vào hệ điều hành
Họ tách nó khỏi cập nhật OS để duy trì chu kỳ phát hành nhanh
.NET Core thì phải cài riêng
Lâu rồi tôi mới thử làm ứng dụng cho Windows và Mac bằng Tauri,
việc phát triển và build thì dễ nhưng vấn đề ký mã khiến đồng nghiệp của tôi không cài được
Trên Mac có thể giải quyết bằng lệnh terminal, nhưng trên Windows thì phải tắt Smart App Control
mà tính năng này không thể bật lại nếu không cài mới hệ thống
Tôi hiểu mục đích bảo mật, nhưng không ngờ quá trình cài đặt lại khó đến vậy
Câu trả lời cho câu hỏi “tại sao không dùng Electron” rất đơn giản —
ứng dụng Electron cho trải nghiệm người dùng tệ
Phát triển thì dễ nhưng phải đánh đổi hiệu năng và chất lượng
Nếu muốn làm ra sản phẩm tốt thì dù khó vẫn nên chọn native
Cá nhân tôi thấy C# tốt hơn TypeScript rất nhiều