2014-10-10 12 views
9

Tôi đã có một cuộc tranh luận nhỏ với một lập trình viên. Ông sử dụng các thành ngữ sau trong mã của mình:Có nhầm lẫn khi kiểm tra `HWND` đối với` INVALID_HANDLE_VALUE` không?

HWND hWnd = SomeFunctionWhichReturnsAWindow(); 
if(hWnd != NULL && hWnd != INVALID_HANDLE_VALUE) 
{ 
    // All good 
} 
else 
{ 
    // Error 
} 

Tôi nói với ông rằng trong quan điểm của tôi đây là một cách tiếp cận sai, như các loại HWND không có gì để làm với các định nghĩa INVALID_HANDLE_VALUE, nhưng anh ta chắc chắn rằng đây là mã tốt , như một xử lý hợp lệ không bao giờ có thể bằng INVALID_HANDLE_VALUE, và nó trong tâm trạng "an toàn hơn xin lỗi".

Vì vậy, nó là một thành ngữ chấp nhận được và chính xác?

+1

Sai lầm là một từ lớn. Nhưng chắc chắn, một cửa sổ xử lý sẽ không bao giờ có giá trị đó, nó chỉ được sử dụng cho kernel32 xử lý. –

+2

@HansPassant trong thực tế, có, nhưng nó không chỉ là một chi tiết thực hiện? – Paul

+0

Nếu bạn nhìn vào các hàm khác nhau trả về HANDLE, bạn sẽ thấy rằng một số hàm trả về NULL (như CreateThread) và một số hàm trả về INVALID_HANDLE_VALUE (như CreateFile). Bạn phải kiểm tra tài liệu để xem mỗi hàm cụ thể trả về lỗi gì. Giá trị trả về rất không phù hợp vì lý do lịch sử. Các giá trị được chọn để tương thích với Windows 16 bit. Các hàm 16-bit OpenFile, _lopen và _lcreat trả về -1 về lỗi, do đó hàm CreateFile 32 bit trả về INVALID_HANDLE_VALUE để tạo điều kiện chuyển mã từ Win16. – Marichyasana

Trả lời

12

Đó là một sai lầm khi so sánh số HWND với số INVALID_HANDLE_VALUE. Mặc dù, trong thực tế đây không phải là một sai lầm mà sẽ làm tổn thương bạn.

Chỉ HWND giá trị được đặt trước bởi CreateWindowEx là không hợp lệ là NULL. Bây giờ, nó xảy ra là chi tiết triển khai mà INVALID_HANDLE_VALUE không bao giờ có thể là HWND hợp lệ, nhưng đó chỉ là chi tiết triển khai. Chức năng tạo ra tay cầm cửa sổ, CreateWindowEx, sử dụng NULL để chỉ báo lỗi. Đó là tất cả những điều bạn cần biết.

Nếu bạn muốn thắng cuộc tranh luận với đồng nghiệp của mình, tôi đề nghị bạn nhìn vào bên trong SomeFunctionWhichReturnsAWindow và tìm ra API Win32 nào được gọi để tạo ra HWND. Sau đó tham khảo tài liệu. Điều đó sẽ cho bạn thấy rằng NULL là giá trị không hợp lệ dành riêng.

Vì lợi ích của sự rõ ràng, bạn hoàn toàn nên thay đổi mã để kiểm tra chống lại NULL một mình.

8

INVALID_HANDLE_VALUE được định nghĩa là -1. Giá trị HWND không hợp lệ được định nghĩa là 0. Không có API nào trả về HWND(-1) do lỗi, vì vậy việc kiểm tra INVALID_HANDLE_VALUE là vô nghĩa, nó sẽ không bao giờ xảy ra.

Tuy nhiên, có một số hàm API mà chấp nhận reserved phi zero-HWND giá trị như đầu vào, và do đó không thể được sử dụng như HWND giá trị trả về giá trị, một trong hai:

PeekMessage()GetMessage():

Nếu hWnd là NULL, (Peek/Get) Thông báo truy xuất thư cho bất kỳ cửa sổ nào thuộc về chuỗi hiện tại và bất kỳ thư nào trên hàng đợi thư của chuỗi hiện tại có giá trị hwnd là NULL (xem cấu trúc MSG). Do đó, nếu hWnd là NULL, cả thông điệp cửa sổ và thông điệp luồng đều được xử lý.

Nếu hWnd là -1, (Peek/Nhận) nhắn lấy chỉ tin nhắn trong hàng đợi thông điệp các thread hiện hành có giá trị hwnd là NULL, đó là, các thông điệp chủ đề như được đăng bởi PostMessage (khi tham số hWnd là NULL) hoặc PostThreadMessage.

Vì vậy, có sự khác biệt hợp lý giữa HWND(0)HWND(-1). Và trên thực tế, vì sự khác biệt đó, một HWND hợp lệ sẽ không bao giờ là -1 vì vòng lặp thông báo sẽ không bao giờ có thể truy xuất thư cho nó.

Cũng SetWindowPos() có một số giá trị dự trữ cũng như:

hWndInsertAfter [trong, không bắt buộc]
Loại: HWND

Một handle cửa sổ để đặt trước cửa sổ vị trí theo thứ tự Z. Tham số này phải là một tay cầm cửa sổ hoặc một trong các giá trị sau.

HWND_BOTTOM
(HWND) 1
Địa điểm cửa sổ ở dưới cùng của thứ tự Z. Nếu tham số hWnd xác định cửa sổ trên cùng, cửa sổ sẽ mất trạng thái trên cùng và được đặt ở cuối tất cả các cửa sổ khác.

HWND_NOTOPMOST
(HWND) -2
Địa điểm cửa sổ trên tất cả các cửa sổ không phải trên cùng (có nghĩa là, đằng sau tất cả các cửa sổ trên cùng). Cờ này không có hiệu lực nếu cửa sổ đã là một cửa sổ không phải trên cùng.

HWND_TOP
(HWND) 0
Đặt cửa sổ ở đầu đơn đặt hàng Z.

HWND_TOPMOST
(HWND) -1
Địa điểm cửa sổ trên tất cả các cửa sổ không phải trên cùng. Cửa sổ duy trì vị trí trên cùng của nó ngay cả khi nó bị vô hiệu hóa.

+1

Tôi cũng phát hiện ra rằng 'SetWindowPos' nhận' (HWND) 1' và '(HWND) -2', vì vậy những người không thể hợp lệ' HWND ', quá. Đó không phải là lý do để kiểm tra những người khi xác thực, mặc dù :) – Paul

1

CreateWindowEx và các chức năng tương tự trả lại HWND nêu rõ rằng HWND không hợp lệ là 0. Bất kỳ điều gì khác có thể hợp lệ.

Do đó, việc kiểm tra INVALID_HANDLE_VALUE là 100% sai, bất kể bạn có thể giả định điều gì.

Giả định như "điều này có thể không bao giờ làm tổn thương" là rất nguy hiểm và, mặc dù tại thời điểm này hợp lệ, trong tương lai bạn có thể được sử dụng để giả định các tính năng tương tự không phải là vô tội.