Library Zone Articles
External Articles
Byte Size

Discovery Zone Catalogue
Diary
Links
Bookstore
Interactive Zone Ask the Gurus
Discussion Groups
Newsletters
Feedback
Etc Cartoons
Humour
COMpetition
Advertising
Site Builder ASP Web Ring ASP Web Ring

The Developer's Resource & Community Site
COM XML ASP Java & Misc. NEW: VS.NET
International This Week Forums Author Central Find a Job

Microsoft Transaction Server

Download print article

Introduction:

COM is a DLL management facility, DCOM is the mechanism that piggy-backs COM interface calls over Microsoft remote procedure calls. So what is MTS? It is many things and in this article I want to outline what it is, what it does and why it was developed.

You may have read MTS described as a new paradigm in programming and texts extol the virtues of the new way to manage state in a distributed application. While I agree that MTS persuades you to think about how you manage state, I do not agree that there is anything new in how state is managed. Indeed, I think this is a happy consequence of what is the real reason for the development of MTS. Read on and you'll see why.

MTS solves COM's Management Problems

COM information is stored in a machines local registry. Specifically, it is stored in HKEY_CLASSES_ROOT which is a mere mapping of HKEY_LOCAL_MACHINE\Software\Classes. When you install a component server on a new machine you have to register all the coclasses and ProgIDs in that server. If the components use interfaces that are not standard, you must register them so that the component can be used out of apartment. In addition, most components have other values that must be put in the registry to allow them to work properly, or be activated in the correct environment (the buzz-word these days is context); the most important of these is the apartment which a DLL-based component is designed to run in, its ThreadingModel. Without these values COM will either refuse to create the component, or will take the safest option when creating it.

When you use a component that is installed on another machine there are still registry entries that should be present on the calling machine. The values that must be present are those that are concerned with marshalling of interfaces: the component's interfaces must be registered on the client machine. You can get round this by having a component that has dual interfaces or dispinterfaces. In this case the component can be called through IDispatch and since this will be registered on all machines it means that you do not need to make any additional changes to your client machines. However, my previous statement still holds - to access a component its interfaces must be registered on the client machine.

To access a component on another machine there are two other aspects that you must take into account. The first is pretty obvious, you have to indicate which machine the component runs on. If you are lucky enough to program in C++ or Delphi you will realise that to do this you can use the COSERVERINFO parameter of CoCreateInstanceEx() or CoGetClassObject(). If you are less fortunate and have to use VB5 or earlier then you'll be aware that there is no facility in the language to specify a remote machine (VB6 remedied this by providing an extra parameter to CreateObject()).

