Special Edition Using Microsoft® Visual Studio for Enterprise Development

Previous chapterNext chapterContents


- 25 -
Using Microsoft Transaction Server to Enable Distributed Applications

by Larry Millett

The Shared Property resource dispenser allows multithreaded applications to share global variables safely.
Transaction Server uses a resource-oriented role-based security scheme.
Learn how I-net applications can interact with Transaction Server.
Review programming tips for developing Transaction Server components. Plan to avoid some pitfalls.

In Chapter 24, you were introduced to the Microsoft Transaction Server (MTS), the Distributed Transaction Co-ordinator (DTC), and distributed transaction-processing concepts. This chapter explores the techniques used to create applications for MTS and delves more deeply into the features that support distributed applications.

Creating distributed transactions isn't an easy task. With applications components running on multiple machines connected over a network, many complicated types of error scenarios can occur. Trying to foresee these possibilities and building your application to deal with them appropriately is a monumental task. Microsoft has provided an infrastructure for these applications that greatly simplifies the job of application developers.

To get the most out of this chapter, you need a basic understanding of Microsoft's Component Object Model (COM) and Distributed COM (DCOM). You also need to understand the basic concepts underlying distributed transactions and the two-phase commit transaction pro-tocol.

Managing Transactions in MTS

MTS's primary function is automated support for transactions. Based on transaction requirements declared for each component, MTS automatically begins, commits, and aborts trans-actions, enlisting database connections and other components as needed. A component's transaction requirements may take one of four values:

A component's support for transactions is declared in Microsoft Transaction Explorer (MTX) when a component is added to a package.


See Chapter 24, "Deploying Distributed Applications," for more information about adding components to packages with the MTX.

To provide automatic transaction support, MTS associates an object context with each object created in its runtime environment. The object context includes information about the identity of the object's creator and the transaction (if any) in which the object executes. The object context exposes the IObjectContext interface. All newly developed MTS components should at least support transactions. At a minimum, this means that each of the component's objects will use the SetComplete and SetAbort methods of the IObjectContext interface. The next section discusses the object context in more detail.


TIP: Any object that includes a Begin Tran statement, or executes SQL that includes a Begin Tran statement, should be declared as Requires a Transaction or Requires a New Transaction. When a component is declared as requiring a transaction or a new transaction, you don't need to include Begin Tran statements in the object; MTS automatically provides transaction support.

As an alternative to its automatic management of transactions, MTS allows a base client to directly control transactions with the ITransactionContextEx interface. Discussion of the ITransactionContext interface, and the corresponding transaction context object, follows discussion of the object context.

Using the Object Context

The object context is central to MTS's implementation of automatic transactions, security, and object pooling. Every object executing in MTS has an object context and can obtain a reference to its context with the GetObjectContext function. Proper use of the object context is essential for automatic transaction management.


TIP: Include a private member variable of type ObjectContext in every MTS object. This reference must never be passed outside the object and must be explicitly released when the object is deactivated.

The GetObjectContext returns a reference to an ObjectContext object (interface IObjectContext). This object has a number of methods for transaction control:


TIP: A transaction can't be committed while any participating object is executing a method. MTS will behave as though COMMIT is disabled until all method calls return.

The work of a transaction can be divided among several MTS objects. In such cases, your first instinct might be to control the transaction and each subsidiary object from the base client. This approach, however, doesn't effectively exploit the automatic transaction support provided by MTS. A better approach would be to develop one master object that creates instances of the subsidiary objects from its object context. Because the subsidiary objects are created from the master object's context, MTS automatically enlists those objects in the transaction.

A base client creates an MTS object, which uses its object context to create two subsidiary objects, each of which uses its object context to create another subsidiary object. If the first MTS object requires a transaction and the subsidiary objects support transactions, all are automatically enlisted in the same transaction (see Figure 25.1).

FIG. 25.1
The object context used to enlist subsidiary objects in a transaction.


NOTE: Don't use CoCreateInstance to create a subsidiary MTS object from within another MTS object. You must use ObjectContext.CreateInstance so that the new object's context can inherit properties from its client's context and enlist in the client's transaction.

