1

I was debugging a complicated bug recently. It was caused by accessing a non-existing Form.Handle (garbaged pointer). The bug revealed itself in rather unexpected way for me - accessing Forms Handle caused resizes and repaints.

I would expect accessing Form.Handle by a garbage pointer would just return some garbage THandle. Expecting that the Handle is created once on form creation and stays the same till the Form is destroyed.

The question

Why is it so, that TForm.Handle is not a field that gets initialized on form creation and is accessed via

property Handle: Integer read FHandle;

, but is a getter

property Handle: Integer read GetHandle;

that creates the Handle and even the Window (CreateWnd) on first access?

Mike Torrettinni
  • 1,816
  • 2
  • 17
  • 47
Kromster
  • 7,181
  • 7
  • 63
  • 111
  • 2
    See [Delphi XE2, vcl styles recreating window handle](http://stackoverflow.com/q/15894918/576719) and [PostMessage returns “invalid window handle” in thread](http://stackoverflow.com/a/3474466/576719). In short, windows needs to recreate the handle in certain situations. – LU RD Jun 03 '16 at 12:26
  • Read about VCL window recreation – David Heffernan Jun 03 '16 at 12:30
  • Because changing certain properties of the window require it to be destroyed and recreated (see `RecreateWnd` and count the number of times it is called in the Forms unit). The *complicated bug* was caused by your not understanding the Form.Handle properly, not a problem with how TForm uses it's handle. :-) – Ken White Jun 03 '16 at 12:30
  • The question seems to relate/mix the structure of the property with window [re]creation. That's why you get comments on one of the topics and an answer on the other. – Sertac Akyuz Jun 03 '16 at 13:02
  • Not a bug, but severe misconception. Your assumption is simply invalid. See https://stackoverflow.com/questions/21011780 and https://stackoverflow.com/questions/582903 – Free Consulting Jun 03 '16 at 14:25
  • @FreeConsulting Did you read the question? The text in *italic* is not the problem, it's just an intro. – Kromster Jun 03 '16 at 14:37
  • @Kromster, yes I did. This is by design, because some of window/control styles **are not settable** by `SetWindowLong` on live `HWND`, but have an effect at `CreateWindow` call only. So, VCL owns the handle thru `HandleAllocated`, `HandleNeeded`, `CreateHandle` etc – Free Consulting Jun 03 '16 at 14:53

1 Answers1

9

The form object can exist even when the underlying OS window doesn't. During those times, the Handle field would be 0, which isn't helpful to code that needs a valid window handle. To ensure you get a valid handle each time you need one, you'd need to call HandleNeeded prior to referring to the Handle field. As a property with a getter, the property can call HandleNeeded for you automatically, making it easier to use the Handle property.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • "making it easier" except times when accessing Handle from different thread, which looks like a really bad idea now on. – Kromster Jun 03 '16 at 12:49
  • 2
    Yep. Call `HandleAllocated` first, in those cases, to guess whether subsequent access of `Handle` might be valid. You can't *know*, because the main thread might destroy the window between time of check and time of use. Ultimately, about doing UI stuff in other threads. If another thread *needs* to know a window handle, make the main thread provide the handle to the other thread (rather than the other thread fetching the handle itself), and also make the main thread take on the responsibility of ensuring the provided handle remains valid for as long as the other thread needs it. – Rob Kennedy Jun 03 '16 at 13:02
  • 3
    @Kromster, if you want access to the form handle from a thread in order to send/post messages, it would probably be a better idea to allocate a handle with `AllocateHwnd()` in the main thread, and let the thread post messages to this handle. From there messages could be forwarded to the VCL. – LU RD Jun 03 '16 at 13:14
  • 4
    I'd say it more strongly than @LURD. The rule is that you **never** use a VCL window handle outside of the main thread because they are subject to recreation. So you use a window handle that is not, for instance one from `AllocateHWnd`. – David Heffernan Jun 03 '16 at 14:00