If you cannot give the server name then COM allows you to specify the remote machine through the AppID key of the registry. You may have seen this used for server-side settings (which I'll come to in a moment), but it is also useful for application-level client-side settings too. To specify the name of the remote machine you should add a key to AppID and in that add the named value RemoteServerName and use this value to give the name of the remote server. Next, you must add a registry key for the component that your client will use from this server, so under CLSID you must add the component's CLSID and in that key add a named value of AppID which has the GUID you entered in the AppID key. After doing all of this COM will know that when the component is requested the local machine needs to forward that request to the remote machine. Note, however, that this does mean that all remote instances of this component will be activated on the specified machine, COSERVERINFO gives your code the option of choosing the host machine at runtime.

This is a real pain to do and it would be simpler to use some tool to do all of this. Indeed, this is one of the facilities of MTS, which has components that allows MTS on machines around your network to communicate with each other over DCOM and to use this to administer where components are activated. MTS offers several options for component deployment:

  • You can 'push' marshalling files to a remote client. This copies and installs the type libraries and/or proxy-stub files for a selected component on to a remote client machine. The component then becomes a 'remote component' on that machine.
  • You can 'pull' marshalling files from a remote server. This copies and installs type libraries and/or proxy-stub files for a selected component on to the local machine from a remote machine. The component becomes a 'remote component' on the local machine.
  • You can export a package. This will create an install file with client-side marshalling files for all of the components in the package.

If your account has sufficient administrator privileges on the machines that will be used in a distributed application then you can administer all of the machines from one PC. You never need use DCOMCnfg again.

MTS Solves the Problems of Distributed Errors

If your application involves calls to several components on several machines and each of these components alter resources, you will have the problem of deciding what to do when code in one component fails. Do you leave the changes made by the other components intact? If you do so then it means that the resources distributed across the network will become inconsistent. The classic example is the 'debit one account and credit another' situation where a record in a database is decremented by some value and a record in another database is incremented by the same value. If just one action occurs and these represents bank accounts, one or other of the customers will get very annoyed!

The solution is to monitor what resources are changing and what the change is. If an action fails then this log of resource changes can be used to roll back to the state that the resources were before the changes were made.

Of course I am talking about transactions. These are not an innovation of MTS at all, but are provided and managed by Microsoft Distributed Transaction Coordinator (MS DTC). What MTS does for you is it allows your components to obtain and enlist in a transaction automatically. You just determine that your MTS component performs actions that require a transaction and MTS ensures that one is there and enlisted.

You may think of transactions as being concerned with databases. Although this is their main use, they are not exclusively concerned with databases. Indeed, the primary reason for transactions is to allow errors to be distributed around that network. Using MTS makes this far easier.

MTS Allows VB Programmers to Use and Write Remote Components

Perhaps the most important aspect of MTS is that it allows VB programmers to enter the COM adult world and create and use remote components. Yes, I know that VB pre-empted DCOM with remote automation and I am sure that the VB team felt that they had scored a coup against the COM team. But automation is very much the less able part of COM: you cannot use the full range of RPC data types and you cannot take advantage of the more efficient data marshalling that COM provides.

Even today, when VB6 can write COM objects with dual interfaces, those interfaces are type library marshalled (oleautimation compatible) and this causes problems because the type library that describes the interface is bound to the server and then registered with the system. Thus, the marshalling information is compiled into the server code that implements the interface and so a client that uses this interface must load the server into its memory space to be able to marshal it. Also, if another server has objects that implement the same interface they will have to load the other server to be able to marshal the interface! COM has a more flexible model where proxy-stub DLLs are separate code modules, which means that several clients and servers can use an interface and only load the marshalling code that they need. This is a problem with type library marshalling and can be partially solved if type libraries are distributed separately.

As I have already mentioned, the problem with calling components over DCOM was that VB5 did not have a mechanism to specify what machine to create the component on. DCOMCnfg could help, but it still needed some registry manipulation on the client which put off most VB programmers. VB6 fixed this problem and provided a servername parameter to CreateObject(), however, this facility came too late.

Next, VB had a problem with security - it could not do any security programming! I will cover security in the next section, but pertinent here is the fact that in VB there is no equivalent of CoInitializeSecurity(), which screws it up for writing servers and removes some of the more useful client-side security facilities. In essence, if you cannot control who can call your components, or you cannot set authentication levels, it makes your code useless for distributed computing.

Furthermore, VB6 can only create STA components which makes the code inherently single threaded. VB had a partial solution for this for EXE servers in that it allows you to create a server that has a pool of STA threads. Although this means that the server is not single threaded, it is still not the same as making a server free threaded by making all components run in the process's MTA. The MTA is a better solution because RPC manages the pool of threads and dynamically changes the size of the pool based on the stress on the server.

MTS solves most of these problems. Firstly, it makes oleautomation interfaces more or less the norm. The reason is that if a server does not have a type library, then there is no way to describe what interfaces its components implements, and so this means that MTS Explorer cannot add their interfaces into the catalog and thus you are not given the option of interface-level role based access checks. It is possible to use the MTS Catalog objects to change the entry for a component, but most people do not bother to do this and since type libraries are used mainly to type marshal oleautomation compatible interfaces (and also in implementing those interfaces) there appears to be little point in putting a non-oleautomation compatible interface in a type library. Indeed, if you do so MIDL will generate warnings. As a consequence, in general, people use oleautomation-compatible interfaces and thus they are now the de facto standard for MTS components. C++ programmers sing to the same song sheet as VB programmers.

Do I think this is a good thing? Not necessarily. As developers eschew [size_is()] for SAFEARRAYs they are denying themselves a simpler and more efficient marshalling mechanism. Also, by relying on type library marshalling (as I have already mentioned) they generally end up using marshalling code that is bound to server files, and thus when you distribute the ability to use a component on another machine you end up distributing the actual server file to that remote client. MTS did not need to do this (it could merely extract the type library resource and distribute that) and I think it is a mistake that its developers decided to take this route.

As to the host machine problem, MTS replaces all the messing around with the registry and DCOMCnfg and, as mentioned earlier, you specify which machine that will be used to run the component by 'pulling' or 'pushing' 'components' between machines (in fact the components are not pulled or pushed, but the ability to use them is). This mechanism of determining which machines will run the component is far more flexible than with vanilla COM, because it allows an administrator to change the load on machines in an application by a few simple mouse clicks.

Like a VB EXE server, MTS creates a pool of STA threads. It has to do this precisely because VB components run in STAs and if it did not do this it would exclude VB components from MTS applications. It is true that STA threads enable MTS to manage activities (STA serialization is used to provide activity serialization) but this activity locking did not have to be done this way as illustrated by COM+.

The MTS thread pool works in a slightly different way to VB thread pools. In the former, the component's class factory is registered in the MTA which means that RPC creates a dynamic pool of threads to manage activation requests, MTS then creates the components in a dynamic pool of STA threads (up to a maximum number of threads). VB thread pools are fixed and the class factories are registered in an STA, which means that there is an inherent bottleneck when many activation requests come in at the same time (to be fair, VB has a mechanism to allow each component to run in an individual thread, but this is still a partial solution).

The final point that I should make here is that much of the MTS API is biased towards VB. As an example, take a look at the interfaces and object model of the MTS Catalog, CatalogObject and CatalogCollection components. These have been designed for VB use through their extensive use of enumerators (for for each) and LPDISPATCH pointers. This often makes C++ programming cumbersome. As a more extreme example of this, take a look at the MTSCatalogLib type library. This contains the components that the catalog components use to access the MTS catalog, and they make extensive use of SAFEARRAYs, which makes the programming simple in VB, but convoluted in C++. However, the sting in the tail is that these components cannot be used by VB because they return data through [out] parameters and not the [in, out] parameters that VB requires. The designers of this library have made life difficult for C++ programmers without a corresponding gain for VB programmers!

MTS Makes Access Checks Easy

VB programmers cannot use the NT security API and so this means that they cannot perform access checks on client access tokens. VB programmers also cannot call CoInitializeSecurity() and so cannot do coarse grain restrictions on who can access components in a server, nor set the default authentication level on the server.

Some of this security administration can be done with DCOMCnfg, which allows you to set the launch and access permissions and default authentication level on the process. However, DCOMCnfg is confusing in some aspects and has some bugs. MTS provides role based access checks, where accounts are added to roles that have the permission to access specific components in a package or specific interfaces on a component. The developer need not do any security programming, and if they do want to do fine grain access checks within a method, the API calls involve role names (as BSTRs) and not the complication of access control lists and access control entries (or trustees) which NT C programmers use.

MTS performs automatic access checks on components and their interfaces (and on the packages that contains them) according to the values held in the catalog. The access checks are performed against roles which are just a description and so this means that the programmer does not need to know the actual accounts that are contained in the role. Contrast this to NTLM (NT Lan Manager) security programming where access checks are performed against specific accounts. You could argue that NTLM has an equivalent in NT aliases (also known as local groups), but even so the checks are performed using the NTLM API which is far from straight forward.

C++ programmers have benefited from role based access checks in MTS because it reduces the amount of code that has to be written. However, yet again, the real winners are VB programmers, because it gives them a facility that previously they could not use.

MTS Changes the Way That You Manage State

A distributed application must have distributed error handling and this means that it must have transactions. If you do not have transactions then the resources used in the application will become inconsistent when an error occurs. To use a resource in a transaction it must be held in a resource manager and because the resource is not held as part of the component it has lead to the idea of 'stateless components'.

In fact, this is not new to MTS and many applications before MTS used resources in this way because data was often held in remote databases and components were used to give access to that data. The designers of such an application would be fully aware of the resources that they are using and the best way to access that data. MTS just formalized this use of remote resources and made developers more aware of this aspect.

In essence the 'new' paradigm of managing state is just a reiteration of how designers of distributed applications have always managed resources and the fact that developers are now putting greater importance on it is a happy consequence.

Conclusion

MTS has changed the lives of many developers and for VB it is practically the only way to produce distributed applications. For most developers all they need to know about MTS is how to point-and-click to get it to do what they want, and they are not interested in what MTS does to make everything work. To such developers MTS is a magical black box. However, when you look further into MTS it turns out that there is no magic going on, it is using the existing technologies of COM and MSDTC, and it presents these facilities in a VB friendly way.

So, should you use MTS? By all means do, in fact, it will save you a lot of work in terms of security programming, transaction enlistment and deployment. Just make sure that when you use MTS you keep in the back of your mind that the real reason for MTS was to give these facilities to VB programmers, who otherwise would not have them.

For more details of how MTS works and its facilities then take a look at Richard's latest book: "Professional Visual C++ 6 MTS Programming", published by Wrox Press.


What do you think of this article?

You can also write a review. We will publish the best ones here on this article. Send your review to [email protected].

Further Reading


Author: Richard Grimes

Richard Grimes started programming aeons ago on 8-bit computers and hasn't looked back since. He has spent an interesting time as a research scientist (the little known "Grimes Effect" is his creation), underpaid time as a computer trainer and done time as a distributed object developer.

ATL took hold of Richard while he was part of a team developing a COM-based workflow system and its elegance and simplicity has had a lasting effect on him. Although his is not an obsessively pure COM existence, he finds that an ATL-assisted COM lifestyle gives him more time to enjoy his garden.

Go to Richards pages in Author Central.


ASPWebhosting.com

Contribute to IDR:

To contribute an article to IDR, a click here.

To contact us at IDevResource.com, use our feedback form, or email us.

To comment on the site contact our webmaster.

Promoted by CyberSavvy UK - website promotion experts

All content © Copyright 2000 IDevResource.com, Disclaimer notice

WTL Introduction

Visit the IDR Forums

Join the Developers Webring

Code Project

WTL Architecture by Richard Grimes