Suppose that an application needs to include in a single transaction work performed by two MTS components: Walk and Wind. Suppose also that each component is defined as Requires a Transaction. A base client implemented in Visual Basic might include the following code:

Public Sub WalkToSchoolAndWindWatch()
Dim objObjectContext As ObjectContext
Dim objWalk As Component1.Walk
Dim objWind As Compnent2.Wind
` Create an instance of Walk, and get a reference to the object context
Set objWalk = CreateObject("Component1.Walk")
Set objObjectContext = objWalk.GetObjectContext
` Use Object Context to create instances of Wind within the same transaction
Set objWind = objObjectContext.CreateInstance("Component2.Wind")
` do work - each component must call ObjectContext.SetComplete or SetAbort
objWalk.Walk("School")
objWind.Wind("Watch")
` Clean up
Set objWalk = Nothing
Set ObjWind = Nothing
Set objObjectContext = Nothing
End Sub

Using the Transaction Context

The TransactionContext object (ITransactionContextEx interface) allows a base client to control enlistment of MTS objects in a transaction. Each new instance of TransactionContext initiates a new transaction. The base client creates a transaction context and uses that object's methods to control the transaction:

Using a transaction context to control a transaction from the base client imposes a number of limitations on an application:

A base client creates a transaction context object and then uses it to create three subsidiary objects, one of which creates its own subsidiary object. The base client controls enlistment of subsidiary objects in the transaction (see Figure 25.2).

FIG. 25.2
The transaction context used to control subsidiary objects in a transaction from the base client.

Suppose that an application needs to include in a single transaction work performed by two MTS components: Walk and Wind. Each component must be defined as Supports Transactions. A base client implemented in Visual Basic might include the following code:

Public Sub WalkToSchoolAndWindWatch()
Dim objTransactionContext As TransactionContext
Dim objWalk As Component1.Walk
Dim objWind As Compnent2.Wind
` Create an instance of TransactionContext
Set objTransactionContext = CreateObject("TxCtx.TransactionContext")
` Use objTransactionContext to create instances of Walk and Wind within a
` transaction
Set objWalk = objTransactionContext.CreateInstance("Component1.Walk")
Set objWind = objTxCtx.CreateInstance("Component2.Wind")
` do work - each component must call ObjetContext.SetComplete or SetAbort
objWalk.Walk("School")
objWind.Wind("Watch")
` Commit the transaction
objTransactionContext.Commit
` Clean up
Set objWalk = Nothing
Set ObjWind = Nothing
Set objTransactionContext = Nothing
End Sub


TIP: To use the TransactionContext object in a Visual Basic project, include a reference to the Transaction Context 1.x Type Library. This library includes TransactionContext and TransactionContextEx objects. The CreateInstance method of the TransactionContext object takes a string program identifier ("Appname.Classname"); the CreateInstance method of the TransactionContextEx object requires the corresponding GUID strings.

Understanding MTS Component Integration Services

In addition to its support for transactions, MTS provides several features for enhanced scalability, security, and efficient administration:

Process and Thread Management

The MTS Executive provides an execution environment for MTS components. An MTS package consists of one or more ActiveX components that share an execution context (a process). Because all components in a package share a process, execution is more efficient. When components execute inside an MTS process, MTS can provide two important performance benefits: just-in-time object activation and resource pooling.

An MTS application component can execute in one of three basic scenarios: in-process, out-of-process, and remote.


NOTE: Some Microsoft documents seem to imply that with MTS, all components run in-process with the base client. This isn't true. An MTS component may run in-process with the base client, but for most enterprise applications, the remote server model makes the best sense. The in-process confusion probably arose because every MTS component must be built as an in-process server (a DLL) and because all components in an MTS package execute in a common process.

Figure 25.3 illustrates in-process execution. The application component runs inside the base client's process. This method provides optimum performance but no process isolation: On any internal error in a component, MTS immediately shuts down the base client and all its active components.

FIG. 25.3
An in-process MTS component uses the base client application's execution context.

