Win32 API, Cửa sổ hình dáng kỳ lạ và lý do chúng gần như biến mất

15 tháng 4, 2026·9 phút đọc

Bài viết phân tích sự khác biệt về hiệu năng giữa các ứng dụng Win32 cổ điển và phần mềm hiện đại dựa trên web, đồng thời khám phá kỹ thuật tạo ra các cửa sổ có hình dáng tùy biến. Tác giả chia sẻ mã nguồn minh họa cách sử dụng Win32 API để tạo giao diện độc đáo, nhưng cũng chỉ ra những thách thức khiến phong cách này dần mai một.

Win32 API, Cửa sổ hình dáng kỳ lạ và lý do chúng gần như biến mất

Tôi thực sự mệt mỏi với những ứng dụng có giao diện na ná nhau. Ngày nay, hầu hết các ứng dụng trên Windows đều trông giống hệt nhau vì chúng được xây dựng dựa trên cùng một nền tảng: những trình bao bọc (wrapper) trình duyệt như React, Electron, ElectronBun hay Tauri nhằm bắt chước các ứng dụng Desktop thực thụ. Chúng chạy chậm, ngốn một lượng lớn bộ nhớ và về cơ bản là phần mềm rác (bloatware).

Notepad là một ứng dụng ghi chú cơ bản, không phải một trình thay thế cho Word; Calculator là một chiếc máy tính bỏ túi, không phải một công cụ hoạch định nhiệm vụ lên mặt trăng của NASA. Đôi khi, Microsoft dường như đã đánh mất phương hướng. Họ như thể đã bỏ cuộc và trao quyền kiểm soát cho một nhóm lập trình viên web không có khái niệm gì về tối ưu hóa.

Một ứng dụng Notepad "cập nhật" hiện nay có thể chiếm gần 50MB bộ nhớ, trong khi phiên bản Notepad tương đương được viết bằng C thuần túy với Win32 API chỉ tốn khoảng 1,8MB. Trong thế giới ngày nay, 50MB có vẻ không nhiều, nhưng chính là điểm mấu chốt: từng MB một, chúng cộng lại thành một gánh nặng. Gần đây, tôi có sở hữu một chiếc máy mới trang bị Intel Ultra 9 285 với 32GB RAM, và thật kinh ngạc khi 77% bộ nhớ bị lấp đầy ngay khi Windows 11 khởi động.

Lập trình với Win32 API hiện nay giống như một nghệ thuật đã bị lãng quên. Tôi nhìn lại với sự tiếc nuối về cách các ứng dụng Windows từng được lập trình. Nó lộn xộn, nhưng nó trao cho bạn quyền kiểm soát hoàn toàn. Hầu hết các lập trình giao diện người dùng (UI) hiện đại đều cố gắng che giấu hệ điều hành khỏi bạn. Bạn bị mắc kẹt trong một khung hình chữ nhật, trong khi từng có một giai đoạn vào thời Windows XP khi việc sở hữu các cửa sổ ứng dụng phi tiêu chuẩn là rất "ngầu". Ngay cả Windows Media Player thời đó cũng có giao diện như vậy.

Không phải mọi thứ đều phải là một hình chữ nhật tẻ nhạt với các góc bo tròn, một thanh bên, một bánh răng cài đặt và một stack web ẩn bên dưới. Đã từng có thời điểm khi các ứng dụng Windows được phép trông kỳ lạ. Các trình phát nhạc trông giống như phần cứng vật lý. Những linh vật (mascot) trên màn hình đi lại quanh desktop của bạn. Các bảng điều khiển tiện ích trông như những bảng điều khiển, đồ chơi, đài radio hoặc những bảng điều khiển của người ngoài hành tinh nhỏ xíu. Một cửa sổ không nhất thiết phải là hình chữ nhật chỉ vì hệ điều hành khởi tạo nó như vậy.

Mục đích thường không phải là tính khả dụng. Đó là bản sắc. Đó là phần mà giao diện desktop hiện đại phần lớn đã đánh mất. Không phải vì Windows không còn làm được nữa, mà vì hầu hết mọi người không còn lập trình ở mức độ mà họ có thể tự kiểm soát chính cửa sổ của mình.

