Export (0) Print
Expand All

Building MTS Applications

Archived content. No warranty is made as to technical accuracy. Content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

This topic contains information that a component application developer needs to understand before building Microsoft Transaction Server (MTS) applications.

MTS Component Requirements

Business Logic in MTS Components

Packaging MTS Components

Calling MTS Components

Holding State in Objects

Database Access Interfaces with MTS

Developing MTS Components with Java

Debugging MTS Components

Automating MTS Deployment

MTS Error Diagnosis

On This Page

MTS Component Requirements
Business Logic in MTS Components
Packaging MTS Components
Calling MTS Components
Holding State in Objects
Database Access Interfaces with MTS
Developing MTS Components with Java
Debugging MTS Components
Automating MTS Deployment
MTS Error Diagnosis

MTS Component Requirements

An MTS component is a type of COM component that executes in the MTS run-time environment. In addition to the COM requirements, MTS requires that the component must be a dynamic-link library (DLL). Components that are implemented as executable files (.exe files) cannot execute in the MTS run-time environment. For example, if you build a Remote Automation server executable file with Microsoft Visual Basic®, you must rebuild it as a DLL.

Note: MTS 1.0 had a limit of 100 methods per component. In MTS 2.0 this limit is now 1024 methods.

Components and TreatAs and AutoTreatAs Registry Keys

COM allows one server to emulate another using the TreatAs or AutoTreatAs registry keys. Suppose a client creates a component of a given CLSID using CoCreateInstance. If the TreatAs or AutoTreatAs key is present under that CLSID in the registry, COM will instead create the component indicated by this key. This effectively routes client requests to the emulating server. (The same routing is possible using the ProgID if the client refers to its servers by ProgID instead of CLSID.)

Components being emulated using TreatAs or AutoTreatAs are not valid MTS components and cannot be imported. If the emulation is to be added after the component is imported, the component must be deleted from the MTS catalog, then replaced with the emulating component.

Additional Requirements for Visual C++ Components

  • The component must have a standard class factory.

    The component DLL must implement and export the standard DllGetClassObject function and support the IClassFactory interface. MTS uses this interface to create objects. IClassFactory::CreateInstance must return a unique instance of an MTS object.

  • The component must only export interfaces that use standard marshaling. For more information, see Passing Parameters.

  • All component interfaces and coclasses must be described by a type library. The information in the type library is used by the MTS Explorer to extract information about the installed components.

  • For custom interfaces that cannot be marshaled using standard Automation support, you must build the proxy-stub DLL with MIDL version 3.00.44 or later (provided with in the Microsoft Platform SDK for Windows NT® version 4.0); use the –Oicf and /MD compiler options; and link the DLL with the mtxih.lib, LE32.lib, and ADVAPI32.lib libraries provided by MTS. Note that you must use the -Os compiler option instead of the -Oicf compiler option if a method contains more than 30 parameters. The mtxih.lib library must be the first file that you link into your proxy-stub DLL. If the component has both a type library and a proxy-stub DLL, MTS will use the proxy-stub DLL.

  • The component must export the DllRegisterServer function and perform self-registration of its CLSID, ProgID, interfaces, and type library in this routine.

Development tools such as Visual Basic and the ActiveX™ Template Library, which is available with Microsoft Visual C++®, allow you to generate interfaces that COM can marshal automatically. These interfaces, known as dual interfaces, are derived from IDispatch and use the built-in Automation marshaling support.

MFC Extension DLLs

MTS components should not be built as MFC Extension DLLs because such DLLs can be loaded only by MFC applications. A COM component, and therefore an MTS component, should be built so that it can be loaded into any process, regardless of the type of application that started the process.

For more information on MFC Extension DLLs, see the Microsoft Visual C++ Programmer's Guide.

Registering MTS Components

You manage MTS components by using the MTS Explorer. Before a component can run with context in the MTS run-time environment, you must use the MTS Explorer to define the component in the MTS catalog. In addition to keeping track of a component's basic COM attributes, such as the name of the implementation DLL, the MTS catalog maintains a set of MTS–specific attributes. MTS uses these attributes to provide capabilities in addition to those provided by COM. For example, the transaction attribute controls the transactional characteristics of a component.

The MTS Explorer assigns components to a package that controls the assignment of components to server processes and control client access to components.

Note: MTS allows only a single server process associated with a given package to run on a computer at a time. MTS writes a warning event message to the log if you attempt to start a second instance of an already active package. However, COM does not explicitly disallow multiple servers running the same COM classes. MTS writes a warning message to the log in the event that two threads try to start the package at the same time. This event is especially likely on a symmetric multiprocessing (SMP) computer where the two package invocations are concurrent. In these cases, MTS enforces a rule of one server process for each package by terminating one of the extra packages. COM then connects to the one server process still running and successfully returns.

Registration for Components Developed with Visual Basic

Whenever you recompile an OLE DLL project in Visual Basic 4.0, Visual Basic rewrites all of the registry entries for all of the components (Visual Basic classes) that live in that DLL. Additionally, Visual Basic may generate new GUIDs (depending on your project configuration) to identify the components in that DLL. This means that your MTS components are no longer properly registered in the MTS catalog.

There are two solutions to this problem. First, there is a Refresh button in the Transaction Server Explorer, as well as the Refresh All Components command on the Tools menu. If you use this command Microsoft Transaction Server will repair all inconsistencies in registry entries of components currently in the right pane of the Explorer.

If you install the development version of Microsoft Transaction Server, check the VB Addin option to enable a feature that will automatically refresh your components after recompiling them. The next time you run Visual Basic 4.0, the add-in will be automatically installed in your Visual Basic IDE. You can also turn the feature on and off on a per-project basis by selecting or deselecting the MTxServer RegRefresh | AutoRefresh after compile command on the Visual Basic Add-Ins menu. If you decide you want to refresh all of your Microsoft Transaction Server components at any given time, you can use the MTxServer RegRefresh | Refresh all components now command on the Add-Ins menu.

Important: The Visual Basic Add-in has been updated to work with both Visual Basic versions 4.0 and 5.0. Once installed, it will automatically refresh the Transaction Server catalog with the changes made during each compile. The add-in menu option to enable and disable the automatic refresh is no longer supported.

Using the add-in will properly refresh the MTS catalog, even after Visual Basic compilations that generate new component GUIDs. Note also that the Compatible OLE Server setting in the Visual Basic Project Options dialog box can be used to stop Visual Basic from generating new component GUIDs.

Refreshing the MTS catalog depends on you not changing the ProgIDs of your components. In Visual Basic 4.0, a component's ProgID is formed by the following concatenation: project name.class name. If you change either of these items, you will have to reinstall your component(s) in the MTS Explorer.

