Using Visual C++ 5.0 to Build Microsoft Transaction Server Components

To create a Microsoft Transaction Server component with Microsoft Visual C++ version 5.0, you must create an Active Template Library (ATL). An ATL is a set of template-based C++ classes with which you can easily create small, fast COM objects. It has unique support for key COM features including: stock implementations of IUnknown, IClassFactory, IClassFactory2 and Idispatch interfaces; dual interfaces; standard COM enumerator interfaces; connection points; tear-off interfaces; and ActiveX controls.

ATL provides built-in support for many fundamental COM interfaces and can be used to create single-thread objects, apartment-model objects, free-thread–model objects, or both free-thread and apartment-model objects. ATL allows you to create COM objects as well as an Automation server and ActiveX controls.

Template libraries, such as ATL, differ from traditional C++ class libraries in that they are typically supplied only as source code (or as source code with some supporting run time) and are not inherently or necessarily hierarchical in nature. Rather than deriving functionality from a class, you instantiate a class from a template.

Code Sample

// Connect.cpp
#include "stdafx.h"
#include "connect.h"

CConnection::CConnection()
{
   m_hEnv = NULL;
   m_hDBC = NULL;
   m_hStmt = NULL;
}

CConnection::~CConnection()
{
   if ((m_hStmt != NULL) || (m_hDBC != NULL) || (m_hEnv != NULL))
      FreeConnection();
}

BOOL CConnection::InitConnection()
{
   RETCODE rc;

   ::SQLAllocEnv(&m_hEnv);
   ::SQLAllocConnect(m_hEnv, &m_hDBC);
   ::SQLConnect(m_hDBC, (UCHAR FAR*) "VCEESamples", SQL_NTS,
                   (UCHAR FAR*) "sa", SQL_NTS,
                   NULL, SQL_NTS);
   rc = ::SQLAllocStmt(m_hDBC, &m_hStmt);

   if (rc == SQL_SUCCESS)
      return TRUE;
   else
      return FALSE;
}

BOOL CConnection::FreeConnection()
{
   RETCODE rc = SQL_SUCCESS;

   if (m_hStmt != NULL)
   {
      ::SQLFreeStmt(m_hStmt, SQL_DROP);
      m_hStmt = NULL;
   }

   if (m_hDBC != NULL)
   {
      ::SQLDisconnect(m_hDBC);
      ::SQLFreeConnect(m_hDBC);
      m_hDBC = NULL;
   }

   if (m_hEnv != NULL)
   {
      rc = ::SQLFreeEnv(m_hEnv);
      m_hEnv = NULL;
   }

   if (rc == SQL_SUCCESS)
      return TRUE;
   else
      return FALSE;
}
// Connect.h : declarations for simple ODBC connection 
//

#ifndef ___CONNECTION___
#define ___CONNECTION___

#include "stdafx.h"

class CConnection
{
// Constructors and Destructors
public:
   CConnection();
   ~CConnection();

// Attributes
protected:
   HENV    m_hEnv;
   HDBC    m_hDBC;
   HSTMT   m_hStmt;

public:
   HSTMT   GetStatement() { return m_hStmt; };


// Operations
public:
   BOOL InitConnection();
   BOOL FreeConnection();
};

#endif // ___CONNECTION___

Because you will use ODBC, you must add SQL headers to the Stdafx.h file and the Odbc32.lib file to the link line.

// stdafx.h: Include file for standard system include files
//      or project-specific include files that are used frequently
//      but changed infrequently.

#if !defined(AFX_STDAFX_H__7AD7B931_FC53_11D0_971C_00C04FB907A0__INCLUDED_)
#define AFX_STDAFX_H__7AD7B931_FC53_11D0_971C_00C04FB907A0__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#define STRICT


#define _WIN32_WINNT 0x0400
#define _ATL_APARTMENT_THREADED


#include <atlbase.h>
//You can derive a class from CComModule and use it if you want 
//to override something, but do not change the name of 
//_Module extern CComModule _Module;
#include <atlcom.h>

//{{AFX_INSERT_LOCATION}}
//Microsoft Developer Studio will insert additional declarations
//immediately before the previous line.

#endif 
//!defined(AFX_STDAFX_H__7AD7B931_FC53_11D0_971C_00C04FB907A0__INCLUDED)

To add Odbc32.lib, click Project, Settings, All Configurations, and then the Link tab, and add Odbc32.lib in the Libraries line.

To implement this method, first declare and initialize the connection to the database. The InitConnection function connects to the database.

Because you will use Microsoft Transaction Server, you disconnect from the database as soon as you are finished with the operation. MTS, through the ODBC version 3.0 driver manager, will automatically pool this connection. If the application requires the connection again, it will be set up from the pool.

rc = ::SQLPrepare(connection.GetStatement(), 
      (SQLCHAR*)"{call sp_validaccount2(?,?)}", SQL_NTS);
rc = ::SQLBindParameter(connection.GetStatement(), 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &lAccountID, 0, &cbAccountID);
rc = ::SQLBindParameter(connection.GetStatement(), 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 4, 0, &szPin[0], _tcslen(&szPin[0]), &cbPin);

rc = ::SQLExecute(connection.GetStatement());
connection.FreeConnection();

if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
{
   m_spObjectContext->SetAbort();
   return E_FAIL;
}

m_spObjectContext->SetComplete();
return S_OK;

The SQLPrepare and SQLexecute functions are the only implementation required. After you have completed coding, you generate the DDL with Visual C++ and then use Microsoft Transaction Server Explorer to build a package and register it with the Microsoft Transaction Server run-time environment.

Debugging Tip

Visual C++ allows for debugging of transaction components either locally or from a remote server. When you use Microsoft Transaction Server Explorer, the run-time environment allocates a transaction context. As an optimization, MTS won't allocate transactions unless it has to. By specifying that the component will run as an in-process server, you can then debug the component. To do this, click the Activation tab and select In the creator's process. You can leave In a server process selected as well.

To prevent deadlocking, MTS terminates a transaction after a preset amount of time. While debugging your component, you could easily exceed the default time of 60 seconds. To disable this, click the properties for the computer and set its transaction timeout to zero seconds. This allows you to stop on breakpoints properly.

To do this, right click My Computer, and then click Properties. Select options, and then set the transaction timeout to 0 seconds.

Here are a few other things you should remember when creating MTS components and applications: