Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why shouldn't you use a handle during component creation or streaming?

I want to make a custom VCL control that wraps a SDL rendering surface via the SDL_CreateWindowFrom function. SDL_CreateWindowFrom takes an existing HWND handle and puts a high-performance rendering context (it has several backends available, including DirectX and OpenGL) onto it.

The helpfile says "Do not refer to the Handle property during component creation or streaming." But it doesn't say why. It says that the first time you try to access the Handle property, it'll call HandleNeeded to ensure that a valid handle exists.

So I have two questions. 1: What's the reason why you shouldn't reference the Handle property during component creation? 2. If the entire point of the control is to wrap a rendering surface that requires a HWND to be initialized, when is it safe to perform the initialization that (ideally) ought to be taking place during creation/streaming?

like image 703
Mason Wheeler Avatar asked Dec 03 '22 08:12

Mason Wheeler


1 Answers

At it's core, it's a performance thing. There are potentially other "bad" side-effects that can happen as well since during the streaming process. Things are in "mid-construction" and all that is normally expected to be there are probably not.

When you reference the "Handle" property, this will initiate the handle creation process. This is because reading Handle actually calls GetHandle. Do this too soon in the streaming process, and you may end up with, at best, slower streaming performance, at worse, a partially configured "handle."

If you need to refer to the Handle properly from within a property setter, you should check if the handle has been created by checking HandleAllocated, and only then do you reference it. If you needed to make some flag changes to the handle like calling SetWindowLong() or something, then you should "cache" that state in the component instance and then override CreateWnd and apply those settings at that point. Another option is to defer all handle access while streaming (if csLoading in ComponentState then) until the Loaded virtual method is called.

Finally, you need to be aware of cases where your handle may need to get recreated. This can happen if the surrounding form or the parent component's handle goes through a recreate process. Up until more recent releases of Windows, the only way to change some window flags was to destroy the handle and recreate with new flags in the CreateWindowEx() call. There are many components that still do this. You know if you're in a recreate situation by checking (csRecreating in ControlState).

So to directly answer your question, the best place is to override CreateWnd and do your work in there. CreateWnd will only be called when the handle gets created. A properly designed component should get only one call to CreateWnd right before it is going to be shown.

like image 52
Allen Bauer Avatar answered May 01 '23 05:05

Allen Bauer