COM+ is a key Microsoft technology. But the need to rebuild COM+ applications and packages in a development environment gets to be quite a chore. I use a relatively new VBScript feature, the class construct, to automate the creation of COM+ applications and packages. My code also demonstrates how to use external modules (including a VBScript file) with a Windows Script (WS—.wsf) file.
Anyone who needs to build a COM+ application regularly and reliably can use my script because its generic code constructs a COM+ application based on the contents of three external files that I describe later. The script automates tasks that systems administrators typically perform manually with the Microsoft Management Console (MMC) Component Services snap-in. This automation is more useful for large, complex, or frequently built COM+ applications. Using a .wsf file and a VBScript class isn't required but illustrates the suitability of these tools for this type of task.
Windows 2000 natively supports VBScript, VBScript Class objects, .wsf files, and the COM+ subsystem. A Windows NT 4.0 environment can support my script if you install Windows Script Host (WSH) and VBScript 5.0. Note, however, that NT 4.0 COM objects in Microsoft Transaction Server (MTS) aren't compatible with COM+. Win2K's COM+ has evolved from its NT 4.0 COM predecessor to a point at which some of the names and features are different. Thus, you might need to install the Microsoft Windows NT 4.0 Option Pack for COM+ compatibility.
Enterprise applications must support access to multiuser databases, multithreading, security, asynchronous transactions, and more. The process of developing, deploying, and maintaining such sophisticated and complex applications is strewn with traps for the developer and complicates the lives of administrators.
Microsoft's evolving COM+ family of technologies attempts to handle much of the complexity of enterprise development behind the scenes or at least to simplify its implementation. Using the COM+ model, developers can take advantage of COM+ infrastructure features such as data-access transactions, object thread pooling (which significantly enhances performance for some applications with high processing volume), queued components (which can take advantage of Microsoft Message Queue Services—MSMQ—an optional Win2K subsystem, for asynchronous processing), and remote activation and processing. COM+ also has some advantages for administrators, including security administration, attribute management, and simplified deployment.
I won't go into detail about the flexibility that COM+ security provides, but here are a couple of features. COM+ lets you define roles that classify Win2K and NT users or groups and grant the roles different levels of access to the COM+ components. You can also run a COM+ application in the context of a privileged account so that it can perform precisely defined transactions on behalf of ordinary users. Having this software proxy can be a useful tool when you want your program to do something that you wouldn't want the user to do.
One price to pay for the consolidation of infrastructure features into the COM+ model is that developers and administrators must determine the values of a significant number of COM+ component attributes. For example, for each of your COM+ components, you need to decide the level of transaction support it will use (Win2K currently offers five levels) and whether it will take advantage of object pooling or queued components. You also need to determine whether your COM+ application will act as a server and remain running or spin down after a period of time.
Developers can configure the COM+ attributes when building applications, and administrators can use two interfaces to customize attributes when deploying applications. One interface for COM+ attribute management is the Component Services snap-in (in Programs, Administrative Tools on a standard Win2K installation); the other is the COM automation interface (which my script uses). COM automation is Microsoft's technology that lets scripting languages call subroutines within program libraries. These interfaces are a boon to administrators working with COM+ objects.
Automating COM+ Application Creation
My group has developed a product that consists of more than 200 DLLs. We built the DLLs based on the COM+ model and grouped them into four complementary COM+ applications. We use COM+'s built-in capabilities to export and import each application as a package. This technique creates two special Windows Installer files for each COM+ application, including all its DLLs and their associated settings. COM+ places the files on the target system (the default location is C:\program files\complus applications) and transparently registers all the files in the target system's registry for access by the COM+ subsystem. (See Dino Esposito, "VBScripting Solutions: Manipulating COM Objects in the Registry," March 2001, InstantDoc ID 19824, for an excellent tutorial about the registry infrastructure behind COM objects.)
We build DLLs and COM+ applications on a regular basis multiple times a week. We then deploy the COM+ applications to multiple servers for testing. We've found that when you deal with many components many times a week, it's easy to omit or incorrectly set an application, component, or interface attribute. Automating the application building and deployment process prevents these mistakes and produces consistent COM+ application packages. If you have or plan to have COM+ applications whose configuration you must consistently and reliably reproduce, you'll want to use a script similar to mine. Automating COM+ application creation is especially helpful if your COM+ design takes advantage of attributes on multiple levels (i.e., application, component, and interface levels).
The VBScript Class
COM+ Application Manager.wsf is the main script. It contains one job—Create COM+ App—that I coded in VBScript. The WS script calls the COM+ Application Classes.vbs file to create a VBScript class instance called COMApplication. The WS script also calls two other files—Component Settings.lis and Interface Settings.lis—which I discuss later. You can download all four files from the Code Library on the Windows Scripting Solutions Web site (http://www.winscriptingsolutions.com).
Working with a VBScript class makes your source code closely resemble the resulting COM+ application object. The COMApplication class's properties and methods let you intuitively manage the COM+ application's property and method settings. Table 1, page 6, lists the COMApplication class's methods and the functions they perform.
COM+ Application Classes.vbs is organized into three sections: Public Properties, Public Methods, and a Private area that contains variables and functions referenceable by the public properties and methods but otherwise inaccessible. The two public sections define the exposed interface of the COMApplication class. Programs can read and write to the public properties when they create a COM+ application object. Similarly, programs can call the public methods. Most VBScript classes have public methods, many have public properties, and some have private areas. For thorough coverage of VBScript classes, I highly recommend that you read Dino Esposito, "Creating Classes with VBScript 5.0," December 1999, InstantDoc ID 7670.
Class Public Properties
The Public Properties section of COM+ Application Classes.vbs exposes the public properties of a generic instance of a COM+ application object to a program that calls the COMApplication class. The Public Properties section uses VBScript's Property Let statement to set property values and VBScript's Property Get statement to retrieve values. You can choose which COM+ application object properties to define and expose for your needs. COM+ Application Classes.vbs has a representative selection but doesn't even approach using all the properties available in a COM+ application. Adding properties as they're needed is preferable to attempting to code and test a comprehensive set of properties. Here's a brief description of each of the properties that COM+ Application Classes.vbs includes.
ComponentsCount. This property is a COM+ application attribute that's actually a function that queries the COM+ application to determine the number of components it currently contains. A static COM+ application property that represents this count of application components doesn't exist, but VBScript classes let you define properties that you're interested in or require. COM+ Application Classes.vbs doesn't define a Property Let call for ComponentsCount because the COM+ engine calculates this attribute on behalf of your VBScript Class object—the attribute isn't stored within the actual COM+ application.
Description. This conventional property maps directly to the corresponding COM+ application attribute, so you can set and retrieve it through your VBScript Class object. I use this property to record useful identifying information about the COM+ application, such as my company name, the application version, and the build date.
RunForever. This conventional COM+ application attribute is valid only if you configure the COM+ application for server activation (as opposed to library activation). The Property Let assignment code for this Boolean class property validates the True or False value that's supplied.
QueueListenerEnabled, QueuingEnabled, Activation, and Authentication. These properties are all examples of COM+ application attributes that you can set and retrieve with the Property Let and Property Set statements, respectively. Each Property Let call performs rudimentary validation to ensure that you don't attempt to set a COM+ application attribute to an invalid value.
Class Public Methods
The COMApplication class's public methods are user-defined functions (UDFs) that operate on the COM+ application and its components, interfaces, roles, and other COM+ objects; these functions are available to the calling (public) program. As Table 1 shows, these UDFs perform common tasks, such as creating the COM+ application, deleting it, adding components to it, settings its properties, starting it (if appropriate), and exporting it. Listing 1, page 6, shows the COMApplication class's CreateApplication function.
I want to explain two COMApplication class functions—ConnectToHost and SetApplicationIdentity—not included in Table 1. ConnectToHost is a required function that represents an object in an underlying subsystem (in this case, COM+). Because VBScript and COM+ are separate entities, some mechanism must establish a connection between the abstract representation of an object (the COMApplication class) and the "real" object and its parent subsystem (the COM+ application and the COM+ engine, respectively). The ConnectToHost function makes this connection to the COM+ subsystem on the local machine. It also uses the private GetApp function to query the COM+ application objects on the local machine to see whether the application that the COMApplication class represents already exists. The ability to determine the COM+ application's existence lets me define the COM+ application in a program that calls the application so that I can manipulate its properties or add components to it.
The SetApplicationIdentity function sets the identity of the COM+ application to a valid Win2K or NT account for the purpose of having it act as a software proxy, as I described earlier. The COM+ application can serve as a software proxy only if you configure it for server activation.
The Class Private Section
The COMApplication class's Private section is where you declare the variables and functions that you use to implement the object but that calling programs such as COM+ Application Manager.wsf shouldn't meddle with. One objective of using a VBScript class is to abstract the implementation details and provide as simple and elegant an interface as possible, so you must have a mechanism for handling details without cluttering up the UI. The Private section is that mechanism and is an example of the OOP technique called encapsulation.
I start the Private section by declaring the variables that I use to attach to the COM+ application. These variables are available to the public properties and methods but aren't directly exposed to the calling program.
The two private subroutines in this section are special VBScript class features. Their special functions are predefined (but VBScript classes don't require them). Their names are Class_Initialize and Class_Terminate; other object-oriented (OO) languages often call them the class constructor and class destructor, respectively. Their special purpose is to execute some code once when a script instantiates a VBScript class and once when a script destroys a class, respectively. In COM+ Application Classes.vbs, I use Class_Initialize to create a COM+ subsystem object because this task is a prerequisite of any COM+ interactivity, and I use Class_Terminate to clean up objects I used in the instantiation. In COM+ Application Manager.wsf, I use the command
to create an instance of the COMApplication class and set it to the COMApp variable. I use the command
to destroy the instance of the COMApplication class.
The only private function defined in COM+ Application Classes.vbs is GetApp. This function locates an existing COM+ application with the name you provide and attaches to it so that you can use COM+ Application Classes.vbs to modify an existing COM+ application if you so desire. A calling program can reasonably expect this functionality from a VBScript class without having to explicitly request it, so I made the function private and hid its implementation details.
The Application-Creating Script
The script in COM+ Application Manager.wsf demonstrates multiple features of COM+ Application Classes.vbs by performing typical steps in creating a COM+ application. The script uses local subroutines to wrap the calls to the COMApplication class object for readability purposes. Wrapping adds a calling layer to the script, but it lets a developer or administrator more easily read through the script and drill down a layer to reach only the portion of code that interests him or her.
After the script declares the constants and variables, the script calls the Bind_WSH_Objects subroutine, which simply sets the WSH subsystem objects for use elsewhere in the script if needed. A complementary call to UnBind_WSH_Objects occurs at the end of the script to deallocate these variables. The next step is where the script begins to work with the VBScript class. The script uses the statement I showed you earlier to create an instance of the COMApplication class and set it to the COMApp variable. This action causes VBScript to trigger the execution of the Class_Initialize subroutine I described earlier. The script now has a COM+ application object, but it isn't yet attached to the COM+ subsystem. The script's next call to the ConnectToHost subroutine accomplishes the connection.
COM+ doesn't let multiple active COM+ applications use the same DLL, so the script can't create a new instance of an application if an instance already exists. (An attempt to create an application that has the same name as an existing application or that contains a reference to a DLL contained in an existing application will fail.) Thus, the script's next step is to call the DeleteApplication subroutine to delete an instance of the COM+ application if one exists.
The script now arrives at the objective of this entire exercise: the creation of a new COM+ application. As Listing 2 shows, the script creates the new COM+ application with a simple call to the CreateApplication function of the COMApplication class. This application creation demonstrates how simple and elegant OOP can be, although we've had to do a lot of work to get to this point.
The last two subroutines in the script, AddComponents and SetProperties, complete the task of building and configuring the COM+ application by adding DLLs and setting their COM+ attributes. The AddComponents subroutine expects to find COM+ DLLs in the C:\foo folder and adds all the DLLs it finds there to the COM+ application. The SetProperties subroutine uses two special files that contain component and interface settings for the application. Rather than hard-code specific settings for specific elements into the COMApplication class, I record the settings in specially formatted text files that the script reads at runtime. Two constants at the beginning of the script, ComponentSettingsFilePath and InterfaceSettingsFilePath, contain the paths to the two files Component Settings.lis and Interface Settings.lis, respectively.
The format of these files is simple, and you can use a text editor such as Notepad to edit them. Comment lines begin with a double slash (//). Lines that specify settings have three elements that appear in the following order:
- the component name (in Component Settings.lis) or the component name and interface name in the format component/interface (in Interface Settings.lis)
- the component or interface attribute name
- the value you want to set the attribute to
Listing 3, page 8, shows an Interface Settings.lis file. Note that you must have the exact name of the attribute and a valid value. You can find attribute names at http://msdn.microsoft.com/library/psdk/cossdk/pgadmincollobjectstoplevel_5c6r.htm.
After the script sets the component and interface attributes, its creation of the COM+ application is complete. The script deallocates the COMApplication class, which triggers the Class_Terminate private subroutine I mentioned earlier.
Why a .wsf File?
I chose to use a .wsf file for my script because I've found that these files let me easily build libraries of frequently used scriptlets and reference them where needed. I can place related scripts in one .wsf file. For example, I frequently store the scripts that perform management functions on a COM+ application as discrete jobs in one .wsf file. In addition, scripts written in JScript and VBScript can coexist in the same .wsf file.
One significant obstacle to using .wsf files is their XML format. If you aren't familiar with XML and aren't interested in learning it, I suggest that you obtain a script editor that supports .wsf files and automates and hides some of the details of XML coding. I use SAPIEN Technologies' Primalscript (http://www.sapien.com/primalscript.htm).
To run the COM+ Application Manager.wsf script, download the script and COM+ Application classes.vbs and place them in the same folder on your system. Create a C:\foo folder and place in it one or more COM+ DLLs that you want to include in a COM+ application. Create appropriate .lis files for those DLLs and put the files in C:\foo (or put the .lis files in another location that you choose and modify the .wsf file's ComponentSettingsFilePath and InterfaceSettingsFilePath constants to point to the files). Then, in Windows Explorer, double-click the .wsf file to build the COM+ Application (double-clicking executes the first job in the .wsf file). To execute the script from a shell script or the command prompt, open a command window, navigate to the location of the .wsf and class files, and type the command
//Job:"Create COM+ App"
"COM+ Application Manager.wsf"
If the .wsf file contained multiple jobs, you could execute any one of the jobs by using this syntax and substituting the correct job name after the //Job: argument.
After running the COM+ Application Manager.wsf job, you can open the Component Services snap-in and expand Component Services, Computers, My Computer, and COM+ Applications to see the COM+ application named Foo. To see the components that your DLL contains, expand Foo and Components.
You can easily delete the sample COM+ application from within the Component Services console by selecting Foo and pressing the Delete key. Deleting an application removes all the application's settings in the registry and removes the DLL modules from the C:\program files\complus applications folder.
Now that you've seen how to use a VBScript class and a .wsf file to create a COM+ application, I hope you find all of these technologies as useful as I have. Technologies aside, the key is that this script makes the necessary task of building and rebuilding a COM+ application consistent and reliable. For an individual developer with a small application, the automation is handy; for a development team with an enterprise class application, such automation is required to produce the same result time after time.