Paul
Paul

Reputation: 6871

Is it a mistake to check a `HWND` against `INVALID_HANDLE_VALUE`?

I had a small debate with a fellow programmer. He uses the following idiom in his code:

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

I told him that in my opinion this is a wrong approach, as the HWND type has nothing to do with the INVALID_HANDLE_VALUE definition, but he's sure that this is good code, as a valid handle can never be equal to INVALID_HANDLE_VALUE, and it's in the mood of "better safe than sorry".

So, is it an acceptable and correct idiom?

Upvotes: 16

Views: 10947

Answers (5)

Peter
Peter

Reputation: 1275

HWND can't be used in comparison to INVALID_HANDLE_VALUE as this two are two different things. Most resources, such as a file, etc return HANDLE and must be compared to INVALID_HANDLE_VALUE to ensure the resource is okay for use by any function which depends on it. However, HWND refers to handle for windows GUI objects. So is save to compare HWND values to 0 for invalid return handles rather than using INVALID_HANDLE_VALUE which is also -1.

Furthermore, to more information on the HANDLE type, you can check this StackOverflow previous answers to learn more.

A HANDLE is a context-specific unique identifier. By context-specific, I mean that a handle obtained from one context cannot necessarily be used in any other aribtrary context that also works on HANDLEs.

For example, GetModuleHandle returns a unique identifier to a currently loaded module. The returned handle can be used in other functions that accept module handles. It cannot be given to functions that require other types of handles. For example, you couldn't give a handle returned from GetModuleHandle to HeapDestroy and expect it to do something sensible.

The HANDLE itself is just an integral type. Usually, but not necessarily, it is a pointer to some underlying type or memory location. For example, the HANDLE returned by GetModuleHandle is actually a pointer to the base virtual memory address of the module. But there is no rule stating that handles must be pointers. A handle could also just be a simple integer (which could possibly be used by some Win32 API as an index into an array).

Upvotes: 1

zar
zar

Reputation: 12227

The question is the windows handle is valid or not, Why not just use IsWindow()?

Upvotes: 0

Michael Chourdakis
Michael Chourdakis

Reputation: 11158

CreateWindowEx and the similar functions that return a HWND clearly state that an invalid HWND is 0. Anything other might be valid.

Therefore, checking for INVALID_HANDLE_VALUE is 100% wrong, no matter what you might assume.

Making assumptions such as "this will probably never hurt" are very much dangerous and, although at this time valid, in the future you may be used to assume similar features that are not that innocent.

Upvotes: 2

David Heffernan
David Heffernan

Reputation: 612934

It is a mistake to compare an HWND against INVALID_HANDLE_VALUE. Although, in practise this is not a mistake that will hurt you.

The only HWND value reserved by CreateWindowEx as being invalid is NULL. Now, it happens to be an implementation detail that INVALID_HANDLE_VALUE cannot ever be a valid HWND, but that is just implementation detail. The function that yields window handles, CreateWindowEx, uses NULL to indicate failure. That's all you need to know.

If you wish to win your argument with your colleague, I suggest you look inside SomeFunctionWhichReturnsAWindow and find out which Win32 API is called to produce the HWND. Then consult the documentation. That will show you that NULL is the reserved invalid value.

For the sake of clarity you absolutely should change the code to test against NULL alone.

Upvotes: 20

Remy Lebeau
Remy Lebeau

Reputation: 595971

INVALID_HANDLE_VALUE is defined as -1. An invalid HWND is defined as 0. No API will ever return HWND(-1) on failure, so checking for INVALID_HANDLE_VALUE is meaningless, it will never happen.

However, there are some APIs that accept reserved non-zero HWND values as input, and thus cannot be used as valid HWND return values, either:

PeekMessage() and GetMessage():

If hWnd is NULL, (Peek/Get)Message retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL (see the MSG structure). Therefore if hWnd is NULL, both window messages and thread messages are processed.

If hWnd is -1, (Peek/Get)Message retrieves only messages on the current thread's message queue whose hwnd value is NULL, that is, thread messages as posted by PostMessage (when the hWnd parameter is NULL) or PostThreadMessage.

So there is a logical difference between HWND(0) and HWND(-1). And in fact, because of that difference, a valid HWND will never be -1 because a message loop would never be able to retrieve messages for it.

Also SetWindowPos() has some reserved values as well:

hWndInsertAfter [in, optional]
Type: HWND

A handle to the window to precede the positioned window in the Z order. This parameter must be a window handle or one of the following values.

HWND_BOTTOM
(HWND)1
Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.

HWND_NOTOPMOST
(HWND)-2
Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window.

HWND_TOP
(HWND)0
Places the window at the top of the Z order.

HWND_TOPMOST
(HWND)-1
Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.

Upvotes: 14

Related Questions