To run MTS components in-process, the base client must run on a Windows NT Server system with MTS running and all components installed locally.


CAUTION: Although running MTS components in-process with the base client provides optimum performance, this approach may compromise security. When a base client successfully invokes a component, MTS doesn't revalidate security for calls between components within the same server process. When MTS components run in-process with the base client, the base client gains access to all components within that server process.

A local Transaction Server component executes on the same computer as the client application, but in a separate process managed by the Transaction Server Executive (see Figure 25.4). The client communicates with the component through the COM proxy/stub mechanism. Each message from a base client to an MTS component must cross a process boundary, which incurs some overhead, but this model allows MTS to provide full security and fault isolation. Scalability, however, is limited to the number of base clients and MTS components that can run on the same, single server.

FIG. 25.4
MTS components can also run on the same computer as the base client, but in a separate process.

Finally, an MTS component might run on a separate computer from the base client, using DCOM. The client communicates with the component through the DCOM proxy/stub mechanism. Communication between the base client and MTS components takes place at network speeds--milliseconds rather than microseconds. This model, shown in Figure 25.5, provides the best scalability for large numbers of base clients.

FIG. 25.5
A remote Transaction Server component executes on a separate computer from the client application, in an execution context provided by the Transaction Server Executive.


ON THE WEB:For a base client running on Windows 95, in-process and local execution aren't an option. (MTS isn't available for Windows 95.) MTS does support Windows 95 base clients for remote execution, but Windows 95 may need an upgrade for DCOM support. For the latest information on DCOM for Windows 95, see http://www.microsoft.com/oledev.


NOTE: You might have to configure DCOM security settings (impersonation and authentication levels) on both client and server computers. The default values for these settings--Identify for impersonation, Connect for authentication--work properly for MTS but might not be appropriate for your application. Impersonation must be set to Identify or higher.

Microsoft recommends using MTX rather than the DCOM configuration utility (dcomcnfg) to change security settings at the package level. Using MTX ensures consistent security settings for all components in a package.


Object Pooling and Just-in-Time Object Activation

In a typical high-volume transaction-processing environment, a large number of base clients invoke a large number of transactions. In MTS, each transaction requires a new instance of a component. Unfortunately, object instantiation takes a long time. It's as though you had to assemble your car before driving to work each day, disassemble it (and put the pieces away) on arrival, reassemble the car to drive home, and take it apart again on your safe return. It's much simpler just to park, lock the car, and take the keys.

Unfortunately, when a large number of people drive to work and park their personal automobiles, parking becomes scarce and traffic becomes dense. Similarly, if every base client maintains its own instance of a component, server resources are strained and performance suffers.

