Obj2Bmp - A Developer's Tool

George Tasker

gtasker@compuserve.com

August 29, 1999

 

Preface

 

One of the things I like to do least, but is one of the most essential parts of developing software, is documentation. I’d much rather write code than writing about the application I’ve developed. To make matters worse, the demands for increasingly more graphic on-line help means that not only to I have to write about the application, but I also have to provide images of the application’s various components. This can mean spending time capturing images of forms, pasting them into Paint Brush or some other graphic application, then laboriously editing them. All too often, I find myself having to repeat the process because I made a mistake in the editing process.

 

From the user’s perspective, however, graphical help greatly eases the learning curve. Without it, the differences between a command button and an option button are meaningless. Failing to provide solid graphically based help can mean that you spend even more time supporting the application.

 

In order to address these issues I developed Obj2Bmp. What it allows you to do is select either a form or object reference, then create a bitmap in one of three color options (16, 256, or 24 bit). Additionally, when selecting the object, you may be able to enable or disable its appearance. This, however, on the code in the form which controls its appearance.

 

Setting It Up

 

The first thing you’ll need to do is create a directory for the Obj2Bmp files and copy them there. Once this is done, in VFP open the Obj2Bmp project, and compile it. In order for the application to work properly, it needs to be compiled under the version and service pack of VFP you are using.

 

Before using the application, you may want to set the FOXTOOLS.FLL file as the library. The application, in order to do what it does must have this library loaded. If you do not, the application will prompt you for the location of the library. If you fail to indicate where it is, the application will terminate.

 

Once the application has been created, start it using the following:

 

oObjPicker = NULL

DO Obj2Bmp.app WITH oObjPicker

 

This will return an object that will be global in scope. This is necessary since, should the object go out of scope, the form will be released.

 

Using Obj2Bmp

 

Figure 1 was created using Obj2Bmp.

 

 

Figure 1

 

Figure 1 shows the Obj2Bmp form. The images used to display the individual elements of the form should be familiar. If an object exists on the form, but is not visible, it does not appear in the treeview.

 

The combobox beneath the treeview controls which form’s objects are displayed in the list. When the application initially starts, the Select Object form will usually be the form displayed. If, however, one or more visible toolbars (other than VFP’s) are present, they will appear. The combobox displays the title bar of the available forms or toolbars. The list displays the individual objects, including the form or toolbar, by name.

 

To create a bitmap, click on the desired object in the treeview. This can be the form or any object shown. Container objects will display the plus sign (like ColorOpts) when they can be expanded. You may select any individual object that is displayed by the treeview.

 

If you wish, you may click on the Disabled check box to toggle the object’s enabled property. Items that are disabled on the form may be enabled by un-checking it. The converse is also true.

 

To capture the object, click the capture bitmap. The object will be captured in a bitmap, using the object’s name as the primary part of the filename.

 

To close the form, either click the close button in the upper right of the form, or the Close command button.

 

The Refresh command button is (unfortunately) a holdover from earlier versions and may not appear in future releases. It reloads the combo box. This functionality, however, will occur whenever the form is activated.

 

Modality and Other Form Issues

 

As you might expect, using a modal form might cause some problems. The same holds true for forms with AlwaysOnTop set to .T. or, in VFP 6.0, AlwaysOnBottom set to .T.. There is a solution, however, that does not require any modification to the form prior to running.

 

If the form is saved as a class, simply create the form from the class in the Command Window and do not issue a call to the form’s Show method.

 

If the form is normally started with a DO FORM command, issue the following, or similar command from the Command Winndow.

 

DO FORM MyForm.scx NAME oForm NOSHOW

 

In both cases, Obj2Bmp will display the form in the manner appropriate (modeless and with neither AlwaysOnTop or AlwayOnBottom set to .T.)

 

Other cases that may cause problems may include top-level-forms or forms that may be moved to the Windows desktop. Unfortunately, because these properties are read-only at runtime, nothing may be done to resolve this by the application.

 

Known Issues

 

Unfortunately, it was necessary for me to hard code the necessary structures required to produce 16 and 256 color bitmaps. These structures are based on the default Windows’ color palette. If the colors do not appear properly for these color modes, this is the reason. This doesn’t apply to 24-bit color.

 

VFP 5.0 cannot capture forms without a title bar. The reason for this is that a caption is required in order to get the form’s window handle. In VFP 5.0, part of the requirement for producing forms without a title bar was to remove the caption. In VFP 6.0 this is not an issue, since setting the TitleBar property to zero removes the title bar, but leaves the caption unaffected. If a form fails to appear in the list it is because the caption is missing.

 

Overlapping objects may not properly be captured. An illustration of this is the label that overlaps the option group that selects the color mode. If you create a bitmap of the option group, you’ll note that only the bottom portion of the label appears. The application does not attempt to capture overlaps such as this.

 

You may experience problems with the application correctly locating the top or left edge of an object. One or more of the object’s containers being positioned in such a way that the top or left location of the container is a negative number would cause this. While the application attempts to properly resolve this, and, to date, this has not appeared, it is a possibility.

 

If multiple forms having the same caption are found, they are renamed. In order to properly retrieve the window handle, a form’s caption must be unique in the collection.

 

