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.
At this point, you have a project but must still create the component. You can use the ATL Object Wizard to do this. The object wizard contains many types of objects and controls. Some of these objects are already optimized for specific situations—for example, the Transaction Server Object is preset with a lot of the options required by Microsoft Transaction Server, including threading, aggregation, and using the correct headers/libraries.
In this instance, the method name is specified and it has two parameters, lAccountID, which is of type long and the password, which is of type BSTR.
// 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.
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: