Error when converting from C++ Builder 2007 to XE

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Error when converting from C++ Builder 2007 to XE

Postby Marloes » Sun Jan 24, 2016 9:57 am

As I upgrade one of my projects from C++ Builder 2007 to XE I get the following error

[bcc32 Error] fraPedigreeTree.cpp(2052): E2034 Cannot convert 'HWND__ *' to 'HDC__ *'

I just got a bit unsure about 'HWND__ *' and 'HDC__ *'. The line causing the error is

Code: Select all
  Graphics::TBitmap* bitmap = new Graphics::TBitmap;
  bitmap->Handle = CreateCompatibleBitmap(Handle, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);


(The code is placed in a TFrame.) Can somebody please enlighten me what needs to be put in there now?
Marloes
Active Poster
Active Poster
 
Posts: 13
Joined: Mon Dec 01, 2014 5:35 am

Re: Error when converting from C++ Builder 2007 to XE

Postby minas » Sun Jan 24, 2016 3:39 pm

Marloes wrote:
Code: Select all
  Graphics::TBitmap* bitmap = new Graphics::TBitmap;
  bitmap->Handle = CreateCompatibleBitmap(Handle, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);




bitmap->Handle = CreateCompatibleBitmap(Canvas->Handle, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);
-
User avatar
minas
BCBJ Guru
BCBJ Guru
 
Posts: 196
Joined: Sat Jul 10, 2004 6:09 am
Location: Greece

Re: Error when converting from C++ Builder 2007 to XE

Postby rlebeau » Sun Jan 24, 2016 5:08 pm

Marloes wrote:As I upgrade one of my projects from C++ Builder 2007 to XE I get the following error

[bcc32 Error] fraPedigreeTree.cpp(2052): E2034 Cannot convert 'HWND__ *' to 'HDC__ *'


You are passing an HWND (window handle) where an HDC (device context handle) is expected. They are not the same thing. That is a clear bug in your code that you need to fix. The code would never have worked to begin with, even if it compiled.

The only way your 2007 project could have been compiling the code without error is if STRICT is disabled, such as if NO_STRICT is defined. In your XE project, STRICT is enabled instead (also, the CLang-based C++ compilers do not even support disabling STRICT at all).

See Embarcadero's DocWiki for more details:

C++ Applications Use STRICT Type Checking

Marloes wrote:I just got a bit unsure about 'HWND__ *' and 'HDC__ *'.


Both HWND and HDC (amongst others) are declared using the Win32 DECLARE_HANDLE() macro.

winnt.h (spacing added for readability):

Code: Select all
#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


windef.h:

Code: Select all
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HDC);


Under NO_STRICT, both HWND and HDC (and others) are just aliases for void*:

Code: Select all
typedef PVOID HANDLE;
typedef HANDLE HWND;
typedef HANDLE HDC;


As you can imagine, this can (and did) lead to bad code errors that the compiler cannot catch, since any void* can be assigned to any other void* without regard to what they actually point at. STRICT was invented to prevent that.

Under STRICT, HWND is an alias for HWND__*, and HDC is an alias for HDC__*:

Code: Select all
struct HWND__{int unused;}; typedef struct HWND__ *HWND;
struct HDC__{int unused;}; typedef struct HDC__ *HDC;


It is not possible to assign an HWND__* to an HDC__*, and vice versa (or any other STRICT-aware handle type). The compiler can catch such errors. This is how STRICT helps promote safer code, by preventing the wrong types from being passed around.

Marloes wrote:The line causing the error is

Code: Select all
  Graphics::TBitmap* bitmap = new Graphics::TBitmap;
  bitmap->Handle = CreateCompatibleBitmap(Handle, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);



The first parameter of CreateCompatibleBitmap() expects an HDC, but you are passing it an HWND instead (the TFrame's window handle). You cannot create an HBITMAP from an HWND, you have to retrieve an HDC for the HWND first, using the Win32 API GetDC(), GetDCEx(), or GetWindowDC() function, eg:

Code: Select all
  Graphics::TBitmap* bitmap = new Graphics::TBitmap;
  HDC hdc = GetDC(this->Handle);
  bitmap->Handle = CreateCompatibleBitmap(hdc, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);
  ReleaseDC(this->Handle, hdc);


VCL UI controls have a protected GetDeviceContext() method for that same purpose, eg:

Code: Select all
  Graphics::TBitmap* bitmap = new Graphics::TBitmap;
  HWND hwnd;
  HDC hdc = this->GetDeviceContext(hwnd);
  bitmap->Handle = CreateCompatibleBitmap(hdc, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);
  ReleaseDC(hwnd, hdc);


Alternatively, you can use a TControlCanvas object, which uses GetDeviceContext() internally:

Code: Select all
  Graphics::TBitmap* bitmap = new Graphics::TBitmap;
  TControlCanvas *pTmpCanvas = new TControlCanvas;
  pTmpCanvas->Control = this;
  bitmap->Handle = CreateCompatibleBitmap(pTmpCanvas->Handle, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);
  delete pTmpCanvas;
Last edited by rlebeau on Wed Jan 27, 2016 7:18 pm, edited 11 times in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1504
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Error when converting from C++ Builder 2007 to XE

Postby rlebeau » Sun Jan 24, 2016 5:13 pm

minas wrote: bitmap->Handle = CreateCompatibleBitmap(Canvas->Handle, BITMAP_WIDTH, BITMAP_SHORTHEIGHT);


TFrame does not have a Canvas property of its own. And even if it did, its Canvas->Handle would only be valid while the TFrame is in the process of being painted. If you need a TCanvas for a TFrame, use a TControlCanvas object, as shown in my reply above.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1504
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Error when converting from C++ Builder 2007 to XE

Postby minas » Sun Jan 24, 2016 5:33 pm

rlebeau wrote:TFrame does not have a Canvas property of its own. And even if it did, its Canvas->Handle would only be valid while the TFrame is in the process of being painted. If you need a TCanvas for a TFrame, use a TControlCanvas object, as shown in my reply above.


yes ,you are right ...I was thinking of TForm !!! I read the question tooooo fast :-)
-
User avatar
minas
BCBJ Guru
BCBJ Guru
 
Posts: 196
Joined: Sat Jul 10, 2004 6:09 am
Location: Greece


Return to Technical

Who is online

Users browsing this forum: No registered users and 19 guests