Writing, testing, and debugging MTS components is more difficult than developing a typical Visual Basic application with a user interface. A few tips and pointers will make you more productive and allow you to maintain your sanity.
You should set up your development workstation with either Windows NT Server or Windows NT Workstation. If you're using Windows NT 4, you should install the Windows NT Option Pack, which includes MTS 2.0. If possible, you should also install Windows NT Service Pack 4. This service pack release provides updated components that significantly improve the ability of Visual Basic 6 to debug MTS components. At the time of this writing, the details of installing MTS with Windows NT 5 haven't been finalized. If you're using Windows NT 5, follow the documentation to install MTS and apply the latest service packs.
In addition to Windows NT and MTS, your development workstation also needs an installation of Visual Basic. Visual Basic 6 is best, but you can also work with Visual Basic 5. This workstation configuration allows you to develop and test MTS components and base client applications on a single computer. In later stages of development, you should test your code in a network environment, but working on a single machine can initially make the process go a lot faster.
If you have enough disk space and RAM on your development workstation, you can also install Internet Information Server (IIS), Microsoft Message Queue (MSMQ), and Microsoft SQL Server. You should have 128 MB or more of RAM if you're going to load up your machine like this. With this configuration, you can create advanced distributed applications on your laptop when you're stuck in a hotel room or traveling on a plane.
When you create and distribute MTS components, keep in mind that everything is based on COM. The MTS catalog tracks information about both CLSIDs and IIDs. You should place your projects in Binary Compatibility mode once you decide to install your ActiveX DLL in the MTS Explorer. You must apply all the principles and guidelines that were covered in Chapter 5 about building compatible servers and managing your versioning.
Once you build an ActiveX DLL, you can install it in a server package in MTS Explorer. One easy way to test your work is to create a simple form-based application that will serve as a base client for your MTS objects. You can create this test client by creating a new Standard EXE project and including the reference to your ActiveX DLL. When you run the test client application, any objects created from the ActiveX DLL will be loaded into the MTS environment. You can run the client from a compiled EXE, or you can run it inside the Visual Basic IDE. In either case, you should be able to look at the MTS Explorer and verify that your objects are being created inside your server package.
You might get some unexpected results if you add the base client project and the ActiveX DLL project to the same Visual Basic project group. When both projects are in the same project group, everything (including the objects from the ActiveX DLL project) will run in the Visual Basic debugging environment and your objects won't be loaded in the MTS environment. This situation has an unfortunate side effect. All of your calls to GetObjectContext will return a null reference. This typically results in a series of run-time errors. If you get a bunch of type 91 errors ("Object variable or With block variable not set"), this could be the cause. You can solve this problem by loading the client project and the ActiveX DLL project into two separate sessions of the Visual Basic IDE. Later in this chapter, you'll learn a technique for debugging both the client project and your ActiveX DLL in a single session of the Visual Basic IDE.
You will constantly rebuild your ActiveX DLL as you modify and test your code in the MTS environment. By default, however, a server package is configured to stay loaded in memory for three minutes after all its objects have been released. If you try to rebuild the DLL while the server package is still loaded, you'll receive a "Permission denied" error. You can get around this problem by right-clicking on the server package in the MTS Explorer and choosing the Shut Down command. You can then rebuild your DLL and rerun your test client. You must also close the project of the test client before you can rebuild the server if the project of the test client is referencing the ActiveX DLL.
The MTS Explorer provides a Refresh command for the Components folder of each package. When you invoke this command, the MTS system updates the Registry so that activation will still occur in proper MTS-like fashion. You can also use a Visual Basic add-in that instructs the MTS system to automatically refresh the components every time you rebuild an ActiveX DLL that has already been registered with MTS Explorer.
Even though Visual Basic and MTS provide some assistance with refreshing the Registry after a rebuild, they don't help you when you add new things to your ActiveX DLL. When you rebuild your DLL after adding a new class, interface, or method, the information in the MTS catalog will get out of sync with the information published in the type library of the DLL. In such cases, you can delete your components from the MTS package and then reinstall the DLL. You should be able to verify that the catalog is back in sync by examining your components in the MTS Explorer.
When you delete a component, you lose some security-related configuration information. However, in the early stages of development, you usually haven't done anything with security yet, so this generally isn't a problem. As long as you're working in Binary Compatibility mode, all of your base client applications should continue to work as before.
Visual Basic provides a powerful and easy-to-use debugging environment for almost every type of component and application you can create. It's usually pretty easy to debug Standard EXEs, ActiveX DLLs, ActiveX controls, and ActiveX EXEs. However, debugging MTS components with Visual Basic is more difficult and can be frustrating because they must be debugged in the MTS run-time environment. Before version 6, the Visual Basic debugging environment couldn't simulate the MTS run time. And even Visual Basic 6 includes compromises that make debugging less than perfect.
If you don't have Visual Basic 6 and Windows NT with Service Pack 4, you have two choices for debugging. First, you can run your components in the MTS run-time environment and write code in your components to generate debug messages using either the Windows NT event log or the MsgBox statement. The second debugging technique involves using the Visual C++ debugging environment.
Let's start by sending debug messages to the Windows NT event log. The Visual Basic App object provides a LogEvent method. You can easily append a message to the Windows NT event log with the following code:
Dim sMsg As String sMsg = "Your debug message here" App.LogEvent sMsg, vbLogEventTypeInformation
While testing your components, you can use the Windows NT Event Viewer to examine your debug messages. You might also find that logging Windows NT events is useful for more than just debugging. You can use events to audit recurring errors in the production environment. You might consider logging all unexpected errors that are raised in your components.
Another popular technique for generating debug messages in MTS is to call upon your old friend the MsgBox statement. You might see the use of MsgBox as a trick for novice programmers, but it's a quick-and-dirty way to see the value of your variables and see how your code is branching at run time. When you need to quickly debug some MTS code, this can be the fastest way to get the job done.
To use the MsgBox statement, you need to do two things. First, make sure your server package is running under the identity of the interactive user. This allows your objects to access your computer's display console. Second, make sure that you don't have the Unattended Execution option selected when you rebuild your server. If you follow these two rules, you can use a message box to send a debug message, as follows:
Dim sMsg As String sMsg = "Your debug message here" MsgBox sMsg, vbInformation + vbMsgBoxSetForeground
The painful thing about this style of debugging is that you have to remove these statements before you distribute your code. If you don't, one of these calls will hang your application. You might consider using a conditional compilation argument so that you can easily switch between builds that generate debug messages and those that don't.
You can employ a more advanced debugging technique using the Visual C++ IDE. This technique lets you set break points inside the class modules from your ActiveX DLL project and single-step through your Visual Basic code. To use the Visual C++ debugger, you must build your ActiveX DLL with symbolic debug info (accessible in the Compile tab of the Project Properties dialog box) and register it with the MTS Explorer. The documentation for MTS 2.0 has the full step-by-step instructions for how to get up and running in the Visual C++ IDE.
Using the Visual C++ debugger can be pretty tricky, but it does provide the best simulation of the actual MTS run-time environment. All of the MTS debugging techniques using the Visual Basic run-time environment involve compromises regarding threading and security.
Visual Basic 6 provides a few new features that let you debug your MTS components in the Visual Basic IDE. The first feature is the new Debugging tab of the Project Properties dialog box. This tab provides a Start Program property that allows you to enter a host application when debugging an ActiveX DLL. This provides some of the debugging capabilities that you have with the Visual C++ debugger. Once you install an ActiveX DLL in the MTS Explorer, you can add the following line as the Start Program setting for the project:
Note that this Start Program setting is the same one you use to activate an MTS component inside the Visual C++ debugger. The GUID after the /p: switch identifies the server package. You can optionally include the name of the package instead of the GUID. Once you enter the Start Program setting and set the appropriate break points in your class modules, you can run the project in debug mode by choosing Run With Full Compile from the Start menu. This launches a special debug version of your server package. When you run your test client application, you can single-step through your code. Remember that you must be working in Binary Compatibility mode.
One other MTS debugging feature has been added to Visual Basic 6. This feature allows you to use a technique that lets you debug MTS components without having to register them first with the MTS Explorer. This makes it much faster and easier to debug your MTS code. You must be running Windows NT with Service Pack 4 to use this technique, and you should note that it too has a few shortcomings when it comes to simulating the MTS run-time environment. However, this technique is definitely the fastest and easiest to use.
Let's examine how to create the setup to use this technique. Visual Basic 6 simulates the MTS run-time environment by temporarily registering your components in an MTS library package. When you run your project, mtxex.dll is loaded into the Visual Basic debugging environment. In Visual Basic 6, each MultiUse class module in an ActiveX DLL project has a new MTSTransactionMode property setting. If you set this property to a value other than NotAnMTSObject, you can debug your MTS code in the Visual Basic IDE.
For example, you can set the MTSTransactionMode property to NoTransactions for your class modules, and Visual Basic will run your objects under the control of the MTS run time. This technique is convenient because you can add the test client project and your ActiveX DLL projects to a single project group. When you run the test project, the objects created from your ActiveX DLLs are created with context wrappers. You can thus safely call GetObjectContext and make method calls on the object context.
You shouldn't register your ActiveX DLLs with the MTS Explorer before using this technique. You'll also encounter some limitations when it comes to testing multithreading and security-related code. Consult the Visual Basic 6 documentation to find out what these limitations are.
Despite a few limitations with this last technique, it significantly improves the debugging facilities over what is possible in Visual Basic 5. For example, when you debug ADO code in an MTS component, single-stepping through your code and examining your variables is just as easy as in other areas of Visual Basic development. However, each debugging technique has its strengths and weaknesses. If you spend a lot of time creating MTS components with Visual Basic, you might use each of the various debugging techniques covered in this chapter from time to time.
This chapter has covered the basics of writing components for use inside the MTS run-time environment, including the fundamental architecture of the MTS run time and the purpose of context wrappers. You've learned how to communicate with MTS through the ObjectContext and ObjectControl interfaces and how to propagate new objects in the current activity.
Chapter 10 builds on this knowledge and shows you how to program transactions with an MTS application. As you'll see, MTS provides a powerful transaction processing monitor. The skills you learned in this chapter will be important as you begin to create components that are transactional. Chapter 11 explores other issues related to designing and creating MTS applications with Visual Basic, such as security and application partitioning.