LOWORD() receives DWORD (unsigned long) but WPARAM is UINT_PTR (unsigned int) - c++

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).

Related

Difference between unsigned long and DWORD?

I am watching a tutorial in which someone is finding a process ID for a running program in C++ using the windows and TlHelp32 headers. He uses DWORDs which are a part of windows. According to documentation DWORDs are 32 bit unsigned integers. So, is there any difference between a DWORD and a unsigned int or unsigned long? If he replaced every instance of DWORD with unsigned long would it make any difference? If there are differences are they compile time or runtime differences? Thx.
Per Windows Data Types, DWORD is just an alias for unsigned long:
typedef unsigned long DWORD;
So no, there is no difference whatsoever between DWORD and unsigned long, they are the exact same thing.
There is, however, a difference between an unsigned int and an unsigned long. They are separate and distinct types, even though they have the same characteristics.

What is the purpose of adding a pointer in: typedef unsigned char UCHAR, *PUCHAR;

What is the purpose of adding a pointer in: typedef unsigned char UCHAR, *PUCHAR;
(there are a lot of other examples of typedefs with additional pointers) I found that next to UCHAR stands *PUCHAR pointer and checked sizeof(UCHAR) and sizeof(PUCHAR) the results was 1 byte and 8 bytes. Is this pointer size fixed or is flexible? Is that correct to make typedef with data types of different size in one line? What if the OS will extend the addressing to 128 bits (16 bytes) in the future?
What is the purpose of making so much data types when it's sure, that addressing is extending?
typedef unsigned char UCHAR, *PUCHAR;
(...)
2.2.16 HANDLE
2.2.17 HCALL
2.2.18 HRESULT
2.2.19 INT
2.2.20 INT8
2.2.21 INT16
2.2.22 INT32
2.2.23 INT64
2.2.24 LDAP_UDP_HANDLE
2.2.25 LMCSTR
2.2.26 LMSTR
2.2.27 LONG
2.2.28 LONGLONG
2.2.29 LONG_PTR
2.2.30 LONG32
2.2.31 LONG64
2.2.32 LPCSTR
2.2.33 LPCVOID
2.2.34 LPCWSTR
2.2.35 LPSTR
2.2.36 LPWSTR
2.2.37 NET_API_STATUS
2.2.38 NTSTATUS
2.2.39 PCONTEXT_HANDLE
2.2.40 QWORD
2.2.41 RPC_BINDING_HANDLE
2.2.42 SHORT
2.2.43 SIZE_T
2.2.44 STRING
2.2.45 UCHAR
2.2.46 UINT
2.2.47 UINT8
2.2.48 UINT16
2.2.49 UINT32
2.2.50 UINT64
2.2.51 ULONG
2.2.52 ULONG_PTR
2.2.53 ULONG32
2.2.54 ULONG64
2.2.55 ULONGLONG
2.2.56 UNICODE
2.2.57 UNC
2.2.58 USHORT
2.2.59 VOID
2.2.60 WCHAR
2.2.61 WORD
UCHAR stands for unsigned char which is 1 byte in size. PUCHAR stands for unsigned char*. To store a pointer you need 8 bytes (in a 64 bit application). That's why the size of UCHAR is 1 byte and size of PUCHAR is 8 bytes.
Why a pointer is 8 bytes?
That's because in a 64 bit application, the address of a single byte has 64 bits. To represent this, you need 64 bits. That's why it takes 8 bits.
Can't we just use *char instead of *PUCHAR or maybe it's some hidden meaning for making so much data types?
*PUCHAR is unsigned char**, not char*. But if I understand your question correctly and what you mean is "using unsigned char* instead of PUCHAR", yes you can. But only if you know about the underlying type.
There can be few reasons for why the developers have gone with a custom typedef like that. It could be to fit in multiple platforms, to fit different architectures, personal opinion, etc... Without knowing the real underlying type, we might actually lose information in the process of casting to another type.

Is there a safe way to cast DWORD_PTR into DWORD?

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);

Is there a 64 bit version of CharLowerBuff?

I am currently transitioning some C++ code to be compiled for 64 bit instead of 32 bit. The code calls the function CharLowerBuff(lpsz, strlen(lpsz)) which raises a warning since strlen returns the type size_t (aka long long unsigned int) but CharLowerBuff expects DWORD (aka long unsigned int).
Is there a 64 bit version of CharLowerBuff that takes DWORDLONG (or something equivalent) instead?
I don't see one, however CharLowerBuff(x, strlen(x)) is just the same as CharLower(x), but the latter does not have this DWORD problem.
Another approach would be to write your own function to do this operation and take a size_t length, which shouldn't be difficult.

long to HWND (VS8 C++)

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.