am currently developing for a company that recently purchased a new content management system. Due to the number of requested custom enhancements, the vendor phased the implementation. They delivered the upgrades as versioned DLLs to replace their predecessors at each phase.
This process, to no one’s surprise, was very prone to error. The constant unregister, copy, and registration of new, versioned DLLs became incredibly tedious. After the second phase of enhancements I figured it would be worth my time to build a simple GUI to automate the process for future upgrades for any user.
I started this task by planning out my GUI and necessary controls. I needed three command buttons to select the components, remove selected components, or clear the list box. I would need a list box to display the selected components, two option buttons to dictate whether to register or unregister the components, and a command button to execute the procedure.
I wanted to be able to easily choose components from anywhere on our server, so I added a common dialog control. I duly named each of the controls and was ready to begin creating my sub-procedures and functions.
Even when I’m not writing DLLs or classes, I make it a point to maintain a componentized structure. Aside from the procedures for the form controls, I created separate sub-procedures or functions to handle instantiating the Windows Script Host Shell object (WSH Shell), destroying the shell object, and registering/unregistering the components.
|Figure 1. The Component Registrar GUI
Running Regsvr32.exe from the command line allows you to register one component at a time. I have 15 everytime there’s an upgrade.
Build a simple GUI that uses the Windows Script Host to invoke the Windows Shell and loop over all your components from a list, passing them to Regsvr32.
I began by creating two module level variables, statMsg, to store my status messages, and theShellObject for the WSH Shell object. The form controls were all pretty straightforward. The only real time spent coding was on registering the components. When the user clicks the Register/Unregister Objects button, I check to see if any items exist in the listbox, get the total number items, create the WSH Shell object by setting my variable to the createTheShell() function (shown in Listing 2), and loop over each item passing the physical path to the regTheObj() sub-procedure.
Listing 1 is the sub-procedure regTheObj() that registers or unregisters the component. This sub-procedure is declared as private and accepts the object path by reference as a string data type. I declare a variable of the string data type named returnVar to capture the Run method’s return value, and another variable named regType, to store whether you are registering or unregistering the component. The latter is used for our status message.
Next, I check whether the user has decided to register or unregister the component. Depending on which they have chosen, I call the Run method of the Shell object passing in the syntax for the regsvr32 command line, an empty argument for the window style, and True for the final argument.
After the Run method has been executed, I check to make sure the return variable is not zero?a zero would indicate that there was an error. Then I update the status message accordingly.
The Run method of the shell object creates a new process that executes any environment variables and syntax, an optional integer argument for the window style of the new process, which is not utilized in a VB UI, and a Boolean that dictates whether to immediately return execution to the calling procedure?somewhat like multi-threading?or wait for the Shell’s Run method to complete and return an any error codes.
|Figure 2. Command Line Method: The standard way to run Regsvr32.exe is from the DOS prompt.
In listing 2, the sub-procedure to instantiate the WSH shell object, I first make sure the object has not been instantiated by passing it to the typeName() function. If an object variable has not yet been instantiated, the typeName function will return the string “Nothing.” Alternatively, you could check to see if the typeName() function were equal to “IWSHShell3“, the typeName() return string for the WSH Shell object. I then declare a variable of type object and set that variable to the createObject method, passing in the object identifier, wscript.shell. I set the function name to that variable to return my object back to the regTheObj sub-procedure.
A utility is only worthwhile if it’s available and easily accessible on all your machines, so I ran the Package and Deployment Wizard to make this a distributable application. I would recommend always including some sort of documentation or readme file in your package?no matter how small your application. In this case, the article serves as documentation.
Packaging Your Product
Before you package your project, make sure you compile it. Go to File > Make projectName.exe… and then click OK when the compile dialog opens. To run the package and deployment wizard, go to Start > Programs > Microsoft Visual Studio 6 > Microsoft Visual Studio 6 Tools > Package and Deployment Wizard. Use the Browse button to select your VBP file and click the Package button to bundle your project into a distributable cab or setup program.
When the wizard asks you for package type, select standard setup package and click Next. Then you will have to select the folder in which your package will be assembled. It defaults to the folder where your project currently resides?in most cases that’s fine. When it asks if you want to create the “package” folder because it doesn’t exist, click OK. This is the subdirectory in your project folder where your setup files are assembled. When that’s done, just click Next.
The next step in the Wizard is to choose the Windows Start menu location for your program. I usually stick with the default, which creates a folder under Programs using the name supplied in the installation screen title and then a link to your program with the same name. The next screen is your chance to select the location of your program files and controls. Unless you are putting them in a custom location, the install paths use system environment variables, such as %(WinSysPath)%, which points to the system32 directory.
After clicking Next, you need to set whether or not other programs will share your program. This effects the uninstall process. If your program is shared, it will not be removed unless all sharing programs are removed as well. Finally, supply a name by which to save the setting for this session. You can create multiple packages for your program, each using different settings, so name them intuitively.
Finished At Last!
Now you can finally click Finished and let the assembly begin. Once complete, it will display a report showing how it packaged your files. There is now a batch file you can run to create another cab file?in case you updated any files in your program. This eliminates the need to run through the wizard again if you are recreating the package with the same setting.
Now you can distribute the cab file either on CD or via a file server that your users can access to install the program. All the project files, as well as the packaged cab file, are included in the code download.
Whenever I come up with an idea like this, I always think someone else must have built the same thing?but in most cases, I like to build before I buy. Retail applications are not developed for you personally or your specific needs, and there is always room for education and improvement when you do it yourself.