Kho lưu trữ GitHub của bài viết này là một lời nhắc nhở nhỏ rằng Win32 vẫn cho phép bạn làm chính xác điều đó. Một ví dụ biến cửa sổ thành hình elip. Một ví dụ khác định hình cửa sổ từ một bitmap (ảnh). Và ví dụ thứ ba biến cả thứ đó thành một linh vật desktop hoạt hình. Không cái nào yêu cầu một khung framework khổng lồ. Nó chỉ cần giao tiếp trực tiếp với Windows.

Vòng lặp thông điệp và vùng (Region)

Điều đầu tiên gây khó hiểu cho những người đến từ lập trình game, trình duyệt hoặc framework UI hiện đại là Win32 không xoay quanh một vòng lặp cập nhật (update loop) do bạn sở hữu. Nó xoay quanh các thông điệp (messages). Ứng dụng của bạn ngồi đó, và Windows liên tục gửi cho nó các sự kiện:

while (GetMessage(&msg, NULL, 0, 0) > 0) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Vòng lặp này là hợp đồng. Windows nói rằng có điều gì đó vừa xảy ra, và thủ tục cửa sổ (window procedure) của bạn quyết định ý nghĩa của nó. "WM_CREATE" có nghĩa là cửa sổ đang được tạo. "WM_PAINT" có nghĩa là nó cần được vẽ lại. "WM_SIZE" có nghĩa là vùng khách hàng của nó thay đổi. "WM_DESTROY" có nghĩa là nó đã kết thúc. Đó là hình dạng thực sự của lập trình Win32: bạn xây dựng hành vi từng thông điệp một.

Và khi bạn hiểu điều đó, những cửa sổ hình dáng kỳ lạ không còn cảm thấy bí ẩn nữa.

Một cửa sổ cấp cao nhất bình thường là hình chữ nhật, nhưng Windows cũng có khái niệm về đối tượng vùng, "HRGN". Nếu bạn gán một vùng cho cửa sổ bằng "SetWindowRgn", chỉ phần đó được tính là cửa sổ thực sự. Phần còn lại biến mất, cả về mặt thị giác lẫn tương tác. Đó là mẹo.

Phiên bản đơn giản nhất nằm trong "basic/main.c". Nó tạo ra một cửa sổ không viền và sau đó thực hiện điều này:

region = CreateEllipticRgn(0, 0, rc.right, rc.bottom);
SetWindowRgn(hwnd, region, TRUE);

Điều đó đủ để biến cửa sổ thành hình bầu dục. Không phải là hình bầu dục giả vẽ bên trong một khung hình chữ nhật, mà là một HWND thực sự hình bầu dục. Mẫu cũng xử lý bit thực tế mà mọi người thường quên: một khi bạn loại bỏ thanh tiêu đề, hệ thống sẽ không còn kéo cửa sổ giúp bạn nữa. Vì vậy, trên sự kiện "WM_LBUTTONDOWN", nó giả vờ kéo thanh tiêu đề bằng cách gửi "WM_NCLBUTTONDOWN" với "HTCAPTION".

Chi tiết nhỏ đó là toàn bộ câu chuyện của các cửa sổ tùy chỉnh thu nhỏ. Tạo hình dáng thì dễ. Thay thế những gì khung bình thường từng làm miễn phí cho bạn mới là công việc thực sự.

Định hình từ Bitmap và Cửa sổ Layered

Mẫu tiếp theo thú vị hơn. Thay vì định nghĩa hình dạng toán học, "drivenbyimage/main.c" suy ra hình dạng từ dữ liệu bitmap. Nó tải "shape.bmp", đọc các điểm ảnh bằng "GetDIBits", sau đó quét hình ảnh từng hàng một. Mỗi đoạn ngang của các điểm ảnh không trong suốt trở thành một vùng hình chữ nhật nhỏ, và những đoạn này được kết hợp thành một vùng cửa sổ cuối cùng.

#define TRANSPARENT_COLOR RGB(255, 0, 255)

Màu hồng tươi (Magenta) có nghĩa là khoảng trống. Mọi thứ khác trở thành một phần của cửa sổ.

Điều đó có nghĩa là bitmap đang làm hai công việc cùng lúc. Thứ nhất, nó là thứ bạn vẽ trong "WM_PAINT". Thứ hai, nó là hình dạng của cửa sổ thực tế. Đó là cách nhiều ứng dụng có giao diện (skinned) cũ hoạt động. Bạn không bị giới hạn bởi các hình tròn, góc tròn hay hình học vector gọn gàng. Nếu hình ảnh trông giống một con chó, một tàu vũ trụ, một máy nghe nhạc hay một khuôn mặt hoạt hình, cửa sổ cũng có thể mang hình dáng đó.

