Tommi Prami 130 Posted July 31, 2019 let's say if I have window Handle (Delphi app form), found by some windows API like FindWindow etc. Sometimes it seems that Window is created and has an handle but not fully functional yet. Is there a way to query with windows API that Delphi form is run all OnCreate etc events amnd is fully visible and all components are ready for user. Reason I as we use AutoIT to automatically test our Apps,, and sometimes Form is not ready yet. No fully visible or still runnin initialization events (OnCreate etc). If not I've suggested to add out base form class an message handler which we could use to quety, then problem would be how the Form it self Knows everything is OK, up and running 🙂 -Tee- Share this post Link to post
PeterBelow 238 Posted July 31, 2019 (edited) There is no panacea for this kind of problem, too much depends on how the form in question has been set up. What you can do from "outside" the process is check if the window is visible (IsWindowVisible) check whether it is the current foreground window (GetForegroundWindow) check whether its message loop is running (WaitForInputIdle, or use SendMessageTimeout to send a do-nothing message to the form, e.g. wm_null, the call will not return until the loop is running) Nothing will help you if the form does some kind of delayed initialization, e.g. using a timer started when the form is created. Also keep in mind that a Delphi form may recreate its window handle at the drop of a (virtual) hat during the initialization phase. Edited July 31, 2019 by PeterBelow 1 Share this post Link to post
Der schöne Günther 316 Posted July 31, 2019 4 hours ago, Tommi Prami said: to add out base form class an message handler which we could use to quety, then problem would be how the Form it self Knows everything is OK, up and running Wouldn't that be the easiest? I don't see much of a "problem" of how to know when everything is ready. By default, it should be after the first time OnShow (or maybe even OnActivate) has been called. This can be done in your base class. If you need more elaborate logic in one form class, then you can override that behaviour. 1 Share this post Link to post
Tommi Prami 130 Posted July 31, 2019 53 minutes ago, PeterBelow said: Nothing will help you if the form does some kind of delayed initialization, e.g. using a timer started when the form is created. Also keep in mind that a Delphi form may recreate its window handle at the drop of a (virtual) hat during the initialization phase. Delayed initialization is an separate problem I think, and that can be handled Case by case, if needed. How, why and when Delphi will recreate the Hvnd for a Form? Never heard of this, this might explain rare weirdness. -Tee- Share this post Link to post
Der schöne Günther 316 Posted July 31, 2019 (edited) A TWinControl has a method RecreateWnd(): http://docwiki.embarcadero.com/Libraries/en/Vcl.Controls.TWinControl.RecreateWnd Maybe you can have a look at the VCL sources where this gets called... Edited July 31, 2019 by Der schöne Günther 1 Share this post Link to post
Tommi Prami 130 Posted July 31, 2019 17 minutes ago, Der schöne Günther said: A TWinControl has a method RecreateWnd(): http://docwiki.embarcadero.com/Libraries/en/Vcl.Controls.TWinControl.RecreateWnd Maybe you can have a look at the VCL sources where this gets called... It seems this can happen (On Form) quite common places. Not too many but still. Did not know any of this, Always thought that handle would be totally permanent on it's whole life time... -Tee- Share this post Link to post
PeterBelow 238 Posted July 31, 2019 2 hours ago, Tommi Prami said: Delayed initialization is an separate problem I think, and that can be handled Case by case, if needed. How, why and when Delphi will recreate the Hvnd for a Form? Never heard of this, this might explain rare weirdness. -Tee- Some of the form properties (e.g. border and bordericons) are implemented via window styles on the API level, and Windows only honors some of the styles when the window is first created. Changes to these properties recreate the window handle for this reason. Another reason are modal forms with popupmode pmauto or pmexplicit; their window handle has to be recreated when they are shown to tie them to their popup parent in Z-order. Changing the formstyle also recreates the handle. 1 Share this post Link to post
Remy Lebeau 1394 Posted July 31, 2019 8 hours ago, PeterBelow said: check whether its message loop is running (WaitForInputIdle, or use SendMessageTimeout to send a do-nothing message to the form, e.g. wm_null, the call will not return until the loop is running) You have to be careful with WaitForInputIdle(), though: WaitForInputIdle should really be called WaitForProcessStartupComplete WaitForInputIdle waits for any thread, which might not be the thread you care about 1 Share this post Link to post
Tommi Prami 130 Posted August 6, 2019 While was walking to work had couple of ideas on this, What if at FormActivate (For example) event of base form, I would do either. 1. Send message to window it self, If I've understood correctly window will not receive that message untill it has processed all the Form initializations of it self, and is able to recveive messages again. 2. Create and start timer and disable and free it on first tick. I think this is essentially same as the method 1. Some codes, me included, are not used to using windows messages too much. Delphi hides the need quite well. When the message arrives or timer fires set the flag that can be queried with other messsage from outside of the app. This should give pretty good starting point. -Tee- Share this post Link to post
Attila Kovacs 629 Posted August 6, 2019 you can detour TForm's DoCreate, DoDestroy, DoShow, Activate etc... from a separate unit and set some flags if it helps Share this post Link to post
Tommi Prami 130 Posted August 6, 2019 1 hour ago, Attila Kovacs said: you can detour TForm's DoCreate, DoDestroy, DoShow, Activate etc... from a separate unit and set some flags if it helps Could you elaborate bit more? What this means in practise -Tee- Share this post Link to post
Микола Петрівський 10 Posted August 6, 2019 (edited) We had similar problem, except, that we wanted to know, when app finishes processing any long task, and is ready to accept new input. And we wasn't allowed to change the code of the app. Our first attempt was to use SetWindowsHookEx in WH_FOREGROUNDIDLE mode. That was working in most cases, but sometimes we had situations, when the last message in the message queue is actually the one, that causes processing of long task, so our hook was triggering at the beginning of the processing, not the end. Also, this hook will hang until some message will get in to message queue, so some sort of wake up message is required. Finally we decided, that since target app uses runtime packages, we can call VCL for help. Now our test app is using windows hooks only to inject our code (dll compiled with runtime packages) in to target process. Then we create event handler for Application.OnIdle. This approach is much more reliable, something like 95%. If you can change the code of target app, then it will the best approach. P.S. You could avoid all of that, if VCL supported UI Automation Edited August 6, 2019 by Микола Петрівський Share this post Link to post
Guest Posted August 24, 2019 On 8/6/2019 at 12:09 PM, Микола Петрівський said: P.S. You could avoid all of that, if VCL supported UI Automation And if that could trickle down to 3rd party!!! Oh what a boon! Share this post Link to post