Building your component in Visual Basic 4.0 without selecting the Compatible OLE Server option replaces your old CLSID and IID on each compile. This has disadvantages when developing an MTS component, even with the Visual Basic add-in enabled.

  • Roles you assigned to the interface using the MTS Explorer are lost, since the interface IID is obsolete.

  • Proxies and registry configurations you distributed to remote machines no longer refer to your component and must all be updated.

  • Packages you exported which contain your component require re-exporting since the package definition file GUIDs are now out of sync.

Running COM Components Under MTS

Exercise caution when registering a standard COM component (one developed without regard to MTS) to execute under MTS control.

First, ensure that references are safely passed between contexts (see Passing Object References).

Second, if the component uses other components, consider running them under MTS. Rewrite the code for creating objects in these components to use CreateInstance (see Creating MTS Objects).

Third, you can effectively use automatic transactions only with components that indicate the completion of their work by calling either the SetComplete or SetAbort methods. If a component does not use these methods, an automatic transaction can only be completed when the client releases the object. MTS will attempt to commit the transaction, but there is no way for the client to determine whether the transaction has been committed or aborted. Therefore, it is recommended that you do not register components as Requires a transaction or Requires a new transaction unless they use SetComplete and SetAbort.

Including Multiple Components in DLLs

You can implement multiple components in the same DLL. The MTS Explorer allows components from the same DLL to be installed in separate packages.

Including Type Libraries and Proxy-Stub DLLs in MTS Components

Development tools supporting ActiveX components can merge your type library or proxy-stub DLL with your implementation DLL. If you do not want to distribute your implementation DLL to client computers, keep your type libraries and proxy-stub DLLs separate from your implementation DLLs. The client only needs a type library or custom proxy-stub DLL to use your server application remotely.

Business Logic in MTS Components

This topic describes how to enact business logic in MTS components.

Granularity is determined by the number of tasks performed by a component. The granularity of a component affects the performance, debugging, and reusability of your MTS components. A fine-grained component performs a single task, such as calculating tax on a sales order. Fine-grained components consume and release resources quickly after completing a task. A component that enacts a single business rule can facilitate testing packages, because isolating individual tasks in components makes testing your applications easier. In addition, fine-grained components are easily reused in other packages. In the following example, a component performs a single task: adding a customer record to the database.

Function Update(ByVal strEmail As String, _
ByVal bNewCust As Boolean, ByVal strContact As String,_
ByVal strPhoneNumber As String, _
ByVal strNightPhoneNumber As String)
    Dim ctxObject As ObjectContext
    Set ctxObject = GetObjectContext
    On Error GoTo ErrorHandler
' Code accesses the customer row from the database.
' Customer information is updated with information
' that was passed in.
'
    ctxObject.SetComplete
    Exit Function

This simple component uses system resources efficiently (passing parameters by value), is easy to debug (single function), and also reusable in any other application that maintains customer data.

A coarse-grained component performs multiple tasks. Coarse-grained components are generally harder to debug and reuse in applications. For example, a PlaceOrder component might add a new order, update inventory, and update customer information. PlaceOrder is a more coarsely grained component because it performs more "work" by adding, updating, and deleting customer, inventory and order information.

For more information about components' shared resources, see Holding State in Objects.

Packaging MTS Components

This document describes how you should package your MTS components. Consider the following design issues when defining package boundaries:

  • Activation

  • Shared resources

  • Fault isolation

  • Security isolation

Activation

You can select either of the following Activation levels for your packages:

  • Library (running within the same process as the client that creates the object)

  • Server (on the same computer but in a different process)

MTS provides a way to set up remote components by using the Remote Computer and Remote Component folders in the MTS Explorer hierarchy. For more information about "pulling" or "pushing" components between computers, see the Administrator's Guide.

By default, components run in a server process on the local computer. If you run your components within the MTS server process, you enable resource sharing, security, and easier administration by using the MTS Explorer for your component. Running components in-process provides an immediate performance benefit, because you do not have to marshal parameters cross-process. However, in-process components do not support declarative security and you lose fault isolation.

Sidebar: In-process Components and Security

Note that in-process components do not support declarative security or offer the benefits of process isolation. In-process components will run in any process that creates the component. Role checking is disabled between in-process components because IsCallerInRole returns True. In other words, the direct caller always passes the authorization check.

Also, it is recommended that you place your components as close as possible to the data source. If you are building a distributed application with a number of packages running on local and remote servers, try to group your components according to the location of your data. For example, in the following figure, the Accounting server hosts an Accounting package and Accounting database.

host

Shared Resources

Sharing resources in a multiuser environment results in faster applications that scale more easily. Note that only components marked with the Local activation setting can share resources. Package your components to take advantage of the resource sharing and pooling that MTS provides for your application.

Pool your resources by server process.Note that MTS runs each hosted package in a separate server process. The fewer pools you have running on your server, the more efficiently you pool resources, so try to group components that share "expensive" resources, such as connections to a specific database. If you reuse the expensive resources within your package, you can greatly improve the performance and scaling of your application. For example, if you have a database lookup and a database update component running in a customer maintenance application, package those components together so that they can share database connections.

Fault Isolation

Fault isolation requires separating components into packages that can operate in their own server process. Components in the same package share the same server process if all the activation settings are the same. By placing components in separate packages, you can mitigate the impact of a component failure because each package runs in a separate server process.

You can also use fault isolation to test new components. You can stage updates to MTS applications by introducing new components. Fault isolation for packages greatly reduces the risk of your local server package failing when you introduce a new component to a shared environment.

Security Isolation

MTS security roles represent a logical group of user accounts which are mapped to Microsoft Windows NT® domain users and groups during the deployment of the package. You can use the MTS Explorer to define declarative authorization checking by applying roles to components and component interfaces. Applying a security role to a component defines access privileges for any user assigned as a member of that security role. Users not assigned to a role with access privileges to a package cannot use the package. Because security authorization occurs between packages rather than between components within a package, it is recommended that you consider the MTS security model when determining your package boundaries. Note that security isolation only applies to packages with components running under the Server activation setting.

Security authorization is checked when a method call crosses a package boundary, such as when a client calls into a package or one package calls another. When you package your components, make sure you group components that can safely call each other without requiring security checks within one package.

All components within a package run under the identity established for the package. If you run under different identities, separate them into two different packages.

You can use declarative security between the client and server, and database security based on package identity between the server and data source. You can restrict access to a data source by assigning an identity to a package, and configuring the database to accept updates according to package identity.

If you use package identity to set up your database security, the database recognizes the package identity as a single user. If database access occurs under an identity set by the package, the database connection set up for the package identity name can be used by all the users mapped to role or roles for that package. This kind of resource sharing improves application performance and scalability.

Calling MTS Components

This topic covers the following:

  • Calling MTS Components using DCOM

  • Calling MTS Components from an Active Server Page

  • Calling MTS Components from a Web Browser-Resident Component

For more information on the methods for creating MTS objects, see Creating MTS Objects.

Calling MTS Components from a Client Application

MTS components can be located on a separate computer from the client. A client can call a remote MTS component using DCOM, HTTP, or Remote Automation. To run an MTS component on the client computer, the client computer must have MTS installed.

