Testing and Debugging COM Components

[Previous] [Next]

Once you compile a component into an ActiveX DLL, you can easily install it into a COM+ server application using the Component Services administrative tool. One easy way to test your component code is to create a simple form-based application with Visual Basic that will serve as a test harness for your COM+ objects. You can create this test harness by creating a new Standard EXE project and including the reference to your ActiveX DLL. When you run this test client, any objects created from a configured component are loaded by the COM+ runtime into a private instance of DLLHOST.EXE.

You can run the test client from a compiled EXE or in the Visual Basic IDE. In either case, you should be able to look at the COM+ Services administrative tool and verify that your objects are being created inside your server application.

You typically end up constantly rebuilding your DLLs as you modify and test your code in the COM+ runtime environment. By default, however, a server application is configured to stay loaded in memory for three minutes after all of its objects have been released. If you try to rebuild the DLL while the server application is still loaded, you'll receive a "Permission denied" error. You can get around this problem by right-clicking on the server application in the Component Services administrative tool and choosing the Shut Down command. Configuring the server application to shut down immediately when all objects have been released is also a good idea during development.

You must also close the test client project before you can rebuild the DLL because the test client project holds a reference to the type library bundled into the DLL. Once you close the client project that references the DLL and make sure that the server application isn't running, you should be able to rebuild the DLL without any problems.

Of course, some programmers have found that they can take the "Permission denied" rebuilding problem a step further. If you manage to load the DLL into the Web server process, INETINFO.EXE, you must shut down INETINFO.EXE before you can rebuild the DLL. When you build components for a Web application, don't test them while they're registered as nonconfigured components or are configured to run in a library application. If you configured your component in a server application, your DLL won't be loaded into INETINFO.EXE and rebuilding during testing shouldn't be a problem.

Running Configured Components in the Visual Basic Debugger

The debugger in Visual Basic 6 includes support for debugging components in a simulated version of the COM+ runtime environment. This support was originally added for MTS development, but it works in a similar fashion on both platforms. As you'll see, this debugging strategy is definitely the fastest and easiest one to use. However, this technique has a few shortcomings in simulating the actual COM+ runtime environment, so I'll also show you a few other techniques.

The Visual Basic debugger simulates the COM+ runtime environment by creating objects from components in library applications. This allows Visual Basic to load and run objects in its debugger (VB6.EXE). If your components have already been added to a library application, everything is already set up as it should be. If your components have been added to a COM+ server application, starting the Visual Basic debugger changes it into a library application. If your components haven't been added to a COM+ application, the Visual Basic IDE creates a hidden library application for them on the fly.

All three cases work in the same way. When you run an ActiveX DLL project that's been configured properly, the COM+ runtime is loaded into the process of the Visual Basic debugger along with your component code. The important thing is that you can configure an application and all of its components using the Component Services administrative tool before you start debugging. You definitely want all of your attributes set correctly before you start testing and debugging your code. This means that you should always add and configure your components in a COM+ application before you start debugging.

Here's how to set things up. In Visual Basic 6, each MultiUse class module in an ActiveX DLL project has an MTSTransactionMode property setting. If you set this property to a value other than NotAnMTSObject, you can debug your COM+ components 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 COM+ runtime.

The Visual Basic team could have made things less confusing by providing two class-level properties instead of one. For example, if a MultiUse class had a COM+Debugging property that could be set to True or False in addition to the setting for the transaction mode, it would be easier to understand what's going on. However, you should note that the MTSTransactionMode property controls both debugging and transaction support. It's confusing because these two things aren't really related.

Earlier in the chapter, I mentioned that it is incorrect to call New on a class that's compiled into the same DLL. Now I'd like to point out that the New operator causes even more frustrating problems when you're trying to debug configured components inside the Visual Basic IDE. Inside the Visual Basic debugger, the rules for when to avoid the New operator are even more strict. You must avoid the New operator when the client and the class being used to create the new object are inside the same project group. In other words, a call to New and the class you're calling New on can't be running inside the same session of the Visual Basic debugger. Let me provide a little background to illustrate why this is such a problem.

Let's say you have a client application project and an ActiveX DLL project in the same project group. Your motivation for adding them to the same project group is to debug both projects in a single session of the Visual Basic IDE. When the client application calls New on a class in the DLL project that you're trying to debug as a configured component, the Visual Basic debugger creates the new object without the assistance of the SCM. The result is that the new object doesn't get created by the COM+ runtime in a valid context.

This situation has unfortunate side effects that are pretty easy to recognize. All of your calls to GetObjectContext and GetSecurityCallContext will return a null reference, which typically results in a series of run-time errors. If you repeatedly see Error 91 ("Object variable or With block variable not set"), the cause is likely that your code is trying to invoke methods using these null references.

What it comes down to is that you can't run your test client project and an ActiveX DLL in the same project group if the client application is using the New operator. It's just as bad if you try to debug two ActiveX DLL projects in the same project group if code in one DLL is using the New operator to create objects from a class in the other DLL. If you want to be sure that the SCM properly creates your objects in a valid context, you must use the CreateObject function instead of the New operator.

As you've seen throughout the chapter, there are many reasons to prefer the CreateObject function over the New operator in COM+ development. Here's yet another. Many COM+ programmers use CreateObject exclusively so they don't have to worry about problems caused by the New operator.

