How can I cast long to HWND (C++ visual studio 8)?
Long lWindowHandler;
HWND oHwnd = (HWND)lWindowHandler;
But I got the following warning:
warning C4312: 'type cast' : conversion from 'LONG' to 'HWND' of greater size
Thanks.
As long as you're sure that the LONG you have is really an HWND, then it's as simple as:
HWND hWnd = (HWND)(LONG_PTR)lParam;
HWND is a handle to a window.
This type is declared in WinDef.h as follows:
typedef HANDLE HWND;
HANDLE is handle to an object.
This type is declared in WinNT.h as follows:
typedef PVOID HANDLE;
Finally, PVOID is a pointer to any type.
This type is declared in WinNT.h as follows:
typedef void *PVOID;
So, HWND is actually a pointer to void. You can cast a long to a HWND like this:
HWND h = (HWND)my_long_var;
but very careful of what information is stored in my_long_var. You have to make sure that you have a pointer in there.
Later edit:
The warning suggest that you've got 64-bit portability checks turned on. If you're building a 32 bit application you can ignore them.
Doing that is only safe if you are not running on a 64 bit version of windows. The LONG type is 32 bits, but the HANDLE type is probably 64 bits. You'll need to make your code 64 bit clean. In short, you will want to change the LONG to a LONG_PTR.
Rules for using pointer types:
Do not cast pointers to int, long,
ULONG, or DWORD. If you must cast a
pointer to test some bits, set or
clear bits, or otherwise manipulate
its contents, use the UINT_PTR or
INT_PTR type. These types are integral
types that scale to the size of a
pointer for both 32- and 64-bit
Windows (for example, ULONG for 32-bit
Windows and _int64 for 64-bit
Windows). For example, assume you are
porting the following code:
ImageBase = (PVOID)((ULONG)ImageBase |
1);
As a part of the porting process, you
would change the code as follows:
ImageBase =
(PVOID)((ULONG_PTR)ImageBase | 1);
Use UINT_PTR and INT_PTR where
appropriate (and if you are uncertain
whether they are required, there is no
harm in using them just in case). Do
not cast your pointers to the types
ULONG, LONG, INT, UINT, or DWORD.
Note that HANDLE is defined as a
void*, so typecasting a HANDLE value
to a ULONG value to test, set, or
clear the low-order 2 bits is an error
on 64-bit Windows.
Related
An old 32 bit C++ application (MS Visual Studio) has code lines like this:
m_value = (PUCHAR)someDWORD;
Where PUCHAR is a pointer to an unsigned char.
Now I have changed to 64 bit and I get a (valid) warning about conversion from DWORD to the 64 bit pointer. My unqualified solution to this is to write like this:
m_value = (PUCHAR)(DWARD_PTR)someDWORD;
Is this the correct way to fix this warning (and potential runtime error)?
That savage cast to DWORD_PTR will only pad someDWORD with zeros, it won't bring back the upper half of the pointer value that was lost.
You need someDWORD to be a DWORD_PTR (or, in fact, a std::uintptr_t) from the beginning.
What is the correct way to use ReadProcessMemory?
I am currently using it like this:
DWORD read_mem(DWORD addr)
{
DWORD buffer = 0x0;
if (!ReadProcessMemory(phandle, LPCVOID(addr), &buffer, sizeof(DWORD), nullptr))
{
return false;
}
return buffer;
}
This causes a warning due to addr being wrongly casted.
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Other example code I've seen such as this uses the same approach.
So what is the proper way to use this function without getting a warning?
"cast to pointer from integer of different size" - this means that DWORD and void* are different byte sizes, which can only happen if you are compiling your code for 64-bit, as they are the same byte size in a 32-bit compilation.
From the MSDN documentation, Windows Data Types:
DWORD
A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
A DWORD is simply not large enough to hold a 64-bit memory address (the other code you mention will similarly only work correctly in 32-bit).
Change Addr (and whatever code you are using to determine the value of Addr) to use DWORD_PTR instead:
DWORD_PTR
An unsigned long type for pointer precision. Use when casting a pointer to a long type to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have been extended to 64 bits in 64-bit Windows.)
Then Addr will be the correct byte size whether you compile for 32-bit or 64-bit.
I implemented this function to convert from dword_ptr to dword but if there is other way with less code that will be appreciated.
this code should be compatible with 32bit and 64bit windows
I have seen this Question but the answer contains new and delete operations
inline unsigned long Convert_to_DWORD(unsigned long long data)
{
//typedef unsigned __int64 ULONG_PTR
//typedef ULONG_PTR DWORD_PTR
//typedef unsigned long DWORD;
assert(UINT_MAX > data);
unsigned long* value = reinterpret_cast<unsigned long*>(&data);
return *value;
}
Is there a safe way to cast DWORD_PTR into DWORD?
Integer types are implicitly convertible to each other. Such conversion is safe in the sense that there is no UB involved
DWORD_PTR original;
DWORD converted = original;
On a 64 bit system DWORD may be smaller than DWORD_PTR, in which case it cannot represent all the values representable by DWORD_PTR. Therefore if you do the inverse conversion, you do not get the same original value back unless the high order bytes happened to be zero. Furthermore, if DWORD_PTR represented a pointer value, then converting the value to DWORD then back to DWORD_PTR then back into a pointer then using the resulting pointer would not be safe.
Since the conversion is narrowing, a compiler might generate a warning. An explicit conversion makes your intention unambiguous and should silence such warning:
DWORD converted = DWORD(original);
As a long is wider than an int giving the low order of an unsigned long should return something bigger than just the low order of unsigned int.
Why does the function still know what the low order of the parameter is? Does it analyze the type given thus DWORD to be understood as a maximum in this case?
LOWORD() does not receive a DWORD, it casts it to a DWORD_PTR.
Both DWORD_PTR and UINT_PTR have the same size.
(32 bit or 64 bit, depending on the operating system architecture).
I'm trying to call the Windows API function GetExitCodeProcess which takes a LPDWORD as its second parameter.
According to MSDN, LPDWORD is a pointer to an unsigned 32-bit value. So I tried to pass a uint32_t*, but the compiler (MSVC 11.0) is not happy with it:
error C2664: 'GetExitCodeProcess' : cannot convert parameter 2 from 'uint32_t *' to 'LPDWORD'
Also a static_cast does not help. Why is that? And is it safe to use a reinterpret_cast in this case?
From the documentation:
DWORD
A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
This type is declared in IntSafe.h as follows:
typedef unsigned long DWORD;
So, LPDWORD is unsigned long int*. But you are trying to pass unsigned int*. I know that the types point to variables that are the same size, but the pointer types are not compatible.
The solution is to declare a variable of type DWORD, and pass the address of that variable. Something like this:
DWORD dwExitCode;
if (!GetExitCodeProcess(hProcess, &dwExitCode))
{
// deal with error
}
uint32_t ExitCode = dwExitCode;