Cc750082.call1(en-us,TechNet.10).gif

Calling MTS Components through DCOM

DCOM is the standard transport for calling MTS components. To enable DCOM calls to MTS components, you must configure the following:

Client Registry Settings—The easiest way to configure your client application to call a remote MTS component is to use the application executable utility, which automatically configures client registry settings. For more information,see the Administrator's Guide.

DCOM Security Settings—You may have to configure the Impersonation Level and Authentication Level on both client and server computers. MTS works properly using the default values for these settings: Identify for Impersonation Level and Connect for Authentication Level. Make the necessary changes in the MTS Explorer at the package level. Changing default settings by using the DCOM configuration utility (dcomcnfg.exe) is not recommended.

If you want to use Microsoft Windows 95 clients with MTS, install DCOM for Windows® 95. For the latest information on DCOM support for Windows 95, see http://www.microsoft.com/com/dcom/dcom95/dcom1_3.asp on the World Wide Web.

Calling MTS Components through Remote Automation

Remote Automation was introduced with Visual Basic® version 4.0, before the introduction of DCOM. It is useful for 16-bit clients, because DCOM works only in 32-bit environments. To use Remote Automation with MTS, the Remote Automation Manager (RACMAN) must be running on the server where the MTS components are installed. For more information, see the Visual Basic documentation.

Note: You cannot use MTS security Remote Automation since all calls are made using the RACMAN identity. Because RACMAN does not impersonate when calling the components on the server, the client identity cannot be determined.

Calling MTS Components through HTTP

There are two ways a client can call an MTS component through HTTP:

Calling MTS Components from an Active Server Page

You can call MTS components from Active Server Pages (ASPs). You can create an MTS object from an ASP by calling Server.CreateObject. Note that if the MTS component has implemented the OnStartPage and OnEndPage methods, the OnStartPage method is called at this time.

You can run your MTS components in-process with or out-of-process with Internet Information Server (IIS). If you run your MTS components in-process with IIS, be aware that if MTS encounters an unexpected internal error condition or an unhandled application error such as a general-protection fault inside a component method call, it immediately results in a failfast, thus terminating the process and IIS.

By default, IIS 3.0 disables calling out-of-process components. To enable calling out-of-process components, modify the following registry entry

HKEY_LOCAL_MACHINE \SYSTEM \CurrentControlSet \Services \W3SVC \ASP \Parameters

by setting the AllowOutOfProcCmpnts key to 1.

Calling MTS Components from a Web Browser-Resident Component

You can call an MTS component from a Web browser–resident component. Use the application executable utility to configure that client, and then use the HTML <OBJECT> tag to call that component. You can also use the <OBJECT> tag to create an MTS object in-process with the browser client. Remember that MTS must be installed on the client computer for an MTS component to run in-process.

The component should be made safe for scripting, either through a component category entry in the registry, or by supporting the IObjectSafety interface.

Remote Data Service (RDS) also allows you to create web browser–resident components using the <OBJECT> tag. RDS supports the following:

  • HTTP

  • HTTPS (HTTP over Secure Socket Layer)

  • DCOM

  • In-process server

Except for in-process objects, the CreateObject method of the DataSpace object creates a proxy for the MTS object that runs in a local or remote server process.

You must configure the following registry key to the Prog ID of the object that you want to call:

HKEY_LOCAL_MACHINE \SYSTEM \CurrentControlSet \Services \W3SVC \Parameters \ADCLaunch

Holding State in Objects

Although there are many benefits to using stateless MTS objects, there are cases where holding state is desirable. This topic provides some guidelines in deciding where state is held in your application.

The following diagram shows a three-tier architecture:

Cc750082.state1(en-us,TechNet.10).gif

Typically, the latency between tiers differs greatly. Calls between the presentation tier and business tier are often an order of magnitude slower than calls between the business tier and datatier. As a result, held state is more costly when calling into the business tier.

However, it often makes sense to hold state within the transaction boundary itself. For example, the objects in the data tier may represent a complex join across many tables in separate databases. Reconstructing the data object state is potentially more inefficient than the cost of the resources held by those objects while they remain active.

Since objects lose state on transaction boundaries, if you need to hold state across transactions, use the Shared Property Manager or store the state in a database.

Example: Order-Entry Application

There are two separate issues when considering the effects of holding state in an application:

  • Network roundtrips—More frequent network roundtrips and slower connections extend the lifetime of the called MTS object.

  • Held resources—Holding state often means holding onto a resource, such as a database connection, and potentially, locks on the database.

Consider the example of an online shopping application. The client chooses items from a catalog and submits an order. Order processing is handled by a business object, which in turn stores the order in a database (not shown).

One way of building the application is for the client to call an Order object, with each call adding or removing an item from the order:

state2

This application has the following properties:

  • Client maintains no state.

  • Server maintains state across multiple calls.

  • Many network roundtrips.

  • High contention for resources. The database connection is held for the lifetime of the Order object. This is not a very scalable solution.

You can require that the client cache the items in an array or recordset:

state3

This application has the following properties:

  • Stateful client.

  • Server is virtually stateless with one call to the server.

  • Fewer network roundtrips.

  • Less contention for resources. This is a scalable solution.

Concurrency

In addition to network bandwidth and resources, concurrency affects application performance. There are two types of concurrency:

  • Pessimistic—As soon as editing begins, the database locks the records being changed. The records are unlocked when all changes are complete. No two users can access the same record at the same time.

  • Optimistic—The database locks the records being changed only when the changes are committed. Two users can access the same record at the same time, and the database must be able to reconcile, or simply reject, changed records that have been edited by multiple users prior to commit.

Implementing a server cache implies optimistic concurrency. The server does not have to hold locks on the database, thus freeing resources.

However, if there is high contention for the resource, pessimistic concurrency may be preferred. It is easier to reject a request to access a database and have the server try again than it is to reconcile cached, out-of-date data with a rapidly changing database.

Database Access Interfaces with MTS

This topic describes the database access interface options for MTS applications. You can use the Open Database Connectivity (ODBC) Application Programming Interface (API) to access a resource manager (which is a system service that manages durable data), or a data access model that functions over the ODBC layer. Because the ODBC version 3.0 Driver Manager is an MTS resource dispenser, data accessed via ODBC is automatically protected by your object's transaction. For object transactions, an ODBC-compliant database must support the following:

  • The database's ODBC driver must be thread safe. It also must be able to connect to the driver from one thread, use the connection from another thread, and disconnect from another thread.

  • If ODBC is used from within a transactional component, then the ODBC driver must also support the SQL_ATTR_ENLIST_IN_DTC connection attribute. This is how the ODBC Driver Manager asks the ODBC driver to enlist a connection on a transaction. You can make your component transactional by setting the transaction property for your component in the MTS Explorer. If you are using a database without a resource dispenser that can recognize MTS transactions, contact your database vendor to obtain the required support.