Đây là phần khiến phần mềm desktop cũ trở nên thú vị. Khung cửa sổ ngừng là một quy luật tự nhiên và trở thành một tài sản (asset) khác.

Tuy nhiên, các vùng dựa trên bitmap vẫn có cạnh cứng. Một điểm ảnh hoặc là nằm trong hoặc là nằm ngoài. Điều đó hoàn hảo cho hình bóng và UI cắt dán, nhưng nếu bạn muốn các cạnh mềm mại, điểm ảnh bán trong suốt hoặc hoạt hình, bạn cần chuyển sang cửa sổ phân lớp (layered windows).

Đó là điều mà ví dụ "Animated/" thực hiện.

Ví dụ về linh vật hoạt hình trên desktopVí dụ về linh vật hoạt hình trên desktop

Thay vì khắc cửa sổ từ một vùng, ví dụ này tạo ra một cửa sổ bật lên "WS_EX_LAYERED" và tải một hình ảnh alpha 32-bit vào đó bằng "UpdateLayeredWindow". Mẫu sử dụng một sprite sheet, chuyển khung hình trên bộ đếm thời gian, vẽ vào một bitmap bộ nhớ bằng GDI+, sau đó đẩy kết quả ra desktop. Tại thời điểm đó, bạn không thực sự nói "cửa sổ của tôi là một hình elip" hay "cửa sổ của tôi khớp với mặt nạ này". Bạn đang nói "cửa sổ của tôi là bất cứ điểm ảnh nào đang có ở đây ngay bây giờ".

Một linh vật hoạt hình hoạt động tốt hơn dưới dạng cửa sổ phân lớp vì bạn có được alpha từng điểm ảnh, các cạnh sạch sẽ, độ trong suốt thích hợp và tự do thay đổi hình dạng hiển thị ở mỗi khung hình.

Tại sao chúng biến mất?

Nhưng có một vấn đề với lập trình Win32 API. Và sự thật là các cửa sổ tùy chỉnh có nghĩa là bạn phải tự làm mọi thứ, kiểm soát mọi thông điệp của Windows, và điều đó rất mong manh. Sự khó chịu bắt đầu ngay khi bạn quyết định loại bỏ khung bình thường. Khi đó, bạn sở hữu việc kéo, thay đổi kích thước, hành vi đóng, kiểm tra va chạm (hit testing), xử lý bàn phím, tính chính xác khi vẽ lại, xử lý DPI và mọi trường hợp cạnh khó chịu nhỏ xíu mà cửa sổ mặc định đã giải quyết từ hàng thập kỷ trước. Đó là lý do các cửa sổ hình dáng kỳ lạ dễ tạo mẫu (prototype) nhưng tốn kém để hoàn thiện.

Người dùng thường không thưởng công cho nỗ lực đó trừ khi kết quả thực sự xuất sắc.

Văn hóa giao diện Desktop đã chuyển từ "nhìn xem giao diện điên rồ này" sang "hoạt động đáng tin cậy và đừng làm phiền tôi". Các cửa sổ kỳ lạ thường gắn liền với các mẹo (gimmicks), phần mềm quảng cáo (adware), thanh công cụ và các tiện ích cồng kềnh hơn là với phần mềm nghiêm túc. Điều đó thật đáng tiếc. Tuy nhiên, tôi vẫn thích những thứ này tồn tại. Nó nhắc nhở bạn rằng Windows từng là một nền tảng nơi phần mềm có thể có sự hiện diện vật lý, không chỉ là một bố cục trang bên trong một tab trình duyệt ngụy trang.

Hầu hết thời gian, một cửa sổ hình chữ nhật bình thường là câu trả lời đúng. Nhưng tốt hơn là nên nhớ rằng đó là một sự lựa chọn, không phải là một luật lệ.

Điều hay đẹp về Win32 là nó không cố gắng thuyết phục bạn bỏ cuộc. Nó chỉ cung cấp cho bạn các thông điệp, các handles, các API vẽ và đủ "dây thừng" để xây dựng một cái gì đó thú vị.

Mã nguồn có thể được tìm thấy trong kho GitHub của bài viết này.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