Microsoft's solution to this problem is object pooling and just-in-time activation. In the ActiveX programming model, a client doesn't explicitly destroy a server component; it just releases the server. Normally, after a server is released by all clients, it destroys itself. However, MTS can deactivate and then reactivate the application component on demand. In fact, MTS can even deactivate an object while a client maintains a reference (provided that the object isn't involved in an active transaction) and doesn't need to maintain any private state information.

To let MTS know when an object isn't involved in a transaction and has no private state to maintain, you must use the IObjectContext.SetComplete and IObjectContext.SetAbort functions. When a component calls one of these functions, it indicates that it has completed its work and doesn't need to maintain any private state for its client.

To perform some action on object activation or deactivation, implement the ObjectControl interface (IObjectControl for Visual C++ and Visual J++ and ObjectControl for Visual Basic). This interface includes three functions:

The following Visual Basic 5.0 (VB5) code example implements ObjectControl:

Option Explicit
Implements ObjectControl
Private Sub ObjectControl_Activate()
     `Initialize member variable for object context
     Set m_oContext = GetObjectContext()
     `A good place to fetch registry entries
End Sub
Private Sub ObjectControl_Deactivate()
     `Explicitly release reference to object context
     Set m_oContext = Nothing
     ` Deallocate any objects created since activation
End Sub
Private Function CanBePooled() As Boolean
     CanBePooled = True
End Function


NOTE: According to Microsoft, object pooling and recycling isn't implemented for custom components in MTS 1.x. MTS invokes the CanBePooled function but ignores the result. Implementing the function now, however, allows a component to take advantage of resource pooling and recycling when MTS implements this feature.


TIP: The ObjectControl interface requires Windows NT 4.0 Service Pack 2.

When a base client initially creates an MTS component (by calling CreateObject or CoCreateInstance), MTS checks for an inactive instance of that object. If an inactive instance is available, MTS returns a reference to that object; if no inactive objects are available, MTS initializes the object in a deactivated state. When the client invokes a method on a deactivated object, MTS first invokes ObjectControl.Activate.


NOTE: In Visual C++, calls to QueryInterface, AddRef, or Release won't activate an object.

MTS deactivates an object when the object calls SetComplete or SetAbort and returns to the caller, or when the last reference from an external client is dropped.

The Shared Property Manager

The Shared Property Manager (SPM) is one of two resource dispensers included with MTS. SPM allows safe multithreaded access to application-defined processwide variables. Possible applications include a web page hit counter or shared state for a multiuser application.

Traditional global variables aren't safe for use in a multithreaded or multiuser application because concurrent access may lead to inconsistent results. Figure 25.6 shows how use of a simple global variable can lead to inconsistent results. SPM provides a locking mechanism that allows safe concurrent access to shared state.


NOTE: SPM doesn't provide transactions for shared properties because properties are non-durable data.

FIG. 25.6
Thread 1 and Thread 2 update a global variable x. Thread 1 sets x = x + 1; Thread 2 sets x = x * 2. Depending on the sequence of reads and writes, the result may be 2, 3, or 4. The case in which the result is 2 is clearly incorrect: Thread 2 reads x while Thread 1 updates x--a dirty read.

As shown in Figure 25.7, SPM uses a simple hierarchy of three classes:

The object-creation methods for SPM include features intended to simplify programming. An attempt to create an instance of SharedPropertyGroupManager when one is already active in the process will succeed, but will return a reference to the existing instance without creating a new one. For example, the following VB code will never fail due to a prior instance of SharedPropertyGroupManager, but will never create a second instance:

Dim spmMgr As Object
Set spmMgr = CreateObject("MTxSpm.SharedPropertyGroupManager.1")

FIG. 25.7
Each process may have one instance of a SharedPropertyGroup-Manager, which contains a collection of SharedPropertyGroups. Each SharedPropertyGroup contains a collection of SharedProperty objects. Each SharedProperty contains a value (a variant).

For SharedPropertyGroup and SharedProperty objects, the create method behaves similarly, but sets a flag (out parameter) to indicate whether a new instance was created or a reference was returned for an existing instance. This flag can be used to conditionally set an initial value:

Dim spmGroupCounter as Object
Dim spmPropertyCounter as Object
Dim bPriorInstance as Boolean
`Create shared property group spmGroupCounter
Set spmGroupCounter = _
 spmMgr.CreatePropertyGroup("Counter", LockSetGet, Process, bPriorInstance)
` Create the counter SharedProperty.
Set spmPropertyCounter = spmGroupCounter.CreateProperty("Next", bPriorInstance)
` Set the initial value to 0 if this is a new instance
If bPriorInstance = False Then
 spmPropertyCounter.Value = 0
End If

Notice that the SharedPropertyGroupManager method CreatePropertyGroup takes two additional parameters: isolation mode and release mode. Setting isolation mode to LockSetGet ensures thread-safe concurrency for all properties in the group. By setting release mode to Process, SharedPropertyGroupManager will maintain the SharedPropertyGroup until the creating server process terminates.


TIP: All objects sharing a property must run in the same server process with the SharedPropertyGroupManager. One way to accomplish this would be to limit use of a shared property group to objects created by the same component, or to objects created by components implemented within the same DLL. Remember that an MTS package generally equates to an MTS process. If two DLLs use the same shared property group and an administrator installs the DLLs in separate packages, the two packages couldn't share properties.


TIP: SPM objects should be created only from within an MTS component, never from the base client.


NOTE: The Receipt component of the sample bank application included in MTS 1.x illustrates a simple application of shared properties.

SPM provides a solution to the problem of shared variables in a multithreaded environment. This is one more way in which MTS allows you to focus on business logic by simplifying multiuser programming issues.

Distributed Security Service

MTS 1.1 uses role-based security to control application security. The security model is resource-based--each package has its own list of roles (basically groups) and users. Roles for a package are defined, renamed, and deleted by using MTX, but the role names must be hard-coded into components. An MTS component can limit access to resources or functions based on roles and can determine at runtime whether a client has access to that role.


CAUTION: For MTS objects running in-process with the base client, security is effectively disabled.

A role is a symbolic name for a group of users. You define and associate roles to MTS components, whereas the MTS administrator defines roles for a package and assigns users to the roles. It's important that the MTS administrator uses the same role names (spelled correctly!) as you.


NOTE: Roles and security information for a package can't be modified or defined while an instance of that package is running in MTS.

Security in MTS 1.1 uses only three methods from the IObjectContext interface (ObjectContext object):


NOTE: When an MTS component runs in-process with the base client, IsCallerInRole always returns True. The IsSecurityEnabled method determines whether security checking is enabled. This method returns False when running in-process. Always call IsSecurityEnabled before using IsCallerInRole.

The Microsoft Transaction Explorer

The Microsoft Transaction Explorer (MTX) is a graphics administrative tool for creating and deploying packages, managing security, and monitoring transaction execution. As the developer, however, you'll use MTX frequently during development and unit testing. Each time an MTS component's interface changes during development, for example, the component has to be removed from any MTS packages and reinstalled.

Using Existing Components with MTS

A COM DLL that doesn't implement any specific MTS functions can still gain substantial benefits from running in the MTS environment:

Installing an existing component to run under MTS is as easy as creating a new package and adding the component to that package. Set the Transaction Support property for the component to Does Not Support Transactions.

MTS support for legacy components can even be leveraged for non-ActiveX code. It's often quite simple to develop an ActiveX "wrapper" for a legacy application; that ActiveX component can then be added to MTS. The simple MTS programming requirements for transaction support make it possible to create a wrapper that supports transactions. For more information, see the section "Managing Transactions in MTS," earlier in this chapter.

Using MTS with I-net Applications

This discussion focuses on interactions between Microsoft Internet Explorer (MSIE) and Microsoft Internet Information Server (IIS). Although a wide variety of browsers and servers exist in the market today, the MSIE/IIS combination provides the richest interaction. However, many of these interactions are proprietary extensions to WWW standards. After you commit to features available only in MSIE or IIS, there may be some loss of function or substantial expense to move to a different platform.

An I-net application may use the Hypertext Transfer Protocol (HTTP) to invoke an MTS component in two ways:

Either approach works well for a thin client, with the limitation that result sets are read-only. Figure 25.8 shows the ASP scenario.

FIG. 25.8
An I-net application can use MTS components via Active Server Pages.


NOTE: Microsoft VBScript embedded in a web page can't by itself access MTS components.

Using Active Server Pages

An Active Server Page can access MTC components via COM or DCOM. Although you can run the MTS components as an in-process server, any internal error in the MTS component causes MTS to terminate and may crash IIS. For reliability, it's better to run MTS components out-of-process.

By default, IIS doesn't allow out-of-process servers. To enable out-of-process components for IIS, use the Registry Editor (REGEDT32). Go to the following Registry key and set the key AllowOutOfProcCmpnts to 1: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\ASP\Parameters

Using Browser-Side ActiveX Components

An ActiveX component executing inside a web browser can call an MTS component, provided that the component is registered on the web browser machine. Use the HTML <OBJECT> tag to invoke the MTS component.


NOTE: The HTML script needs no special modifications to invoke an MTS component; the component just needs to be registered on the browser machine as an MTS component. Often, the same ActiveX component can be registered as a standalone (without MTS). In that case, the same script will invoke the standalone.

You can also use the <OBJECT> tag to load an MTS component in-process with the browser client (requires MTS installed on the web browser computer). Figure 25.9 shows an ActiveX component running in a web browser and invoking a remote MTS component.

FIG. 25.9
An ActiveX component running in a browser can invoke MTS components just like any other process.

Using Remote Data Streams

Microsoft Remote Data Streams (RDS) allow an ActiveX component running in a web browser to retrieve (read-only) data sets from a Microsoft Internet Information Server via ADO. RDS supports a number of protocols:


NOTE: RDS was previously known as the Advanced Data Connector (ADC). Microsoft changed the name to Remote Data Streams on bringing the technology into its Universal Data Access initiative.


ON THE WEB:For more information about Remote Data Streams, visit http://www.microsoft.com/adc.

Unless your application uses the HTTPS protocol (Secure Sockets Layer), IIS password authorization settings must include Allow Anonymous for RDS to successfully retrieve data with the HTTP protocol. Follow these steps to modify this IIS setting (requires stop and restart for the web service):

1. Run Microsoft Internet Service Manager.

2. Double-click the web service.

3. At the bottom of the Properties dialog box, select the Allow Anonymous option for Password Authentication and click OK.

4. Stop the web service (click the black square) and then start the web service (click the black forward arrow) so that the new settings take effect.

5. Close Internet Service Manager.

Accessing MTS Components via DCOM and HTTP

Sometimes you may want to access the same MTS component on the same machine via DCOM (over a local area network) and via HTTP (remote web users). Accessing the component via DCOM simply requires adding it to a package in MTS. To make the same MTS component accessible from IIS, follow these steps:

1. Use Transaction Server Explorer to view properties for the MTS component.

2. Choose the Activation tab.

3. Select In the Creator's Process... and click OK.

Developing MTS Components with Visual Basic

One of the best features of VB is the source-level debugger. A developer can single-step through code, set breakpoints, and examine the call stack and any variable. In VB4, you could run multiple instances of the VB Integrated Development Environment (IDE), load a COM component into one session and a base client into the other, and interactively debug the two applications simultaneously.

It's not obvious how to achieve simultaneous interactive debugging for an MTS component. You would really like to debug the MTS component in the MTS environment, but the VB IDE is an EXE and won't run in the MTS runtime environment. It's not a reasonable test to comment out all MTS-specific functions. Microsoft seems to have a reasonable solution--an ObjectContext stub enabled with a Registry setting.


CAUTION: Use the stub ObjectContext only for debugging. An ObjectContext stub installed on a production system disables all transactioning and security for that system.

To enable the ObjectContext stub, log in as a member of the administrators group for the local machine and use REGEDT32 to add the following Registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Transaction Server\Debug\RunWithoutContext The ObjectContext stub provides degenerate behavior for the most frequently used MTS functions:


NOTE: Using the ObjectContext stub allows ObjectContext methods to execute. However, the debugging session does not run in the MTS environment.


TIP: For other MTS objects, such as ObjectControl and TransactionContext, use conditional compile blocks (#If MTS... #End If) to disable the objects during debugging.


NOTE: Another area where debug behavior will vary from MTS runtime behavior is OLE Automation Errors (Error.Raise vbObjectError + SomeConstant). MTS 1.x doesn't support OLE Automation exceptions. MTS components built with Visual Basic (VB) can't use the Error object to notify callers of error conditions.


CAUTION: Single-threaded, stateful components are prone to deadlocks. To eliminate this problem, use stateless objects and call SetComplete before returning from any method.


CAUTION: VB-developed server components that use RDO may be subject to deadlock. To avoid deadlock, always explicitly close and deallocate rdoConnection and rdoResultset objects. If an open rdoResultset is allowed to go out of scope, the ODBC calls to close and deallocate the object might not occur before the ODBC resource dispenser reuses the connection. Deadlock may follow.

Each time you recompile an OLE DLL project in VB4, VB rewrites all Registry entries for interfaces (classes) included in that DLL. Depending on project settings, VB may generate new GUIDs for the components in that DLL. The end result is that you might have to reinstall components with MTX after each compile.

One alternative is to choose Tools, Refresh All Components from the MTX menu. Another option is the MtxServer RegRefresh VB add-in optionally included with the developer install of MTS. This add-in automates the MTX refresh after each compile.


TIP: The standard developer install for MTS doesn't install the VB add-in. Select the VB Addin checkbox in the Select Components dialog box during the MTS install.


CAUTION: Any recompile that changes the CLSID and IID for a component, such as changing the ProgID (Project.Classname), requires a complete reinstall of all components (including associated roles) for the project into MTX. If the application is deployed, you have to re-export the packages and reinstall all clients.


TIP: In VB4, use the Project, Options, Compatible OLE Server setting to ensure that each recompile preserves CLSID and IID for each class. Preserving the IID allows MTX to preserve associated roles and client installations.

When instantiating MTS objects from VB, always use the GetObject and CreateObject functions, even if the class instantiated is part of the current project. You can use the New keyword for classes not part of the current project. When you want a new MTS object to enlist in an existing transaction, use CreateInstance with the ObjectContext from an object already enlisted in the transaction.

Developing MTS Components with Visual C++

This section identifies tricks and pitfalls unique to developing MTS components with Visual C++ 5.0.


NOTE: To run a Visual C++ (VC++) MTS component in-process, you must call


MTS supports the COM transparent remote debugging infrastructure. A debugging session is automatically started on the server process if necessary. Similarly, single-stepping past the return address of code in a server object automatically stops just past the corresponding call site in the client's process.

Visual C++ 5.0 and MTS both support transparent remote debugging via OLE RPC. When enabled, transparent remote debugging allows a step-into server process code even if the server is on a different computer. To enable OLE RPC debugging in the Visual Studio IDE, choose Tools, Options, Debug, OLE RPC Debugging.

If you prefer, you can enable debugging in the Visual Studio IDE for out-of-process component DLLs:

1. Shut down server processes with MTX by right-clicking My Computer and then selecting Shutdown Server Process from the context menu.

2. Find the GUID for the MTS package in which your component is installed. You can find this information in MTX on the package's General property sheet page. To copy this text string, select the string and press Ctrl+C.

3. In the Visual Studio IDE, choose Project, Settings, Debug, General. Set the program arguments to /p:{YourPackageGUIDHere}, and set the full path to MTX.Exe (typically C:\MTX\MTX.EXE).

To enable debugging for in-process components, go to the Visual Studio IDE and enter the DLL name under Project, Settings, Debug, Additional DLLs.


NOTE: MTS 1.x doesn't support OLE Automation exceptions. Visual C++ components that implement ISupportErrorInfo will appear not to implement this interface, even if they do. Microsoft plans to correct this omission in a future release.


NOTE: Don't build MTS components as MFC extension DLLs. These applications can be loaded only by other MFC applications. Because an MTS component is a COM component, it should be loadable into any process, regardless of the type of application that started the process.

When instantiating MTS objects from Visual C++, always use CoCreateInstance, even if the class instantiated is part of the current project. You can use the New keyword for classes not part of the current project. When you want a new MTS object to enlist in an existing transaction, use CreateInstance with the ObjectContext from an object already enlisted in the transaction. To control the transaction from the base client (not necessarily a good idea), use the ITransactionContext interface to create a TransactionContext object, and then use CreateInstance with the ObjectContext for the TransactionContext (MyObj = GetTransactionContextEx().GetObjectContext.CreateInstance(IID)).


NOTE: The context object isn't available during calls to a constructor or destructor. For access to the context object during activation or deactivation, implement IObjectControl.

From Here...

This chapter gives you a developer's tour of Microsoft Transaction Server. After looking at the programming model for managing transactions, you looked at other services the system provides, including security, database connection pooling, the Shared Property Manager, and just-in-time object activation. After seeing how I-net applications can interact with MTS, you reviewed some programming strategies and pitfalls.


Previous chapterNext chapterContents


© Copyright, Macmillan Computer Publishing. All rights reserved.