Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conversion from HGDIOBJ to HBRUSH

Tags:

c++

g++

winapi

(This question is asked in the context of Win32API using the g++ compiler). I have a trouble with understanding why the following line of code won't work

wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);

wndclass is an instance of the WNDCLASSEX structure, and the Windows API clearly specifies that the type of its member hbrBackground is HBRUSH. Further, HBRUSH is just a typedef for a HANDLE, which in turn is a typedef for void*. Hence, HBRUSH should be of type void*. Now, the GetStockObject function's return type is HGDIOBJ, which is also typedefed as a HANDLE, hence a 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 then do I get the following error upon compilation:

invalid conversion from 'HGDIOBJ {aka void*}' to 'HBRUSH' [-fpermissive]

If I explicitly cast the returned value from GetStockObject it works

wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

Thank you for any help.

like image 286
jensa Avatar asked Nov 08 '14 08:11

jensa


1 Answers

It's because implicit conversions from void* are disallowed in C++ (unlike C).

Function

HGDIOBJ GetStockObject(int fnObject);

returns HGDIOBJ which is defined as void*:

typedef void NEAR* HGDIOBJ;

You are assingning it to HBRUSH which is a typedef to pointer to struct

struct HBRUSH__;
typedef struct HBRUSH__ *HBRUSH;

(see windef.h)

While such assignment works fine in C, in C++ you should explicitly cast :

wndclass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));

See: void pointers: difference between C and C++

Edit:

As jensa noted in comments, the article Windows Data Types is wildly outdated. This is putting it mildly. I don't remember when it's happened exactly, but STRICT Type Checking was enabled by default since decades. This article was probably written in the last century (a 20th one).

Here is the quote of the comment by yic81 from 10/7/2012

This article needs reviewing. When was it last reviewed? 15 years ago? The statement typedef HANDLE HINSTANCE; is totally incorrect, as many other typedef HANDLEs. Vast majority of them are now DECLARE_HANDLE() structs. Please review and fix this article. See this KB83456 http://support.microsoft.com/kb/83456 (last updated November 1999) for more details

You can also learn more about STRICT and it's advantages here: STRICT Type Checking

And here is how it looks like in windef.h:

DECLARE_HANDLE(HBRUSH);

And somewhere below DECLARE_HANDLE 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 are using DECLARE_HANDLE from line 6. With NO_STRICT -- lines 9-10.

like image 156
Ivan Aksamentov - Drop Avatar answered Oct 03 '22 20:10

Ivan Aksamentov - Drop