According to Herb Sutter's C++ Coding Standards: 101 Rules, Guidelines, and Best Practices programmer should avoid c-style casting:
C-style casts have different (and often dangerous) semantics depending on context, all disguised behind a single syntax. Replacing C-style casts with C++-style casts helps guard against unexpected errors
WndCtrls* WndCtrls::Button ( WndCtrls* const p_ctrl, HWND hwnd, RECT const &rc )
p_ctrl->ctrl = CreateWindowEx (
WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
(HINSTANCE)GetWindowLongPtr ( hwnd, GWL_HINSTANCE ), // Problematic C-style cast for which I already know workaround
SetWindowSubclass ( p_ctrl->ctrl, WndCtrls::CtrlProc, 0, (DWORD_PTR)p_ctrl ) ) // C-style cast
LRESULT CALLBACK WndCtrls::CtrlProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
WndCtrls* const p_ctrl = (WndCtrls*)dwRefData; // Problematic C-style cast
switch ( message )
return DefSubclassProc ( hwnd, message, wParam, lParam );
Sutter's advice is just that: advice. They aren't hard and fast rules; they're just suggestions that encourage you to write safer, more robust code.
This is one of those cases where the advice doesn't work.
In many places, the Windows API needs to be able to pass data that may or may not be a pointer. As such, it uses a pointer-sized integer, using a C-style cast (remember that the Windows API is primarily C-based) to turn the integer into a pointer. This is safe because the documentation requires it to be: if you give Windows a garbage pointer value, you're breaking that function's rules!
The standard C/C++ names for the pointer-sized integers are
intptr_t (signed) and
uintptr_t (unsigned). However, Windows predates C99 and C++11 (when these were introduced), so it uses its own names:
LONG_PTR (signed) and
ULONG_PTR (unsigned). In addition,
LRESULT are also pointer-sized, since window messages often need to deal with pointers.
So go ahead and use that C-style cast or that
reinterpret_cast<>, whichever one you prefer. The other casts won't work because you need to interpret an integer as a pointer, which the other casts won't let you do.
You may need these anyway because there are other places that, because the Windows API needs to not only be in C but also be usable from other languages, subclassing is replaced by having an object of the struct to derive from as the first element of the dervied struct. This is most apparent in the
WM_NOTIFY message, where all possible notification structs do this with
NMHDR. Just keep this in mind.