Copy a single Form, Report, Browse, Letter, or Label layout to a Remote Site
by Jim Chapman
I had a request from an Alpha Five user to be able to send a single report to an end users site. Although we can easily zip up and send the data dictionary files for any given table or set, this overwrites all objects associated with the table or set. If your copy of a database (excluding data of course) is matched exactly with the remote site, then this is not a problem. But if the end user site has the full version of Alpha Five and works with it in developing and extending the application, you cannot send and overwrite their data dictionary files. Another use for these routines might be the creation of incremental backups of complex reports and forms.
Although the original request was for the ability to transfer a single report, if I can transfer a report, I can transfer any layout object, report, form, label, or letter.
In my mind I saw two approaches to this problem, I could create a 'transfer' dbf table and related files to be the container to carry these needed layout records to the remote site. The advantage of using a table is that it would allow for more than one layout object to be transferred. I decided not to transfer the layout object via normal dbf table structures. I decided to transfer a single layout in a small binary file. Multiple binary transfer files can be created and emailed to a remote site and installed in a single procedure. The single file approach seems more elegant to me.
To accomplish this task requires a script that I call ObjectImport, to be available at the remote site. A script I have called ObjectExport is needed to create the binary file to send to the remote site. I have tried to make the use of these scripts as generic as possible, but they can easily be modified for your particular need if you know a little Xbasic.
When the ObjectExport is run, a Xdialog box is displayed where the user selects an object type to export, either a form, report, letter, or label.
(EDITOR'S NOTE: The browse object was inadvertently left out of the article, screen shots, and the scripts. This has been corrected. The scripts available for download include the capability to transmit browse objects.)
Once the object type is selected the Xdialog box displays a list of available object of this type in the current database, along with it's data dictionary path.
Selecting the desired object to export brings up another Xdialog box that will allow you to select where the binary file will be saved on your local system.
The routine defaults to the current data path as the location to save the binary file. If the routine finds an identically named file in the chosen path, another Xdialog is brought up allowing the user to either overwrite the existing file, or increment up the file name.
That is it. The binary file will be created and saved to the location specified, and a final Xdialog box appears letting the user know that the file has been created.
The naming convention I have used is 'ObjectType' + 'ObjectName' + '*.abn'. So if you chose to export a report named "QuarterlyRpt", the binary file created would have the name "ReportQuarterlyRpt.abn". This file is then transferred to the receiving system, whether that be a remote site, another system on your network, or just another database on your system.
On the receiving end, the *.abn files need to be placed in the databases' data path. The ObjectImport script is designed to look in the data path of the current database for files with the *.abn extension. This could easily be changed if you have another location that makes sense for your situation. Once the binary file or files have been placed in the data path, running the ObjectImport script will import the layout object into the current database.
The ObjectImport script checks to make sure there is a data dictionary in the current database that matches the data dictionary name on the originating system. If you created the export object from the Customer table on your system, the importing routine will only import the object to the Customer table's data dictionary. It is possible to have two identically named tables/sets in the same database is the tables or sets reside in different paths. Although I do not think this is a very good idea except for special circumstances, it is allowed. If the import script runs into two or more identically named data dictionaries in the same database it will give a message to the user and exit the routine without importing the object. Although this would be coded around by allowing the sender to specify a path for the data dictionary, I decided not to mess with it, as it should be an extremely rare situation.
If the ObjectImport script finds a single instance of the correct data dictionary, it checks the data dictionary to see if a layout object exists of the same type and name. If it does, then the routine overwrites the existing layout object. If the object does not exist, the routine creates a new object.
I more than one *.abn file is found, the ObjectImport script will loop give the user a message asking if they want to continue importing objects, and loop through all files found if the user so chooses.
I will not bore you with a blow by blow of these routines, but I will share the heart of how these scripts work. With Alpha Five's rich Xbasic language, creating the routines was straight forward.
Data dictionary files are regular dbf file structures with different extensions. Alpha Five gives us the tools to read and manipulate these files directly. I use the TableName.record_data_set() method, (only of course using a pointer to an open data dictionary file instead of a table pointer), to set the appropriate layout record data to a blob variable. Taking this blob variable I resize it and add 100 bytes to the end of it. In this 100 bytes I store the name of the object, the object type, and the data dictionary name using the using BlobVariable.pokec() method. A weak point of this routine could be the 100 bytes I add for the name, type, and data dictionary name. One null terminating byte must be left at the end of the file, and I use up two bytes with separation characters between the three character strings. This leaves 97 bytes for the names. It would of course be very simple to increase the size of this 'extension'. But in thinking about it, if you use huge names for your objects……….. well you know what I am thinking :-)
I make sure that this character string is poked into the blob AFTER the original null terminating byte of the blob. Now the blob contains the actual layout object definition, and the information I need at the receiving end to import it into the correct data dictionary and determine if it is a new object or a replacement object.
On the receiving end I was curious to see if my 100 byte extension would have any negative effects on how Alpha Five imported the binary file. I planned on having to remove the 100 bytes but it does not appears to cause a problem. I assume that when Alpha hits the null terminator byte at the end of the original blob which I was careful to preserve, it stops processing the 'DataDictionaryName.record_data_set()'. Either that or the 100 extra bytes are hiding in the layout ready to bit me later :-)
The scripts in their present form do not differentiate between a shadowed database and a source database, so make sure you are logged into the 'real' database on your server, otherwise the new object will be overwritten the next time the shadowed database is refreshed.
I want to give special thanks to Ron Anusiewicz and Scott Emerick. Ron found several bugs for me and gave great suggestions, among them suggesting that the user be able to select the storage location for the binary file on the originating end which was implemented. Ron has taken these scripts and modified them for his specific situation, adding some great touches. I believe his versions will also be available on the code archives.
I had originally written these scripts in version 6, using a couple of the new functions that make life so easy for the Xbasic coder. Scott Emerick had a need for these routines, but several of his clients are running version 5. Scott replaced my v6 dependent syntax with v5 syntax making the routines compatible with both versions.
Download the ObjectExport and ObjectImport scripts here, or they can be found in the code archives of the Alpha Software message boards.