Now that I've talked about what you should avoid doing, let me summarize a list of steps you should follow to make debugging configured components work smoothly:

  1. Launch a session of the Visual Basic IDE, and open an ActiveX DLL project or a project group of ActiveX DLL projects that contain your configured components. Make sure to use CreateObject when activating objects across DLL projects.
  2. Be sure that each project is set up for binary compatibility. This means that you must build each DLL at least once before you debug it.
  3. Change the MTSTransactionMode property for each MultiUse class to something other than NotAnMTSObject. If you're not creating transactional components, use a setting of NoTransactions.
  4. Be sure that you've installed your components into a COM+ application and configured all your attributes appropriately. If your components aren't configured in a COM+ application, all attributes are given default settings.
  5. If you've added your components to a server application, be sure that the server application process isn't running when you start the Visual Basic debugger. If the server application is running, use the application's Shut Down command in the Component Services administrative tool.
  6. Set the breakpoints you want, and start the Visual Basic debugger by choosing the Start With Full Compile command from the Run menu.
  7. Run the client application. You can run the client from its compiled executable, from another session of the Visual Basic IDE or from the same session of the Visual Basic IDE that's running the DLL projects. If you decide to run the client application inside the same session of the Visual Basic IDE as your DLLs, make sure your client uses CreateObject instead of the New operator.

It's common to switch back and forth between running your component code in DLLHOST.EXE and the Visual Basic debugger. Just be sure that the client application releases all of its objects and you shut down the server application or the Visual Basic debugger before switching over to the other. This ensures that the activation setting of your application is switched back and forth between a server application and a library application without any hiccups.

You face a few important limitations with the Visual Basic debugger. First, your code doesn't run in an instance of DLLHOST.EXE. Your code runs in VB6.EXE. Second, the Visual Basic debugger is limited to a single thread. There's no way to simulate concurrency. Third, if you haven't configured your components in a COM+ application, your application and component attributes are assigned default values during debugging.

Other Useful Debugging Techniques

At times you might want to debug your code in DLLHOST.EXE instead of the Visual Basic debugger. The only way to debug your code in an actual instance of DLLHOST.EXE is to run your Visual Basic components in the Visual C++ debugger. The primary reason for doing this is to test how your code works in situations in which objects running on separate threads try to access the same resource concurrently. In MTS, you have to use the Visual C++ debugger to test security-related code. Fortunately, this isn't necessary with COM+.

To run compiled Visual Basic components in the Visual C++ debugger, you must build your ActiveX DLL with symbolic debug information. You access this option on the Compile tab of the Project Properties dialog box. This adds extra information to your compiled DLL that associates instructions with lines from your Visual Basic source code. Next, you must load the DLL and your Visual Basic class modules into the Visual C++ IDE. (See the item in MSDN titled Debugging Compiled Visual Basic Components for details on how to get everything up and running.)

You should keep two other quick-and-dirty debugging techniques up your sleeve. You can generate simple debug messages by using the MsgBox statement or writing to the Windows event log. Let's start by generating debug messages with your old friend the MsgBox statement.

You might regard the use of MsgBox as a trick for novice programmers, but it's a quick-and-dirty way to see the values of your variables and see how your code is branching at runtime. When you need to quickly debug a configured component running in DLLHOST.EXE, this can be the fastest way to get the job done.

To use the MsgBox statement, you must do two things. First, you must be sure that your server application is running under the identity of the interactive user so that your objects can access your local computer's display console. Second, you must be sure that the Unattended Execution option isn't selected when you rebuild your server. If you follow these two rules, you can use a message box to send a debug message, as shown here:

 Dim Msg As String Msg = "Your debug message here" MsgBox Msg, vbMsgBoxSetForeground, "Poor Man's Debugger" 

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 can hang a thread in 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.

The other useful technique is sending debug messages to the Windows event log. Visual Basic provides a built-in App object that exposes the LogEvent method. You can easily append a message to the Windows event log with the following code:

 Dim Msg As String Msg = "Your debug message here" App.LogEvent Msg, vbLogEventTypeInformation 

When you test your components, you can use the Windows Event Viewer to examine your debug messages. You might find, by the way, that logging Windows events is useful for more than just debugging. You can use events to audit recurring errors in the production environment. You should consider logging all unexpected errors that your components raise. Note that the second parameter of the LogEvent method can take a value of vbLogEventTypeInformation, vbLogEventTypeWarning, or vbLogEventTypeError.

Summary

So what has this chapter taught you? You should understand now that the COM+ programming model is all about declarative attributes and context. You must look for opportunities to do more declaratively and less programmatically. The secret is to let the COM+ runtime do as much work as possible. You should also look for ways to keep the things that change out of your compiled code so you don't have to recompile and redistribute your DLLs as often.

Knowing how COM+ administration works is important. Even after you create a COM+ application and add your components, you still have to explicitly configure several attributes. Some of you will learn to write administrative scripts, and some of you will rely on the Component Services administrative tool. Either approach can get the job done. Over the next few chapters, I'll discuss many more application and component attributes in greater detail. At this point, it's important that you simply understand when and how to configure them.

In this chapter, you saw how COM+ tracks attribute values and contextual information in a running application. An understanding of this architecture is critical to mastering how COM+ works internally. Every context has its own object context that stores contextual information. You also saw how to programmatically interact with the object context, and you saw how call context flows along as control is passed from method to method.

I ended this chapter by describing various resources for testing and debugging configured components. This information and the other ideas presented in this chapter should pave the way for the chapters ahead. I think you'll agree that attribute-based programming changes the world in which you live. Your components are definitely not in Kansas anymore.



Programming Distributed Applications with COM+ and Microsoft Visual Basic 6.0
Programming Distributed Applications with Com and Microsoft Visual Basic 6.0 (Programming/Visual Basic)
ISBN: 1572319615
EAN: 2147483647
Year: 2000
Pages: 70
Authors: Ted Pattison

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net