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.

+3


source to share


2 answers


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.

+6


source


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

+1


source







All Articles