This became too long to put in one post, so I broke it into two parts. Part one will cover the QTP Extern Object and the User32.dll function SetForegroundWindow. Part two will cover the BrowseForFolder function on the Shell.Application object.
Over the past few months, I have done a couple of custom testing functions that require user input. For example, in one script I was exporting an Excel file with some metrics pertaining to average log in and page load times. I wanted to prompt the user (usually me) to enter a location to save the Excel file. I found the BrowseForFolder function on a Windows Shell.Application object, but the folder browser dialog never popped up in front. I looked high and low for a way to move my desired window to the front. The only thing I could find was WScript.AppActivate, but I never had any success with that strategy. I ended up giving up for a while, since I was usually the only one running either of these scripts, so I knew what to do when the script paused, anyway.
My next attempt came a few days ago as I was trying to figure out a good, best practices method for abstracting test data and environment specific values such as URLs and DB connections. I am attempting to set up a system where if the test is running in a test set, then the test set itself will dictate the environment specific values, but when you are developing and debugging in QTP, a local config file would dictate the environment specific values. I also wanted it smart enough that if someone who had no knowledge of this system could run the tests and it would prompt them for input regarding which environment they wished to be the default and to automatically create the local config file.
Enter the DotNetFactory. I must preface the rest of this by saying that I am obsessed with using .NET objects in my scripts now, so a bulk of my postings about QuickTest Pro will most likely be on that subject. I figured that I would present the user with a custom form with some instructions, a drop-down, and a couple buttons to allow them to input the default environment facilitating the creation of the local config file for a user who doesn’t already have one. This seemed all the more feasible given the fact that the .NET Form Class has a ShowDialog method. After coding up my dialog, testing it directly in a script, and thinking I got it, I moved the code to a function library attached to the scripts for use throughout the project. Alas, when the code is called from a function library, the dialog never pops to the front.
I spent a bunch more time trying AppActivate and other fruitless strategies, but all the research into these techniques, however futile, ultimately educated me on Windows Handles, the QTP Extern object, and other useful info. The solution I found to bring my custom .NET Form to the front was to access the User32.dll function SetForegroundWindow. The only way I could figure out how to utilize this function was to use the QTP Extern object. I will offer a warning at this point that in my research, I got the impression that this technique may not always work, although it’s worked for me so far, and that it may not work for Vista or Windows 7 computers. I’m not exactly sure why, but I guess Microsoft was trying to make it more difficult for applications to push their way to the front since a lot of developers were using this technique. Apparently, this is why the flashing application handle on the task bar has become the norm.
The Extern object is used for declaring a function from an external .dll file for use in a script or function library. One of the things that confuses me about the Extern object is that in the function declaration, you specify the return type for the function and in this case it is a boolean indicating if the function was successful or not, but there is no mic constant to specify a boolean return type. If anyone knows what that is all about drop me a line. Since there is no constant for a boolean return type and I’m not sure if I would really want, or need, to do anything about it if the function returned false anyway, I used void for the return type. Here is how you declare SetForegroundWindow in a script or function library:
Extern.Declare micVoid, "SetForegroundWindow", "System.User32.dll", "SetForegroundWindow", micHwnd
The first argument is a built-in QTP constant for return type. Refer to the QTP help files for more information. The second is the function name. The third is the .dll file name. The fourth is the function “alias” which can specify different entry points for different character encoding. Click here for more information. The fifth and any following arguments are the type(s) for the arguments that will be passed to the SetForegroundWindow function. In this case there is one argument required and it is the Windows Handle for the application you want to bring to the front. I discovered that this is simply a number and you can pass it as a long integer.
I want to point out that I truly don’t have a full grasp on the ins and outs of the underlying functionality going on here. Most of my knowledge comes from reading documentation, other blogs and articles, web searches, and a ton of trial and error. Anyway, here’s the code to show a .NET Form and bring it to the front:
Dim myForm Set myForm = DotNetFactory.CreateInstance("System.Windows.Forms.Form", "System.Windows.Forms") Extern.Declare micVoid, "SetForegroundWindow", "user32.dll", "SetForegroundWindow", micHwnd Extern.SetForegroundWindow CLng(myForm.Handle) myForm.ShowDialog myForm.Dispose Set myForm = Nothing
Stick around for part two where we’ll look at making the BrowseForFolder dialog on the Shell.Application object snap to the front and explore Windows Handles in a little more detail.