The following table summarizes database requirements for full MTS support.

Requirements

Description

Resources (if applicable)

Support for the OLE transactions specification, or support for XA protocol

Enables direct interaction with Distributed Transaction Coordinator (DTC). Use the XA Mapper to interact with DTC

MTS SDK in the Microsoft Platform SDK.

ODBC driver

Platform requirement for MTS server components

ODBC version 3.0 SDK

ODBC driver support for the ODBC version 3.0 SetConnectAttr SQL_ATTR_ENLIST_
IN_DTC call.

MTS uses this call to pass the transaction identifier to the ODBC driver. The ODBC driver then passes the transaction identifier to the database engine.

ODBC version 3.0 SDK

Fully thread-safe ODBC driver

ODBC driver must be able to handle concurrent calls from any thread at any time.

ODBC version 3.0 SDK

ODBC driver must not require thread affinity

ODBC driver must be able to connect to the driver from one thread, use the connection from another thread, and disconnect from another thread.

ODBC version 3.0 SDK

If a memory access violation in the mtx.exe process occurs within the driver after 60 seconds of inactivity, you may be using an ODBC driver that is not thread safe or requires thread affinity. The fault occurs in the driver when the inactive connections are being disconnected.

MTS Distributed Transaction Coordinator

MTS uses the services of the Microsoft® Distributed Transaction Coordinator (DTC) for transaction coordination. DTC is a system service that coordinates transactions that span multiple resource managers. Work can be committed as a single transaction, even if it spans multiple resource managers, potentially on separate computers. DTC was initially released as part of Microsoft SQL Server version 6.5, and is included as part of MTS. DTC implements a two-phase commit protocol that ensures that the transaction outcome (either commit or abort) is consistent across all resource managers involved in a transaction. DTC supports resource managers that implement OLE Transactions, X/Open XA protocols, and LU 6.2 Sync Level 2.

Choosing your Data Access Model

The following table summarizes commonly used data access models supported by MTS.

Interface

Description

Microsoft ActiveX™ Data Objects (ADO), Remote Data Service (RDS)

ADO offers one common yet extensible programming model for accessing data. ADO includes the ability to pass query results (Recordsets) between server and client, and the ability to pass updated Recordsets from client to server using RDS.

OLE DB

OLE DB is a low-level interface that provides uniform access to any tabular data source. You cannot call OLE DB interfaces directly from Microsoft® Visual Basic® because OLE DB is a pointer-based interface. A Visual Basic client can access an OLE DB data source through ADO.

Open DataBase Connectivity (ODBC)

ODBC is a recognized standard interface to relational data sources. ODBC is fast and provides a universal interface that is not optimized for any specific data source.

Remote Data Objects (RDO)

RDO is a thin object layer interface to the ODBC API. It is specifically designed to access remote ODBC relational data sources.
Note that adding the rdExecDirect flag to the .Execute method ensures that a temporaray stored procedure is not created when using two DSN's from the same transaction. See the RDO documentation for more details.

The diagram below illustrates how MTS components interact with the different data access interfaces:

Cc750082.datahei(en-us,TechNet.10).gif

ADO is not specifically designed for relational or ISAM databases, but as an object interface to any data source. ADO can access relational databases, ISAM, text, hierarchical, or any type of data source, as long as a data access provider exists. ADO is built around a set of core functions that all data sources are expected to implement. ADO can access native OLE DB data sources, including a specific OLE DB provider that provides access to ODBC drivers. ADO ships with the OLE DB Software Development Kit (SDK).

RDO does have some functionality that is not currently implemented in ADO, including the following:

  • Events on the Engine, Connection, Resultset, and Column objects

  • Asynchronous operations

  • Queries as methods

  • Enhanced batch-mode error and contingency handling

  • Tight integration with Visual Basic, as in the Query Connection designer and TSQL debugger.

Future versions of ADO will provide a superset of RDO version 2.0 functionality and provide a far more sophisticated interface, in addition to an easier programming model. Because ADO is an Automation-based component, any application or language capable of working with Automation objects can use it.

Developing MTS Components with Java

You can develop Java MTS components using tools provided by MTS and Visual J++. It is also recommended that you install the latest version of the Microsoft SDK for Java, available at http://www.microsoft.com/mscorp/java/.

This section contains the following topics:

  • Implementing a Component in Java

  • Using an MTS Component from Java

  • Using the Java Sample Bank Components

Implementing a Component in Java

To implement a component in Java, follow these steps

  1. Run the ActiveX Component Wizard for Java (available with Visual J++) for each Java class file. Use the wizard to create new IDL files.

  2. Modify the IDL files to add JAVACLASS and PROGID to the coclass attributes. See "Using IDL Files with Java Components."

  3. Run the ActiveX Component Wizard for Java again. Use the IDL files that you created in Step 1 to create type libraries for your components.

    This will create a set of Java class files, typically under \%systemroot%\Java\Trustlib. It will create one class file for each custom interface, and one class file for each coclass in the library.

  4. Run JAVAGUID against each class file generated in Step 3. See "Working with GUIDs in Java" for more information.

  5. Recompile your Java implementation classes.

  6. Run EXEGEN to convert the type libraries and class files into a DLL. See "Using EXEGEN to Create DLLs."

  7. Use the MTS Explorer to install the DLL.

Using IDL Files with Java Components

To specify the custom attributes in a type library, add the following in your IDL or ODL file:

#include <JavaAttr.h>

Within the attributes section of a coclass, specify the JAVACLASS:

JAVACLASS("package.class")

You may optionally specify a PROGID:

PROGID("Progid")

For example:

     [
          uuid(a2cda060-2d38-11d0-b94b-0080c7394688),
          helpstring("Account Class"),
          JAVACLASS("Account.AccountObj"),
          PROGID("Bank.Account.VJ"),
          TRANSACTION_REQUIRED
     ]
     coclass CAccount
     {
          [default] interface IAccount;
     };

Using EXEGEN to Create DLLs

EXEGEN is the Java executable file generator. To use this file, copy it to the appropriate destination folders (usually \JavaSDK\bin). This version of EXEGEN.EXE is capable of creating DLL files from Java classes, and can also include user-specified resources in its output files. This version of EXEGEN no longer supports the /base: directive. Class files are always included with the proper name. It supports a new /D directive that causes it to generate a DLL file instead of an EXE.

EXEGEN is now capable of reading five types of input files:

  • Java class files

  • RES files containg resources to be included

  • Executable files containg resources to be included

  • TLB files containing type libraries to be included

  • Text files describing which classes should be registered (DLL only).

If you use EXEGEN to create a DLL, the DLL can self-register any included Java classes that implement COM objects. There are two ways to tell EXEGEN which classes should be registered:

  • Include a type library that contains custom attributes for the classes. This is the preferred method.

    –or–

    Include a text file as input that gives EXEGEN the necessary directions. Each line of the text file describes one Java class, using the following keywords:

    • class:JavaClassName

      Required keyword.

    • clsid:{.....}

      Optional keyword that specifies the clsid GUID. If omitted, EXEGEN chooses a unique GUID.

    • progid:ProgId

      Optional keyword. If omitted, the class will be registered without a progid.

