Lỗi Hy Hữu Do WM_CREATE Gây Ra
Trong quá trình bảo trì một ứng dụng Windows, mình đã gặp phải một lỗi khá đặc biệt khiến mình phải ghi chú lại để rút kinh nghiệm. Đây là một chương trình Windows đơn giản, sử dụng hàm callback WinProc để xử lý các thông báo như WM_CREATE
, WM_PAINT
, WM_TIMER
và một số thông báo khác.
Hiện tượng lỗi rất lạ: Luồng xử lý WM_CREATE
chưa hoàn tất thì ứng dụng đã bắt đầu xử lý các thông báo khác như WM_TIMER
. Điều này tạo cảm giác như hàm WinProc bị gọi lặp lại (re-entrancy) một cách bất ngờ.
Sau khi kiểm tra kỹ lưỡng, mình phát hiện ra nguyên nhân bắt nguồn từ cách Windows 7 xử lý thông báo WM_CREATE
. Cụ thể, hệ điều hành này có một cơ chế “ngầm” bắt các ngoại lệ (exception) xảy ra trong quá trình xử lý WM_CREATE
. Khi có lỗi truy cập bộ nhớ nghiêm trọng (ví dụ truy cập con trỏ NULL), thay vì crash toàn bộ tiến trình, hệ thống lại tiếp tục chạy như không có gì xảy ra. Hậu quả là cửa sổ vẫn được tạo thành công, nhưng các luồng xử lý khác như WM_TIMER
đã bắt đầu nhận tín hiệu và chạy song song, dẫn đến hiện tượng “giao thoa” không mong muốn.
Mình đã kiểm tra trên nhiều máy tính khác nhau và khẳng định đây là lỗi đặc thù của Windows 7 (phiên bản 64-bit). Chương trình được biên dịch bằng MinGW32, tạo ra file thực thi 32-bit. Mình chưa từng gặp lỗi này trên các hệ điều hành khác như Windows 10/11 hay Linux (thông qua Wine).
Cách kiểm chứng đơn giản:
Bạn có thể thử nghiệm bằng cách sửa hàm WinProc như sau:
|
|
Trên hệ thống Windows 7 64-bit, đoạn mã này sẽ không gây crash, mà chương trình tiếp tục chạy bình thường.
Dự đoán nguyên nhân:
Có thể Windows 7 đã tích hợp cơ chế Structured Exception Handling (SEH) trong giai đoạn xử lý WM_CREATE
để bảo vệ tiến trình khỏi sụp đổ. Tuy nhiên, điều này lại tạo ra hành vi “ẩn lỗi” khó phát hiện, đặc biệt với các ứng dụng 32-bit.
Giải pháp:
- Thêm các khối kiểm soát ngoại lệ riêng trong
WM_CREATE
bằng__try/__except
. - Tránh thực hiện các thao tác nguy hiểm (truy cập tài nguyên không an toàn) trong giai đoạn khởi tạo cửa sổ.
- Nâng cấp ứng dụng lên kiến trúc 64-bit nếu cần tương thích lâu dài.
Mình đã tìm kiếm thông tin trên Google nhưng dường như chưa có tài liệu nào đề cập chính xác đến lỗi này. Nếu bạn gặp phải hiện tượng tương tự, đừng quên chia sẻ để cùng tìm ra giải pháp tối ưu!