14 điểm bởi GN⁺ 2026-03-23 | 3 bình luận | Chia sẻ qua WhatsApp
  • 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đơ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...

 
carnoxen 2026-03-23

Không biết bao giờ mới có WYSIWYG cho WinUI 3 nữa.

 
GN⁺ 2026-03-23
Ý 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

    • Nếu muốn tránh các vấn đề về an toàn bộ nhớ và _UNICODE, bạn có thể làm cùng một thứ trong .NET Framework với một nửa thời gian
    • Trước đây các lớp mỏng như Delphi hay MFC giải quyết được chuyện này, nhưng giờ chúng đã hết thời và không có phương án thay thế
      Tôi nghĩ phong trào “NoFramework” nên quay lại để đưa chúng ta trở về thời RAD
    • Win32 vẫn có tài liệu và công cụ rất phong phú, và sẽ còn tồn tại rất lâu nữa
      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
    • Tôi tò mò không biết phải làm thế nào để ứng dụng Win32 trông đẹp mắt trong mắt người dùng phổ thông
    • Tôi cũng tự hỏi các lập trình viên Winamp đã làm thế nào để tạo ra một ứng dụng Win32 xuất sắc như vậy
      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ở

    • Trước đây tôi từng làm ứng dụng Windows 8 bằng WinJS và đưa lên Windows Store
      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
    • Gần đây có bài blog công bố rằng “trải nghiệm cốt lõi của Windows sẽ được chuyển sang WinUI3”, nghe thì là để cải thiện chất lượng nhưng vẫn thấy bất an
      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

    • Tôi thà tiếp tục dùng mã Win32 thô ráp còn hơn
      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
    • Lập trình viên ngày nay đã quen với hệ sinh thái thay đổi hàng tuần, nên thường có xu hướng nghĩ rằng cái gì cũ là “không còn được bảo trì”
    • Tuy vậy, các vấn đề như DPI độ phân giải cao hay xử lý đầu vào vẫn còn khá rắc rối
    • Thách thức lớn nhất là chuyển hoàn toàn từ 32-bit sang 64-bit
    • Có quá nhiều cách định nghĩa chuỗi nên rất dễ rối
  • 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

    • Hỗ trợ dark mode là vấn đề lớn nhất
      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ách tiếp cận này không thể tạo ra UI theo phong cách Windows 11
      Có thể tham khảo thảo luận liên quan trong bài này
    • Trước đây tôi từng dùng WTL 3.0, nó nhẹ hơn MFC rất nhiều mà vẫn truy cập được toàn bộ tính năng Win32
      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
    • Nếu thiết kế API của wrapper kiểu MFC tốt, AI thậm chí có thể viết phần triển khai thay bạn
    • Cũng có ý kiến rằng thà dùng C++ Builder hay Delphi còn hơn
  • 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

    • Tuy vậy, WPF và WinForms là ngoại lệ khá ổn định
      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

    • Trớ trêu là Outlook và Teams lại gặp các vấn đề đó vì chúng dựa trên web app (Electron)
      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...
    • Tôi cũng dùng tổ hợp TypeScript + Bun + Electrobun khi làm công cụ cá nhân
      Tham khảo dự án Electrobun
    • Ngay cả Microsoft còn làm ứng dụng bằng Electron, thì còn mong gì ở các lập trình viên khác
  • 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ớ

    • Nhưng Qt chỉ hoạt động thật sự native trên một số bản phân phối Linux nhất định
    • Ứng dụng Qt cần runtime nên khó coi là native hoàn toàn
    • Dĩ nhiên nó bất tiện hơn môi trường managed, nhưng trong môi trường nhúng thì vẫn rất hữu ích
  • 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

    • Vì có quá nhiều phiên bản .NET và chúng không tương thích ngược hoàn toà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
    • Trước đây đã từng phân phối qua Windows Update, nhưng cập nhật có thể làm hỏng ứng dụng hoặc quá lớn nên kém hiệu quả
      Giờ đóng gói kèm DLL vẫn tốt hơn
    • Từ .NET 5 trở đi, mô hình bảo mật và namespace đã thay đổi rất nhiều
      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
    • Hiện tại .NET Framework dạng legacy được tích hợp sẵn trong OS, còn
      .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