Working with GUIDs in Java

When an MTS method uses a GUID parameter, you must pass an instance of class com.ms.com._Guid. Do not use class Guid, CLSID or IID from package com.ms.com; they will not work and they are deprecated. The definition of class _Guid is:

package com.ms.com;
public final class _Guid {
     // Constructors
     public _Guid (String s);
     public _Guid (byte[] b);
     public _Guid (int a, short b, short c,
          byte b0, byte b1, byte b2, byte b3,
          byte b4, byte b5, byte b6, byte b7);
     public _Guid ();
     // methods
     public void set(byte[] b);
     public void set(String s);
     public void set(int a, short b, short c,
          byte b0, byte b1, byte b2, byte b3,
          byte b4, byte b5, byte b6, byte b7);
     public byte[] toByteArray();
     public String toString();
}

Instances of this class can be constructed from a String (in the form "{00000000-0000-0000-0000-000000000000}"), from an array of 16 bytes, or from the usual parts of a Guid. Once constructed, the value can also be changed. Method toByteArray will return an array of 16 bytes as stored in the Guid, and method toString will return a string in the same form used by the constructor.

JAVAGUID.EXE

Microsoft Transaction Server supplies a tool, JAVAGUID.EXE, that will post-process the output of JAVATLB. The following occurs for each class file:

  • If any method takes a GUID as a parameter, the class of that parameter will be changed to com.ms.com._Guid.

  • If the class file is an interface derived from a type library, a public static final member named iid will be added to the class. This member will contain the interface ID of the interface.

  • If the class file represents a coclass derived from a type library, a public static final member named clsid will be added to the class. This member will contain the CLSID of the class.

The clsid and iid members that JAVAGUID adds are useful as parameters to IObjectContext.CreateInstance and ITransactionContextEx.CreateInstance.

JAVAGUID can only be executed from the command line. It takes one or more parameters which are names of class files to update.

JAVATLB will eventually be updated to make JAVAGUID unnecessary.

Using an MTS Component from Java

To use an MTS component from Java, run the Java Type Library Wizard against the type library for the component. This will create several Java class files, typically under \%systemroot%\Java\TrustLib. It will create one class file for each custom interface, and one class file for each coclass in the library.

Assume, for example, that the type library contained one interface named IMyInterface, and one coclass, named CMyClass.

From Java, you can create a new instance of the component by executing

new CMyClass()

If you want to control transaction boundaries in the class, you can execute

ITransactionContextEx.CreateInstance ( CMyClass.clsid, IMyInterface.iid )

You should never call Java's new operator on the class that you implemented. Instead, use one of the following techniques:

  • Use Java's new operator on the class created by the Java Type Library Wizard. This will cause the Java VM to call CoCreateInstance.

  • Call MTx.GetObjectContext().CreateInstance (clsid, iid);

    This will create a new instance in the same activity as the current instance. This only works if the calling code is itself an MTS component.

  • If you have a reference to an ITransactionContextEx object, call its CreateInstance method. This will create a new instance in the transaction owned by the ITransactionContextEx object.

All of these techinques will result in the creation of a new instance of the class that you implemented.

Using the Java Sample Bank Components

The Java Sample Bank components are automatically configured by MTS Setup and require no additional steps in order to run them.

If you want to recompile the Java Sample Bank components, follow these steps:

  1. Run the SetJavaDev.bat file located in the \mts\Samples\Account.VJ folder. Javatlb.exe must be in your path for this batch file to run properly.

  2. Recompile your Java component implementation classes.

  3. After you recompile the component classes, use the mkdll.bat file located in the \mts\Samples\Account.VJ folder to generate and register vjacct.dll. Exegen.exe must be in your path for this batch file to run properly. You can also add running mkdll.bat as a build step to your Visual J++ project to simplify recompiling.

  4. Using the MTS Explorer, import the new components into the Sample Bank package.

Debugging MTS Components

This document describes techniques for debugging MTS components written in Microsoft® Visual Basic®, Microsoft Visual C++®, and Microsoft Visual J++™. These techniques are just suggestions for successfully debugging MTS components; you can choose your debugging environment and techniques according to your application needs.

If you are using MTS components in a distributed environment, it is recommended that you debug your components on a single computer before deploying to multiple servers. Components that function without error in a package on a local computer usually run successfully over a distributed network. If you do encounter problems with distributed components, you must test and debug both the client and server machines to determine the problem. It is also recommended that you stress test your application with as many clients as possible. You can build a test client that simulates multiple clients to perform the stress test on your application.

For debugging MTS components written in a specific language, see the following topics:

Debugging Visual Basic MTS Components

Debugging Visual C++ MTS Components

Debugging Java Classes

Debugging Visual Basic MTS Components

Microsoft Transaction Server components written in Visual Basic® version 5.0 or Visual C++® version 5.0 can be debugged in the Microsoft Visual Studio™ 97 Integrated Development Environment (IDE).

If you want to debug your components after they are compiled, you cannot use the Visual Basic 5.0 debugger, which only debugs at design time. To debug a compiled Visual Basic component, you will need to use the functionality of the Visual Studio 97 debugger.

Follow these steps to configure Visual Studio to debug MTS components built with Visual Basic 5.0:

  1. In Visual Basic, click Properties on the Project menu and then click the Compile tab to select the Compile to Native Code and the Create Symbolic Debug Info checkbox. It is also recommended that you select the No Optimization checkbox while debugging.

  2. In the MTS Explorer, right-click the package in which your component is installed, and select the Properties option. Place your cursor over the Package ID, and select and copy the GUID to the clipboard.

  3. Open Visual Studio. On the File menu, click Open and select the DLL containing the component that you want to debug.

  4. Select Project Settings, and then click the Debug tab. Select the MTS executable for the debug session (\mtx\mtx.exe). Enter the program arguments as /p:{<package GUID>} for the package GUID that you copied from the package properties. MTS 2.0 allows for the package name to be used in place of the GUID. Open the .cls files containing the code that you want to debug and then set your breakpoints. If you also want to display variable information in the debug environment, go to the Visual Studio Tools menu, select Options, and then select the Debug tab. In the Debug tab, place a check next to Display Unicode strings.

  5. In the MTS Explorer, shut down all server processes.

  6. In Visual Studio, select Build, then select Start Debug. Then select Go to run the server process that will host your component(s), and set breakpoints to step through your code.

  7. Run your client application to access and debug your components in Visual Studio.

  8. Before you deploy your application, remember to select one of the optimizing options in the Compile tab on the Project menu of Visual Basic (set to No Optimization in Step 1), clear the Create Symbolic Debug Info checkbox, and recompile the project.

