Boy, do I feel stupid!
As David pointed out in the comments to take one of this subject, there is a much easier way to get all the instantiated forms at run time:
var CustomForm: TCustomForm; idx: Integer; begin for idx := 0 to Screen.CustomFormCount - 1 do begin CustomForm := Screen.CustomForms[idx]; Memo1.Lines.Add(Format('%s (%s)', [CustomForm.Name, CustomForm.ClassName])); end; end;
Forgot all about
Screen.CustomForms existence. And it’s been there since at least D5… My only excuse is that I haven’t done much UI programming in the last, what, seven years.
There is also
Screen.Forms, but that only lists
TForm descendants. While
Screen.CustomForms lists all TCustomForm descendants including for example property pages.
There is a caveat in using either. According to the docs, the order in which instantiated forms appear in both lists is affected by the Z-order of all forms. So while you are iterating over one of these lists, you shouldn’t do anything that might affect the Z-order, such as creating and/or activating another form in your application, as that would change the contents of the list!
If you need to do anything like that, then your best bet is still to use
Application.Components like I showed in take one.