1

Is there a difference in the way that the HDC type (Device Context Handle) is declared in Delphi 2007 versus Delphi XE2.

In D2007 the following code works fine, but produces a range check error in DXE2:

Control.Parent.Perform(WM_PAINT, Integer(DC), 0);

When stepping through the code in D2007 the value of DC (Device Context) seems to always be less than MaxInt but in DXE2 the value of DC is usually greater than MaxInt.

Why is the value of DC different in D2007 and DXE2 when run on the same machine (same project, same code, same OS)?

Is it safe to cast the DC to WParam (which I think is an unsigned integer) instead?

deonvn
  • 35
  • 4
  • I'd strongly recommend you to employ casting to `WParam`, which ought to compile in both environments. – OnTheFly Mar 28 '13 at 21:46

2 Answers2

3

Your cast is incorrect in modern Delphi versions. The second parameter of Perform is typed as WPARAM which in XE2 is unsigned. So if you were going to cast then you should cast to WPARAM.

In 32 bit code your cast re-interprets large values of DC as negative values. Then when you pass to an unsigned parameter and the range check error ensues. In 64 bit code your cast would result in pointer truncation.

But you don't need to cast anyway. That's because HDC is UINT_PTR and so is WPARAM. Simply remove the cast:

Control.Parent.Perform(WM_PAINT, DC, 0);

The definition of Windows types has traditionally been a mess in Delphi with many of the key types defined incorrectly. When the 64 bit Delphi compiler was introduced Embarcadero chose that moment to correct these errors.

On older Delphi versions the cast was needed because the second parameter of WPARAM was signed, but HDC was unsigned.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Just found this [previous post](http://stackoverflow.com/questions/7837084/when-did-wparam-change-from-being-signed-to-unsigned) which states that WParam changed to unsigned in XE2. So if I understand correctly, if your code is going to be compiled in Delphi versions prior to XE2 you should cast HDC, but then cast it to WParam (not Integer). As of XE2 onwards you should not cast HDC at all. Does that sound about right? – deonvn Mar 28 '13 at 12:06
  • Yes I think that is correct. The basic problem is that the old versions of Delphi did it wrong. So you had to cast to make up for those errors. If you want code that compiles on old and new, then cast to `WPARAM`. – David Heffernan Mar 28 '13 at 12:11
1

be carfull type integer is not WParam .. you need to convert DC type to WParam type

 Control.Parent.Perform(WM_PAINT, WPARAM(DC), 0);
SMP3
  • 71
  • 1
  • 6
  • You don't need to cast an `HDC` to `WPARAM` since they are already compatible. They are both `UINT_PTR`. – David Heffernan Mar 28 '13 at 10:44
  • @David, that's what you should not rely on. You don't need to do it now, but who knows, `HDC` or `WPARAM` may become defined as different type in the future. [+1] – TLama Mar 28 '13 at 10:48
  • 1
    @TLama It only changed because Borland screwed it up way back when. In the rest of the world, it's been unsigned forever. It won't change because doing so would break everything! Go back far enough and the Borland declaration for the parameter was `Integer`. So casting to integer would have been right then, by your analysis. But that's what led to the error in the first place. Now that the types are correctly declared, casts can be removed. The problem with casting is that it takes you outside the type system. Casts are always a code smell. – David Heffernan Mar 28 '13 at 10:53