To facilitate application debugging using Visual Basic 5.0, a component that uses ObjectContext can be debugged by enabling a special version of the object context. This debug-only version is enabled by creating the registry key:

HKEY_LOCAL_MACHINE \SOFTWARE \Microsoft \Transaction Server\Debug\RunWithoutContext

Note that when running in debug mode, none of the functionality of MTS is enabled. GetObjectContext will return the debug ObjectContext rather than returning Nothing.

When running in this debug mode, the ObjectContext operates as follows:

  • ObjectContext.CreateInstance - calls COM CoCreateInstance (no context flows, no transactions, and so on)

  • ObjectContext.SetComplete - no effect

  • ObjectContext.SetAbort - no effect

  • ObjectContext.EnableCommit - no effect

  • ObjectContext.DisableCommit - no effect

  • ObjectContext.IsInTransaction - returns FALSE

  • ObjectContext.IsSecurityEnabled - returns FALSE

  • ObjectContext.IsCallerInRole - returns TRUE (same as normal when IsSecurityEnabled is FALSE)

You can also develop your own testing message box functions to generate an assert in an MTS Visual Basic component. The following sample code can to used to display error messages while debugging Visual Basic code. You can also use this in conjunction with the Microsoft Windows NT® debugger (WinDbg.exe), which is a 32-bit application that, along with a collection of DLLs, is used for debugging the Kernel, device drivers, and applications. Note that you must enter DEBUGGING = -1 in the Conditional Compilation dialog box (located on the Make tab of the Project Properties dialog box) to enable the assert.

The following code provides an example.

#If DEBUGGING Then
    'API Functions
    Private Declare Sub OutputDebugStringA _
        Lib "KERNEL32" (ByVal strError As String)
    Private Declare Function MessageBoxA _
        Lib "USER32" (ByVal hwnd As Long, _
        ByVal lpText As String, _
        ByVal lpCaption As String, _
        ByVal uType As Long) As Long
    'API Constants
    Private Const API_NULL                  As Long = 0
    Private Const MB_ICONERROR              As Long = &H10
    Private Const MB_SERVICE_NOTIFICATION As Long = &H200000
Public Sub DebugPrint(ByVal strError As String)
    Call OutputDebugStringA(strError)
End Sub
Public Sub DebugMessage(ByVal strError As String)
     Dim lngReturn As Long
        lngReturn = MessageBoxA(API_NULL, strError, "Error In Component", _
            MB_ICONERROR Or MB_SERVICE_NOTIFICATION)
End Sub
#End If

You can then run checks through your code to aid stress debugging, such as in the following code:

SetobjObjectContext=GetObjectContext()
#If DEBUGGING Then
If objObjectContext Is Nothing Then Call DebugMessage("Context is Not Available")
#End If

Debugging Visual C++ MTS Components

You can use Visual Studio™ 97 to debug MTS components written in Visual C++®, including components that call SQL Server functions or stored procedures. For more information, see Debugging Visual Basic MTS Components.

The following information applies to components that have their activation property set to In a dedicated server process.

Microsoft Transaction Server supports the COM transparent remote debugging infrastructure. If transparent remote debugging is enabled, then stepping into a client process will automatically stop at the actual object's code in the server process, even if the server is on a different computer on the network. 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 will automatically stop just past the corresponding call site in the client's process.

In Microsoft Visual C++, selecting the OLE RPC debugging check box (on the Tools menu, select the Options submenu and choose the Debug property sheet) enables transparent remote debugging. It is not known at this time whether other debuggers support this infrastructure.

You can also debug your Microsoft Transaction Server component DLL in Visual C++ by performing the following steps. Each of these steps is made either inside the MTS Explorer or inside of a Visual C++ session with your MTS DLL project.

  1. Shutdown server processes using the MTS Explorer. To do this, right-click My Computer, and select Shutdown Server Process.

  2. In your Visual C++ session, under Project, Settings, Debug, General, set the program arguments to the following string: "/p: PackageName", for example:

    /p: "Sample Bank"
    
  3. In the same property sheet, set the executable to the full path of the Mtx.exe process, for example: "c:\MTx\MTx.exe".

  4. Set breakpoints in your component DLL, and you are ready to debug.

  5. Run the server process (in the Build menu, select Start Debug and click Go.)

The following information applies to in-process component DLLs that have their activation property set to In the creator's process.

You can debug your in-process MTS component DLL in Visual C++ by performing the following steps. Each of these steps is made inside a Visual C++ session with your base process project.

  1. Set the component DLL under Build, Settings, Debug, Additional DLLs.

  2. Now you are ready to step into or set breakpoints in your component DLL at will.

If you are using Visual Studio and Microsoft Foundation Classes (MFC) to debug, the TRACE macro can facilitate your debugging. The TRACE macro is an output debug function that traces debugging output to evaluate argument validity. The TRACE macro expressions specify a variable number of arguments that are used in exactly the same way that a variable number of arguments are used in the run-time function printf. The TRACE macro provides similar functionality to the printf function by sending a formatted string to a dump device such as a file or debug monitor. Like printf for C programs under MS-DOS, the TRACE macro is a convenient way to track the value of variables as your program executes. In the Debug environment, the TRACE macro output goes to afxDump. In the Release environment, the TRACE macro output does nothing.

Example:

// example for TRACE
int i = 1;
char sz[] = "one";
TRACE( "Integer = %d, String = %s\n", i, sz );
// Output: 'Integer = 1, String = one'

The TRACE macro is available only in the debug version of MFC, but a similar function could be written for use without MFC. For more information on using the TRACE macro, see the "MFC Debugging Support" section in Microsoft Visual C++ Programmer's Guide.

Note that you should avoid using standard ASSERT code in Visual C++. Instead, it is recommended that you write assert macros like a MessageBox using the MB_SERVICE_NOTIFICATION flag, and TRACE macro statements using the OutputDebugString function call.

Debugging Java Classes

Debug your Java classes as thoroughly as possible before converting the Java classes into MTS components. Note that once your Java class is converted into an MTS component, it is not possible to step through the code in the Visual J++™ debugger, or in any current debugging tool as well.

Sidebar: Using Visual J++ to Debug Java Classes

Microsoft Visual J++ (VJ++) provides a Java debugger that you can use to set breakpoints in your code. Note that when you are using VJ++ to debug, if you set a breakpoint in a Java source file before starting the debugging session, Visual J++ may not stop on the breakpoint. For performance reasons, the debugger preloads only the main class of your project. The main class is either the class with the same name as the project or the class you specify in VJ++. If you use the editor to set breakpoints in other classes before the classes are loaded, the breakpoints are disabled.

You can choose one of the following options to load the correct class so that the debugger stops at breakpoints.

  • Select the class in the category Additional Classes, located on the Debug tab of the Project Settings dialog box, and make sure the first column is checked. This loads the class when the debugging session starts.

  • Right-click a method in the ClassView pane of the Project Workspace and select Set Breakpoint from the Shortcut menu. This causes a break when program execution enters the method.

  • Set the breakpoint after Visual J++ has loaded the class during debugging. You may need to step through your Java source until the class is loaded.

