Is it normal for an hwnd to have its high bit set?
Asked Answered
O

1

0

I'm passing my HWND to a sub-process so it can send me messages back on its progress. Occasionally I never receive any messages from the sub-process. While investigating, I've found that GetSafeHwnd() of which I'm passing to the subprocess seems to be returning values I don't expect.

For example: 0xffffffffa5400382

Based on that, I can probably deduce that I'm not properly converting that value to/from an int64/string properly. I can fix that. But what I find odd is that this hwnd just doesn't look right?

Are there scenarios where an HWND can have it's high bit set? Is this a normal window, or is there something special about the hwnd to end up like that?

I'm in C++, this is an CDialog based application window.

Orford answered 25/3, 2017 at 4:16 Comment(2)
Is the process 32 or 64bit? The handles can have any bits set, the high bit is nothing special.Shapely
Both processes are 64-bit.Orford
M
3

The result you are seeing comes from sign extension of the handle value to a 64-bit integer. The actual handle value is 0xa5400382, because handle values are always in the 32-bit range, even if the process is 64-bit!

So you should cast the HWND to std::uint32_t instead and convert that to string (or the other way around).

Convert HWND to wstring:

HWND hwnd = GetSafeHwnd();
std::uint32_t handleValue = reinterpret_cast<std::uint32_t>( hwnd );
std::wstring handleValueStr = std::to_wstring( handleValue );

Convert wstring to HWND:

try
{
    std::uint32_t handleValue = std::stoul( someString );
    HWND handle = reinterpret_cast<HWND>( handleValue );
}
catch( std::exception& e )
{
    // Handle string conversion error
}

The try/catch block is required because std::stoul() may throw exceptions if the conversion fails.

Merciless answered 25/3, 2017 at 14:9 Comment(6)
Interesting @zett42. I can't reproduce this on my machine, so I'm resorting to logging. The code that logs the HWND is like this: I hadn't seen that handle values are always 32-bit and that they are safe to truncate in that respect. I will be watching for the next instance our code deals with a window handle that appears to be quite large.Orford
Thanks for your comments @zett42. I will mark it as an answer once I understand the issue I'm seeing better. Unfortunately, I'm unable to type in a carriage return in these comments (Stupid Edge). The code I'm logging with is like this uint64 nOwnderHwnd = (uint64)GetSafeHwnd(); Log("%I64x", nOwnerHwnd); I would expect that line to not do a 32-bit signed carry? But what I'm seeing logged is like this: "ffffffffe22400c8". If I change it to "%I64u", I get this "18446744073208594632".Orford
@Leo That's interesting because printf() outputs uint64_t correctly as e22400c8 with either "%I64x" or "%llx". The decimal value outputted by your log function seems to be completely unexplainable, so there is possibly a bug in the log function?Merciless
@Leo Fun thing is, I can reproduce it with this code: uint64_t x = 0xe22400c8; printf("%llx\n", x); void* p = (void*) x; x = (uint64_t) p; printf("%llx\n", x);. The 1st printf outputs e22400c8, the 2nd one outputs ffffffffe22400c8. So it seems like the issue is in the language. A pointer is always sign-extended when converting to 64-bit integer, even if the integer is unsigned.Merciless
@Leo I have created a new question for this because it's not specifically related to handles (handles are just typedefs for pointers). From the comments so far it can be concluded that this is normal (implementation-specific) behaviour of the compiler.Merciless
Thanks for looking into this. Yes, I reproduced that too, but only if my process was 32-bit. I didn't reproduce it when my process is 64-bit. Yet, it seems VERY similar to what I was seeing in the logs on our windows server machine that I have very limited access to. I'm still waiting for our server to reproduce this scenario again to satisfy my curiosity on what values it really has. But this has been most helpful.Orford

© 2022 - 2024 — McMap. All rights reserved.