Objects within containers can, for the most part, be selected. One notable exception to this is a grid. You may only select the entire object in this case. Headers, columns, and the contained controls are not available.

 

The target location of all bitmaps is in the current default directory. Further, the name of the file is determined by the name of the object. At this time, no plans exist for allowing selection of either the location or the file name used. If a file already exists in the current directory, you are prompted and given the opportunity to give the file a different name.

 

If a top level is selected and that form is maximized, you may get an image that is off by one or two pixels. This problem is being investigated and, hopefully, will be resolved in a future release. This does not affect objects on the form.

 

Forms whose ShowWindow property is set at 2 (As Top Level Form) can cause problems if a bitmap already exists with the same name as the one being created. The reason for this is that the dialog that advises of the duplicate file brings the VFP main window back on top. Since the bitmap is not as yet created, an image of the VFP screen may appear. This may be resolved in future releases. At this time, however, it is not. If you get this dialog when working with a Top Level form, re-name or delete the existing bitmap and then try to create the bitmap again.

 

Tips

 

The BmpMaker class can be used to capture entire forms independently of the application. The resulting bitmap can then be printed using the ShellExecute() API call. In order to do this, you first must retrieve the window handle using Foxtools. Assuming that oForm is the name of the form to be captured, and Foxtools is already loaded, the syntax to get the window handle would be:

 

lnhwnd = WhTohWnd(_WFindTitl(oForm.Caption))

 

Next, create an instance of the class:

 

SET CLASSLIB TO BmpMaker ADDITIVE

oMaker = CREATEOBJECT(“BmpMaker”)

RELEASE CLASSLIB BmpMaker

lcfile = oMaker.MakeBitmap(lnhWnd)

oMaker = NULL

 

This will return the name of the 16-color bitmap in the current default directory. The name of this file will be a generated by the class and will be unique. Optionally, you may set the cFileName property of the oMaker object to whatever name you desire prior to calling the MakeBitmap() function. If you wish to create a bitmap with a higher color resolution, pass one of the following as a second parameter to the function:

 

4 – 16 Colors

8 – 256 Colors

24 – 24 bit color

 

Note, you should take whatever steps are necessary to assure that the form is active and not obscured by any floating toolbar or form with an AlwaysOnTop property set to .T.

 

The used the following code to print the bitmap. In this example lcfile is the name of the file to print.

 

DECLARE INTEGER ShellExecute IN Shell32;

  INTEGER hwnd, STRING @lpOperation,;

  STRING @lpFile, STRING @lpParameters,;

  STRING @lpDirectory, SHORT nShowCmd

lcop = ‘print’

lcparms = “”

* Note this function is part of Foxtools in 5.0

lcdir = JustPath(lcfile)

= ShellExecute(0, @lcop, @lcfile, @lcparms, @lcdir, 0)

 

This will cause the bitmap to be printed by whatever application (usually Paint) that it’s associated with. The zero parameter as the show command will cause the application not to be visible. The potential problem with this method is that large bitmaps may be cut off.

 

The FileExists object uses a method I demonstrated in a FoxPro Advisor article. If you look at the form, you’ll note that no icon is shown. However, when the form is displayed, the standard Windows Question Mark icon appears. The Init method of the class contains the code to create the icon, along with the definition of the question mark (IDI_QUESTION). Besides the question mark, the following values may be used.

 

#define IDI_APPLICATION     32512

#define IDI_HAND            32513

#define IDI_EXCLAMATION     32515

#define IDI_ASTERISK        32516

#define IDI_WINLOGO         32517

 

One of the things that I initially didn’t like was the way the treeview would “jump” despite the fact that LockScreen was set to .T.. After some research, I discovered the reason why this occurs. Windows can only lock the state of one window at a time, and the treeview is a different window. The code in the Init and the click event of the Refresh command button shows how to lock the state of an OLE control. However, because each situation is different, what works here may not work in every case. It is highly recommended that Spy++ be used to determine what level in the child window hierarchy the OLE is, and that this information be used to create a solution specific to the individual problem.

 

Modifications

 

August 14, 1999

 

Code to handle modal forms, as well as the AlwaysOnTop and AlwaysOnBottom issues, was added to the new method ShowForm.

 

August 29, 1999

 

Corrected bug connected with the selection of the “Cancel” command button being chosen when a file already exists.

 

Modified the program to take into account Top Level forms with menus.

 

Acknowledgements

 

I’d like to acknowledge those kind folks who served as my beta testers on this project: Nancy Folsom, John Koziol, Ed Rauh, Barbara Paltiel, David Frankenbach, and Cetin Basoz. Without them, and their input, I might never have completed this project. I’d also like to thank Monte Murdock for uncovering a bug and reporting it to me.

 

Standard Disclaimer and Stuff

 

Obj2Bmp is freeware. No warranties, guaranties are either intended or implied. You may freely distribute any or all of it. You do so, however, at your own risk. Further, while I’ll supply support (at gtasker@compuserve.com), I cannot promise that all problems will be able to be resolved. Furthermore, so and so forth, blah, blah and blah, and the rest of all that legalize that usually appears in print so small you need a microscope.