When a method has one or more overloaded versions and shows up as a called method in the Call Stack window, the type and value for the parameters are not displayed in some cases. It appears as though the method takes no parameters. This occurs when the called method is not defined as the first version of the overloaded method in the class definition. For example, see the following class definition:

public class Test
   {
       int method(short s)
       {
           return s;
       }
       int method(int i)
       {
           return i;
       }
   }

If you were looking at a call to the second version of the method in the Call Stack window, it would appear without the type and value for the method:

method()

To view the method's parameters, change the order of the method overloads so that the method that you are currently debugging is first in the class definition.

printf-style Debugging

You can use printf-style debugging to debug your Java classes without using a debugger. printf-style debugging involves including status text messages into your code, allowing you to "step through" your code without a debugger. You can also use printf-style debugging to return error information. The following code shows how you can add a System.out.println call to the try clause of the Hellojtx.HelloObj.SayHello sample.

try
{     
System.out.println("This message is from the HelloObj implementation");
     result[0] = "Hello from simple MTS Java sample";
     MTx.GetObjectContext().SetComplete();
     return 0;
}

The client must be a Java client class, and you must use the JVIEW console window to run that class. Note that you need to configure your component to run in the process of its caller, which is in this case JVIEW. Otherwise, this debugging technique results in your component running in the MTS server process (mtx.exe), which would put the println output in the bit bucket rather than the JVIEW console window.

Use the MTS Explorer to configure your component to run in the caller's process by following these steps.

  1. Right-click the component.

  2. Click the Properties option.

  3. Click the Activation tab and clear the In a server process on this computer checkbox.

  4. Select the In the creator's process... checkbox.

  5. Reload the Client class. Your component's println calls will be visible in the JVIEW console window.

Using the AWT Classes

You can also use the AWT (Abstract Window Toolkit) classes to display intermediate results, even if your component is running in a server process. The java.awt package provides an integrated set of classes to manage user interface components such as windows, dialog boxes, buttons, checkboxes, lists, menus, scrollbars, and text fields.

The following example demonstrates how to use the AWT classes to display intermediate results in a dialog box:

import java.awt.*;
public final class MyMessage extends Frame
{
     private Button closeButton;
     private Label textLabel;
     // constructor
     public MyMessage(String msg)
     {
          super("Debug Window");
          Panel panel;
          textLabel = new Label (msg, Label.CENTER);
          closeButton = new Button ("Close");
          setLayout (new BorderLayout (15, 15));
          add ("Center", textLabel);
          add ("South", closeButton);
          pack();
          show();
     }
     public boolean action (Event e, Object arg)
     {
          if (e.target == closeButton)
          {
               hide();
               dispose();
               return true;
          }
          return false;
     }
}

Asynchronous Java Garbage Collection

Note that garbage collection for Java components is asynchronous to program execution and can cause unexpected behavior. This behavior especially affects MTS components that perform functions such as enumerating through the collections in the catalog because the collection count will be too high (garbage collection is not synchronized). To force synchronous release of references to COM or MTS objects, you can use the release method defined in class com.ms.com.ComLib.

Example:

Import com.ms.com.ComLib
…
ComLib.release(someMTSObject);

This method releases the reference to the object when the call is executed. Release the object reference when you are sure that the reference is no longer needed. Note that if you fail to release the reference, an application error is not returned. However, an incorrect collection count results because the object reference is released asynchronously when the garbage collector eventually runs.

You can also force the release of your reference and not call that released reference again.

Example:

myHello = null;
     System.gc();

Note that forcing the release of an object reference consumes extensive system resources. It is recommended that you use the release method defined in com.ms.com.ComLib class to release references to MTS

Automating MTS Deployment

This document describes how you can use the scriptable administration objects to automate deployment and distribution of your MTS packages. The MTS Explorer lets you configure and deploy packages by using a graphical user interface rather than by programming code. However, you can use the scriptable administrative objects to automate administration tasks, such as program configuration and deployment. Note that the scriptable administrative objects support the same collection hierarchy as the MTS Explorer. The following figure shows the MTS Explorer collection hierarchy.

methhier

For more information about MTS Explorer functionality, see the Administrator's Guide.

Using the Scriptable Administration Objects

Microsoft Transaction Server contains Automation objects that you can use to program administrative and deployment procedures, including:

  • Installing a Pre-Built Package

  • Creating a New Package and Installing Components

  • Enumerating Through Installed Packages to Update Properties

  • Enumerating Through Installed Packages to Delete a Package

  • Enumerating Through Installed Components to Delete a Component

  • Accessing Related Collection Names

  • Accessing Property Information

  • Configuring a Role

  • Exporting a Package

  • Configuring a Client to Use Remote Components

Note that you can use the scriptable administration objects to automate any task in the MTS Explorer.

The scriptable administration objects are derived from the IDispatch interface, so you can use any Automation language to develop your package, such as Microsoft® Visual Basic® version 5.0, Microsoft Visual C++® version 5.0, Microsoft Visual Basic® Scripting Edition (VBScript), and Microsoft JScript™.

Each folder in the MTS Explorer hierarchy corresponds to a collection stored in the catalog data store. The following scriptable objects are used for administration:

  • Catalog

  • CatalogObject

  • CatalogCollection

  • PackageUtil

  • ComponentUtil

  • RemoteComponentUtil

The Catalog, CatalogObject, and CatalogCollection scriptable objects provide top-level functionality such as creating and modifying objects. The Catalog object enables you to connect to specific servers and access collections. Call the CatalogCollection object to enumerate, create, delete, and modify objects, as well as to access related collections. CatalogObject allows you to retrieve and set properties on an object. The Package, Component, Remote Component, and Role objects enable more specific task automation, such as installing components and exporting packages. This utility layer allows you to program very specific tasks for collection types, such as associating a role with a user or class of users.

The following diagram illustrates how the MTS scriptable administration objects interact with the MTS Explorer catalog:

Cc750082.vipa01(en-us,TechNet.10).gif

Interface

Description

 

 

ICatalog

The Catalog object enables you to connect to specific servers and access collections.

ICatalogCollection

The CatalogCollection object can be used to enumerate objects, create, delete, and modify objects, and access related collections.

ICatalogObject

The CatalogObject object provides methods to get and set properties on an object.

IPackageUtil

The IPackageUtil object enables a package to be installed and exported within the Packages collection.

IComponentUtil

The IComponentUtil object provides methods to install a component in a specific collection and to import components registered as an in-process server.

IRemoteComponentUtil

You can use the IRemoteComponentUtil object to program your application to pull remote components from a package on a remote server.

IRoleAssociationUtil

Call methods on the IRoleAssociationUtil object to associate roles with a component or component interface.

For example, you can automate creating a new package and installing components into the new package by using the scriptable objects in the utility layer (Package, Component, Remote Component, and Role objects).

