Conversion from HGDIOBJ to HBRUSH
(This question is being asked in the context of Win32API using the g ++ compiler). I am having trouble understanding why the following line of code will not work.
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass is an instance of the WNDCLASSEX structure, and the Windows API clearly states that the type of its hbrBackground member is HBRUSH. Also, HBRUSH is just a typedef for HANDLE, which in turn is a typedef for void *. Therefore, HBRUSH must be of type void *. Now, the return type of GetStockObject is HGDIOBJ, which is also typed as HANDLE, hence void *.
Windows Data Types http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
GetStockObject http://msdn.microsoft.com/en-us/library/dd144925(v=vs.85).aspx
WNDCLASSEX http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx
Why am I getting the following error after compiling:
invalid conversion from 'HGDIOBJ {aka void*}' to 'HBRUSH' [-fpermissive]
If I explicitly pass the return value from GetStockObject it works
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
Thanks for any help.
source to share
This is because implicit conversions from are void*
prohibited in C ++ (as opposed to C).
Function
HGDIOBJ GetStockObject(int fnObject);
returns HGDIOBJ
, which is defined as void*
:
typedef void NEAR* HGDIOBJ;
You check it for HBRUSH which is typedef
for a pointer tostruct
struct HBRUSH__;
typedef struct HBRUSH__ *HBRUSH;
(see windef.h
)
While this kind of assignment works fine in C, in C ++ you must explicitly use:
wndclass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
See: void pointers: difference between C and C ++
Edit:
As Jens pointed out in the comments, the Windows Data Types article is heavily outdated. That's putting it mildly. I don't remember exactly when this happened, but has STRICT Type Checking
been enabled by default since decades. This article was probably written in the last century (20th).
Here is a quote from a comment yic81
from10/7/2012
This article needs revision. When was it last reviewed? 15 years ago? Typedef HANDLE HINSTANCE; is completely wrong, as many other typedef roulettes. The vast majority of them are now DECLARE_HANDLE () Structures. Review and correct this article. See KB83456 http://support.microsoft.com/kb/83456 (last updated November 1999) for details
You can also read more about STRICT
and here the benefits: STRICT type check
And this is how it looks in windef.h
:
DECLARE_HANDLE(HBRUSH);
And somewhere below it DECLARE_HANDLE
is defined as:
#ifdef STRICT
typedef void *HANDLE;
#if 0 && (_MSC_VER > 1000)
#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
#else
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
#endif
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
By default we use DECLARE_HANDLE
from line 6. With NO_STRICT
- lines 9-10.
source to share
In C ++ terms, you can say what it GetStockObject
returns GDIBase*
, and a conversion is required to convert the corresponding derived class (like suppose HBrushGDI
). Therefore, you must resort to type.
class GDIBase;
class HBrushGDI : GDIBase;
GDIBase* GetStockObject(int);
HBrushGDI* pBrush;
pBrush = static_cast<HBrushGDI*>GetStockObject(WHITE_BRUSH);
This is the same as the typecasting function-pointer returned from GetProcAddress
. Therefore, casting to the appropriate type is safe (assuming you know the correct type).
source to share