The following Visual Basic sample shows how to use the scriptable administration objects to create and install components into a new package named "My Package."

  1. Declare the objects that you will be using to create and install components into a new package.

    Dim catalog As Object
     Dim packages As Object
     Dim newPack As Object
     Dim componentsInNewPack As Object
     Dim util As Object
    
  2. Use the On Error statement to handle run-time errors if a method returns a failure HRESULT. You can test and respond to MTS trappable errors using the On Error statement and the Err object.

    On Error GoTo failed
    
  3. Call the CreateObject method to create an instance of the Catalog object. Retrieve the top level Packages collection from the CatalogCollection object by calling the GetCollection method. Then call the Add method to add a new package.

    Set catalog = CreateObject("MTSAdmin.Catalog.1")
     Set packages = catalog.GetCollection("Packages")
     Set newPack = packages.Add
     Dim newPackID As String
    
  4. Set the package name to "My Package" and save changes to the Packages collection.

    newPackID = newPack.Key
     newPack.Value("Name") = "My Package"
     packages.savechanges
    
  5. Call the GetCollection method to access the ComponentsInPackage collection. Then instantiate the ComponentUtil object in order to call the InstallComponent method to populate the new package with components.

    Set componentsInNewPack = 
         packages.GetCollection("ComponentsInPackage",
         newPackID)
     Set util = componentsInNewPack.GetUtilInterface
     util.InstallComponent"d:\dllfilepath", "", ""
     Exit Sub
    
  6. Use the Err object to display an error message if the installation of the package fails.

    failed:
         MsgBox "Failure code " + Str$(Err.Number)
     End Sub
    

For a complete description of how to program these procedures and more sample code, refer to the Administrator's Guide.

MTS Error Diagnosis

This topic describes how to determine the source of an error in your MTS application. You can diagnose the source and obtain a description of application errors by using a combination of Microsoft® Windows NT®, MTS, and other tools. If you discover that the application error is caused by MTS, you can interpret the error message using the Win32 (Win32.h) or MTS header files (mts.h), or the Microsoft Visual C++® error utility.

For more information on debugging an MTS application, see Debugging MTS Components.

Finding the Source of the Error

If your server application is failing or causing unexpected behavior, you must first determine where your error occurred. Windows NT provides a system Event Viewer that tracks application, security, and system events. Refer to the Application Log in the Event Viewer first to check the application associated with the event message. (Because you can also archive event logs, you can track an event history of the error.) Selecting an entry in your log activates an Event Detail, which provides further information about the system event. If you attempt to run the Sample Bank client without starting the Microsoft Distributed Transaction Coordinator (MS DTC), you will be returned the following Automation error.

errordia

Since this error does not indicate which application caused the failure, you can reference the Application Log in the Event viewer, which shows the error was caused by MTS.

Cc750082.applicat(en-us,TechNet.10).gif

Note: If you are using MTS for Windows 95, events are written to text files in the \Windows\MTSLogs directory.

Interpreting Error Messages

The Event Viewer helps you determine the application source of the problem. You can use other tools to interpret individual error messages. Success, warning, and error values are returned using a 32-bit number known as a result handle, or HRESULT. HRESULTs are 32-bit values with several fields encoded in the value. A zero result indicates failure if that bit is set. A non-zero result can be a warning or informational message.

HRESULTs work differently, depending on the platform you are using. On 16-bit platforms, an HRESULT is generated from a 32-bit value known as a status code, or SCODE. On 32-bit platforms, an HRESULT is the same as an SCODE. Note that if you are returning HRESULTs from Java, you should throw an instance of com.ms.com.ComFailException to indicate failure. You can specify a particular HRESULT when constructing the ComFailException object. The HRESULT is used as the return value for the COM method. To indicate successful completion, you do not need to do anything; just return normally. To return S_FALSE, indicating a successful completion but a return value of Boolean False, throw an instance of com.ms.com.ComSuccessException. In Visual Basic, you use the Err.Raise function to set and the On Error… / Err.Number to retrieve HRESULTs.

For a list of the values of common system-defined HRESULTs, see ComFailException. For a complete list of system-defined HRESULT values, see the header file Winerror.h included with the Platform SDK.

MTS never changes the value of an HRESULT error code, such as E_UNEXPECTED or E_FAIL, returned by an MTS object method. When an MTS object returns an HRESULT status code (such as S_OK or S_FALSE), MTS may convert the status code into an MTS error code before it returns to the caller. This occurs, for example, when the application returns S_OK after calling the SetComplete function; if the object is the root of an automatic transaction that fails to commit, the HRESULT is converted to CONTEXT_E_ABORTED. When MTS converts a status code to an error code, all the method's output parameters are cleared. Returned references are released and the values of the returned object pointers are set to NULL.

The Mtx.h header file contains the MTS specific error codes. Winerror.h contains the error code definitions for the Win32 API. For an overview of error codes, see "Error Handling" in the COM portion of the Microsoft Platform SDK

You can also use the ERRLOOK utility in Microsoft Visual Studio™ 97 to retrieve a system error message or module error message based on the value entered. ERRLOOK retrieves the error message text automatically if you drag-and-drop a hexadecimal or decimal value from the Visual Studio debugger or other Automation-enabled application. You can also enter a value either by typing it in or pasting it from the IDE clipboard and clicking the Look Up option.

Contacting MTS Support

If you run into a problem that you cannot solve, you can contact Microsoft support with the following information:

  • Topography of the application where the error occurred, such as a description of packages, components, and interfaces

  • Application event log on all computers

  • Reproduction of the error, if possible

Troubleshooting

If you are having trouble diagnosing your problem, refer to the list of troubleshooting tips below:

  • Make sure that the Distributed Transaction Coordinator (DTC) is running on all servers.

  • Check network communication by first testing on a local computer to verify that the application works. If you are running TCP/IP on your network, you can then use the Windows NT Ping.exe utility to verify that the machines are on the network.

  • Make sure that SQL and DTC are either located on the same computer or that the DTC Client Configuration program specifies that the DTC is on another computer. If not, SQLConnect will return an error internally when called from a transactional component.

  • Set the MTS transaction timeout to a higher number than the default 60 seconds, otherwise MTS aborts the transaction after this time has lapsed. All subsequent calls to the component return immediately with CONTEXT_E_ABORTED.

  • Make sure that your ODBC drivers are thread-safe and do not have thread affinity.

  • If you have difficulty getting an application to work over several servers, reboot the client and then verify that your Windows NT domain controller is configured properly.

  • Turning off resource pooling may reveal that a resource dispenser used by your application is the source of the problem. You can turn off resource pooling by setting the following registry key:

    HKEY_LOCAL_MACHINE \SOFTWARE \Microsoft \Transaction Server\Local Computer\My Computer:Resource Pooling=N

See the DCOM documentation and DCOM-related Knowledge Base articles if you are experiencing application errors that you suspect are caused by DCOM.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft