- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Understanding Transactions
- COM+ and MTS Features
- An Example of a COM+ Application
- Summary
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
An Example of a COM+ Application
The CD-ROM that accompanies this book includes two projects to show you how an application that supports transactions runs under COM+ in Windows 2000. The VcBankApp project creates a COM+ application using ATL. The BankClient project creates a dialog box-based application that uses the VcBankApp COM+ application to deposit, withdraw, and transfer money between accounts in an Access database.
The VcBank Database
The database used for the VcBankApp application is included on the accompanying CD-ROM. The database is named VcBank.mdb and consists of a single table named AccountTab. Table 32.1 describes the AccountTab table.
Table 32.1. Fields in the AccountTab Table
| Field | Type |
| Account | long |
| Balance | long |
This database tracks the current balance for bank accounts.
Before using the database in the COM+ application, you'll need to register a new data source on your machine that refers to the VcBank data base.
Run the Data Sources applet, which you can find in the Control Panel. The Data Sources applet icon is located in the Control Panel's Administrative Tools folder. Click on the Administrative Tools icon to display the Administrative Tools folder, then click on the Data Sources icon to open the Data Sources applet.
As Figure 32.18 shows, the Data Sources applet includes seven tabs. For the COM+ application, you'll want to create a system DSN—a data source that can be accessed by any user on your machine.
Figure 32.18 Use the Data Sources applet to define data source names.
Click the System DSN tab to display the System DSN page, as shown in Figure 32.19.
Figure 32.19 Use the System DSN page to define data sources accessible by any user.
Click Add to display the Create New Data Source dialog box. You use this dialog box to select the driver to be used to access the data source. Select Microsoft Access Driver (*.mdb) and click Finish to continue. The ODBC Microsoft Access Setup dialog box appears, as shown in Figure 32.20.
Figure 32.20 The ODBC Microsoft Access Setup dialog box.
Enter a name for the data source; the VcBank application requires the name to be Vc Bank Data. Feel free to enter a description for the data source, although it is not required for this example.
To specify the path to the database, click Select. The database must be located on your hard drive instead of on the book's CD-ROM. Click OK to dismiss the dialog box and create the data source.
Creating the VCBankApp COM+ Module
The VCBank COM+ component is housed in an in-process server created using an ATL named VCBankApp. The complete source for the project is located on the CD-ROM that accompanies this book; the steps required to create the project are described in the following sections.
To begin building the project, create an ATL project named VcBankApp using the ATL COM AppWizard. Use the settings provided in Table 32.2 to fill in the first wizard page.
Table 32.2. VcBankApp ATL COM AppWizard Values
| Option | Setting |
| Server Type | Dynamic Link Library |
| Allow Merging of Proxy/Stub Code | Unchecked |
| Support MFC | Unchecked |
| Support MTS | Checked |
To create the project and dismiss the wizard, click Finish.
Inserting the VcBank COM+ Component
The next step is to add the VcBank component to the project. Choose New ATL Object from the Insert menu. The ATL Object Wizard appears, as shown in Figure 32.21.
Figure 32.21 Using the ATL Object Wizard to insert a component that supports transactions.
Select the MS Transaction Server Component object type, and click Next. The ATL Object Properties dialog box appears, as shown in Figure 32.22.
Figure 32.22 The ATL Object Wizard Properties dialog box.
Fill in this dialog box using the properties provided in Table 32.3. You should only need to provide the short name for the component—the other values are filled in automatically.
Table 32.3. Name Properties for the VcBank Components
| Option | Value |
| Short Name | VcBank |
| Class | CVcBank |
| .H File | VcBank.h |
| .CPP File | VcBank.cpp |
| CoClass | VcBank |
| Interface | IVcBank |
| Type | VcBank Class |
| Prog ID | VcBankApp.VcBank |
The options in Table 32.3 are identical to the parameters used in all COM objects built using ATL. The purpose of these properties is to define the names and symbols that will be used by the new object.
Select the MTS tab, and select the properties shown in Table 32.4.
Table 32.4. Name Properties for the VcBank Components
| Option | Setting |
| Interface | Dual |
| Support IObjectControl | Checked |
| Can Be Pooled | Checked |
Click OK to insert the VcBank component into the VcBankApp project. The files and classes associated with the component are added to the project workspace window.
Adding Interface Methods to the VcBank Component
Four methods must be added to the VcBank component:
- Balance returns the current balance for an account.
- Withdraw removes money from an account.
- Deposit adds money to an account.
- Transfer moves money from one account to another.
To add these methods, right-click on the IVcBank icon in the project workspace class view, and choose Add Method from the context menu. The Add Method dialog box appears and requires two pieces of information: the method's name and the method's parameters. After providing these two properties, click OK to add the method to the component. Use the values in Table 32.5 to add the four new methods to the VcBank component.
Table 32.5. Name Properties for the VcBank Component
| Method | Parameters |
| Balance | [in]long account, [out]long* balance |
| Withdraw | [in]long account, [in]long amount |
| Deposit | [in]long account, [in]long amount |
| Transfer | [in]long source, [in]long dest, [in]long amt |
Changes to StdAfx.h
The VcBank component will use ActiveX Data Objects (ADO) to interact with the bank database. Add the code provided in Listing 32.1 to the project's StdAfx.h header file. Insert this code after the #include directive for atlcom.h.
Example 32.1. The #import Directive for ADO for the VcBankApp Project
#import "c:\program files\common files\system\ado\msado15.dll" }
no_namespace rename("EOF", "adoEOF")
The #import directive in Listing 32.1 causes the compiler to generate a header file that contains smart pointers and other types that may be used to simplify programming with ADO.
Changes to VcBank.h
In order for a COM+ component to be pooled, it must support aggregation. In order for the VcBank component to support aggregation, you need to make one minor change to the VcBank.h header file. By default, Visual C++ inserts the DECLARE_NOT_AGGREGATABLE macro into your component's header file. This macro must be changed to a DECLARE_AGGREGATABLE macro, like this:
DECLARE_AGGREGATABLE(CVcBank)
This is the only change required to the VcBank.h header file.
Adding Helper Functions to VcBank.cpp
The interface methods used in the VcBank component will use two helper functions. The AccountToCmdString method takes an account number as a parameter and returns a _bstr_t that contains the SQL query string that selects the relevant record in the data base. The UpdateBalance function has two parameters: the account number and a new balance for the account. Listing 32.2 provides the source code for these two functions. Add these functions to the VcBank.cpp source file before any other functions in the file.
Example 32.2. Helper Functions Used in VcBank.cpp
// Given an account number, create a SQL command string that
// selects the account number from the database.
_bstr_t AccountToCmdString(long account)
{
char szAccount[256];
wsprintf(szAccount, "%d", account);
_bstr_t bstrCmd = L"SELECT * FROM AccountTab WHERE Account = ";
bstrCmd += szAccount;
return bstrCmd;
}
// Given an account number, update the account balance.
HRESULT UpdateBalance(long account, long amount)
{
_RecordsetPtr rs = NULL;
_bstr_t bstrAccount = AccountToCmdString(account);
try
{
_variant_t vBalance;
rs.CreateInstance(__uuidof(Recordset));
rs->Open(bstrAccount,
"DSN=VC Bank Data",
adOpenForwardOnly,
adLockOptimistic,
adCmdText);
rs->PutCollect(L"Balance", amount);
rs->Update();
rs->Close();
}
catch(_com_error& e)
{
return e.Error();
}
return S_OK;
}
The AccountToCmdString function simply concatenates the account number to a SQL query string. The UpdateBalance function is more complicated, however. The function begins by calling AccountToCmdString to create the appropriate query string toward the database. An ADO recordset object is created and is opened using the query string. The recordset then is updated using the new account balance.
Note that the UpdateBalance function uses C++ exception handling. In order for this component to work properly, you must enable C++ exception handling for the VcBankApp project by following these steps:
- Open the Project Settings dialog box by choosing Settings from the Project menu.
- Select the C++ tab.
- Select All Configurations from the Settings combo box. Selecting All Configurations will apply these changes to Release and Debug builds of the project.
- Select C++ Language from the Category combo box.
- Enable the Enable Exception Handling check box.
- Click OK to close the dialog box.
Additionally, you must remove the _ATL_MIN_CRT preprocessor macro that is included by default in all ATL release builds. This macro definition prevents the C runtime library from being linked with the project, resulting in smaller, faster code with fewer dependencies. Since this project uses exception handling, the C runtime is required. Remove the _ATL_MIN_CRT macro by following these steps:
- Open the Project Settings dialog box by choosing Settings from the Project menu.
- Select the C++ tab.
- Select Multiple Configurations from the Settings combo box, which will display a dialog box containing all build configurations for the project. Check all Release builds, and close the dialog box by clicking OK.
- Select Preprocessor from the Category combo box.
- Remove the _ATL_MIN_CRT macro from the Preprocessor definitions edit control.
- Click OK to close the dialog box.
Implementing the VcBank Interface Methods
The function bodies for each of the four VcBank interface methods have been created in VcBank.cpp. Modify these functions by adding the source code shown in bold in Listing 32.3.
Example 32.3. The VcBank Interface Methods
STDMETHODIMP CVcBank::Balance(long account, long *balance)
{
_RecordsetPtr rs = NULL;
_bstr_t bstrAccount = AccountToCmdString(account);
try
{
_variant_t vBalance;
rs.CreateInstance(__uuidof(Recordset));
rs->Open(bstrAccount,
"DSN=VC Bank Data",
adOpenForwardOnly,
adLockReadOnly,
adCmdText);
vBalance = rs->Fields->GetItem("Balance")->Value;
*balance = vBalance;
rs->Close();
m_spObjectContext->SetComplete();
}
catch(_com_error& e)
{
m_spObjectContext->SetAbort();
return e.Error();
}
return S_OK;
}
STDMETHODIMP CVcBank::Withdraw(long account, long amount)
{
long balance = 0;
HRESULT hr = Balance(account, &balance);
if(SUCCEEDED(hr))
{
if(balance < amount)
{
m_spObjectContext->SetAbort();
return E_FAIL;
}
balance -= amount;
hr = UpdateBalance(account, balance);
}
if(FAILED(hr))
m_spObjectContext->SetAbort();
else
m_spObjectContext->SetComplete();
return hr;
}
STDMETHODIMP CVcBank::Deposit(long account, long amount)
{
long balance = 0;
HRESULT hr = Balance(account, &balance);
if(SUCCEEDED(hr))
{
balance += amount;
hr = UpdateBalance(account, balance);
}
if(FAILED(hr))
m_spObjectContext->SetAbort();
else
m_spObjectContext->SetComplete();
return hr;
}
STDMETHODIMP CVcBank::Transfer(long source, long dest, long amt)
{
long balance = 0;
HRESULT hr = Balance(source, &balance);
if(SUCCEEDED(hr))
{
if(balance < amt)
return E_FAIL;
long newBalance = balance - amt;
hr = UpdateBalance(source, newBalance);
if(SUCCEEDED(hr))
{
hr = Balance(dest, &balance);
if(SUCCEEDED(hr))
{
newBalance = balance + amt;
hr = UpdateBalance(dest, newBalance);
}
}
}
if(FAILED(hr))
m_spObjectContext->SetAbort();
else
m_spObjectContext->SetComplete();
return hr;
}
The functions in Listing 32.3 use some basic ADO code to interact with the VcBank database. Each of these functions calls SetAbort or SetComplete, depending on the function's success or failure. This is especially useful when performing a money transfer. The transfer of money consists of two operations:
- The removal of money from the first account
- The addition of money to the second account
If the first operation succeeds but the second fails, SetAbort is called, causing the first operation to be rolled back. This type of mechanism is especially useful when a transaction consists of operations performed by multiple components. If any component calls SetAbort, the entire transaction rolls back.
Registering the VcBank COM+ Application
Open the COM+ MMC snap-in and select the COM+ applications node. Create a new COM+ application by following these steps:
- Right-click on the COM+ applications node; then choose New, Application from the context menu. The COM Application Install Wizard appears.
- Click Next to move past the welcome page.
- Click the icon to create an empty application.
- For the application name, enter Visual C++ Bank. Leave the application type set to the default value of Server application, and click Next.
- Leave the application identity set to the default value of the interactive user. Click Next.
- Click Finish to complete the application creation procedure.
The next step is to add the VcBank component to the COM+ application. Expand the tree node associated with the Visual C++ Bank and the component by following these steps:
- Right-click on the Components node; then choose New, Component from the context menu. The COM Component Install Wizard appears.
- Click Next to move past the welcome page.
- Click the icon to install a new component. A File Open dialog box appears.
- Navigate to the directory that contains VcBankApp.dll, select the file, and click Open.
- The VcBank component is listed as a component found in the DLL. Click Next to continue.
- Click Finish to complete the component installation.
The component now is registered in the COM+ catalog. Some changes must be made to the component before you use it in this example, however. Finish configuring the component by following these steps:
- Right-click on the VcBank component, and choose Properties from the context menu.
- Select the Transactions tab, and click the Transactions Required radio button.
- Select the Activation tab, and enable object pooling.
- Click OK to complete the configuration changes.
The Visual C++ Bank COM+ application now is registered and ready to use. The next several sections create a client application that will use the component.
A Client Application for VcBank
You can access a COM+ application in a number of ways. Visual Basic, the Windows Scripting Host (WSH), and Active Server Pages (ASP) are three of the more popular ways to use COM+ applications. Because this is a Visual C++ book, this chapter creates an MFC application that serves as a client to the VcBank component.
Begin by using MFC AppWizard to create a dialog-based application named BankClient. Accept all the default properties for a dialog box–based application.
Adding Dialog Boxes to the BankClient Project
The BankClient project consists of several dialog boxes. In addition to the dialog boxes created by AppWizard, you must add three new dialog boxes to the BankClient project:
- A dialog box to handle withdrawals from an account
- A dialog box to handle deposits to an account
- A dialog box to handle money transfers between accounts
Begin by adding three new dialog box resources to the BankClient project:
- Open the project workspace Resources tab.
- Right-click on the dialog box icon, and choose Insert Dialog from the context menu.
- Repeat Step 2 twice to create three dialog boxes.
Use the information in Table 32.6 to set the properties for each dialog box.
Table 32.6. New Dialog Boxes for the BankClient Project
| Resource ID | Caption |
| IDD_DEPOSIT | Deposit to account |
| IDD_WITHDRAW | Withdraw from account |
| IDD_TRANSFER | Transfer money to another account |
Figure 32.23 shows the IDD_DEPOSIT dialog box. Add two edit controls and two static text labels to the dialog box.
Figure 32.23 The BankClient Deposit dialog box.
Use the values from Table 32.7 to define the properties for the new controls.
Table 32.7. Control Properties for the Deposit Dialog Box
| Control | Resource ID | Caption |
| Account edit | IDC_ACCOUNT | None |
| Amount edit | IDC_AMOUNT | None |
| Account label | IDC_STATIC | Account |
| Amount label | IDC_STATIC | Amount |
In addition to the properties listed in Table 32.7, the IDC_ACCOUNT edit control has the read-only property.
Use the ClassWizard to associate a new class with the dialog box. Open ClassWizard by pressing Ctrl+W. As the ClassWizard opens, you are asked whether a new class should be created or an existing class reused. Select the default option, which is to create a new class to manage the dialog box, and click OK. The New Class dialog box appears.
Use the values in Table 32.8 to fill in the New Class dialog box.
Table 32.8. New Class Dialog Box Properties for the Deposit Dialog Box
| Property | Value |
| Class Name | CDlgDeposit |
| Base Class | CDialog |
| Dialog ID | IDD_DEPOSIT |
| Automation | None |
Click OK to add the CDlgDeposit class to the project, and then use the values in Table 32.9 to associate two CDlgDeposit member variables with dialog box controls.
Table 32.9. New Class Dialog Box Properties for the Deposit Dialog Box
| Control ID | Variable Name | Category | Type |
| IDC_ACCOUNT | m_nAccount | Value | long |
| IDC_AMOUNT | m_nAmount | Value | long |
Click OK to dismiss the ClassWizard, and add the new member variables to the project.
The IDD_WITHDRAW dialog box is similar to the IDD_DEPOSIT dialog box (see Figure 32.24). Add two edit controls and two static text labels to the dialog box.
Figure 32.24 The BankClient Withdraw dialog box.
Use the values in Table 32.10 to define the properties for the new controls.
Table 32.10. Control Properties for the Withdraw Dialog Box
| Control | Resource ID | Caption |
| Account edit | IDC_ACCOUNT | None |
| Amount edit | IDC_AMOUNT | None |
| Account label | IDC_STATIC | Account |
| Amount label | IDC_STATIC | Amount |
In addition to the properties listed in Table 32.10, the IDC_ACCOUNT edit control has the read-only property.
Use the ClassWizard to associate a new class with the Withdraw dialog box. Open the ClassWizard by pressing Ctrl+W, and elect to create a new class to manage the dialog box. The New Class dialog box appears.
Use the values in Table 32.11 to fill in the New Class dialog box.
Table 32.11. New Class Dialog Box Properties for the Withdraw Dialog Box
| Property | Value |
| Class Name | CDlgWithdraw |
| Base Class | CDialog |
| Dialog ID | IDD_WITHDRAW |
| Automation | None |
Click OK to add the CDlgWithdraw class to the project, and then use the values in Table 32.12 to associate two CDlgWithdraw member variables with dialog box controls.
Table 32.12. New Class Dialog Box Properties for the Withdraw Dialog Box
| Control ID | Variable Name | Category | Type |
| IDC_ACCOUNT | m_nAccount | Value | long |
| IDC_AMOUNT | m_nAmount | Value | long |
Click OK to dismiss the ClassWizard and add the new member variables to the project.
Figure 32.25 shows the IDD_TRANSFER dialog box. Add three edit controls and three static text labels to the dialog box.
Figure 32.25 The BankClient Transfer dialog box.
Use the values in Table 32.13 to define the properties for the new controls.
Table 32.13. New Dialog Boxes for the BankClient Project
| Control | Resource ID | Caption |
| From account edit | IDC_ACCOUNT | None |
| To account edit | IDC_TO_ACCOUNT | None |
| Amount edit | IDC_AMOUNT | None |
| From account label | IDC_STATIC | From Account |
| To account label | IDC_STATIC | To Account |
| Amount label | IDC_STATIC | Amount |
In addition to the properties listed in Table 32.13, the IDC_ACCOUNT edit control has the read-only property.
As with the previous dialog boxes, use the ClassWizard to associate a new class with the dialog box. Use the values from Table32.14 to fill in the New Class dialog box.
Table 32.14. New Class Dialog Box Properties for the Transfer Dialog Box
| Property | Value |
| Class Name | CDlgTransfer |
| Base Class | CDialog |
| Dialog ID | IDD_TRANSFER |
| Automation | None |
Click OK to add the CDlgTransfer class to the project, and then use the values in Table 32.15 to associate three CDlgTransfer member variables with dialog box controls.
Table 32.15. New Class Dialog Box Properties for the Transfer Dialog Box
| Control ID | Variable Name | Category | Type |
| IDC_ACCOUNT | m_nAccount | Value | long |
| IDC_AMOUNT | m_nAmount | Value | long |
| IDC_TO_ACCOUNT | m_nDestination | Value | long |
Click OK to dismiss the ClassWizard and add the new member variables to the project.
Modifying the Main Dialog Box for BankClient
Figure 32.26 shows the main dialog box for the BankClient application. Add one edit control, three static text labels, and four pushbutton controls to the dialog box. The IDC_BALANCE_LABEL static control is located directly under the edit control, but isn't shown in the figure because it has no caption.
Figure 32.26 The main dialog box for BankClient.
Use the values in Table 32.16 to define the properties for the new controls.
Table 32.16. Control Properties for the Withdraw Dialog Box
| Control | Resource ID | Caption |
| Account edit | IDC_ACCOUNT | None |
| Balance value | IDC_BALANCE_LABEL | None |
| Account label | IDC_STATIC | Account |
| Balance label | IDC_STATIC | Balance |
| Balance button | IDC_BALANCE | &Balance |
| Withdraw button | IDC_WITHDRAW | &Withdraw |
| Deposit button | IDC_DEPOSIT | &Deposit |
| Transfer button | IDC_TRANSFER | &Transfer |
Use the values in Table 32.17 to associate a CBankClientDlg member variable with the dialog box control.
Table 32.17. Control Properties for the Main Dialog Box
| Control ID | Variable Name | Category | Type |
| IDC_ACCOUNT | m_strAccount | Value | CString |
Use the values in Table 32.18 to add four message-handling functions to the CBankClientDlg class. These functions will handle messages generated when the pushbuttons in the main dialog box are clicked.
Table 32.18. Message-Handling Functions for the Main Dialog Box
| Object ID | Message | Function |
| IDC_BALANCE | BN_CLICKED | OnBalance |
| IDC_WITHDRAW | BN_CLICKED | OnWithdraw |
| IDC_DEPOSIT | BN_CLICKED | OnDeposit |
| IDC_TRANSFER | BN_CLICKED | OnTransfer |
Click OK to dismiss the ClassWizard.
Accessing the COM+ Application
For maximum efficiency, COM+ clients typically acquire references to COM+ objects as early as possible and release them as late as possible. The BankClient application will hold on to a single IVcBank interface pointer for as long as the application is running. The COM+ application will use just-in-time activation and object pooling to make the application as efficient as possible.
To include definitions for the symbols used in the VcBankApp module, copy the VcBankApp.h and VcBankApp_i.c files from the VcBankApp project directory to the BankClient project directory.
Add the following #include directive to the StdAfx.h header file after the existing #include directives.
#include "vcbankapp.h"
Add the following #include directive to the BankClientDlg.cpp source file. This file contains definitions for the CLSID and other symbols from VcBankApp.
#include "vcbankapp_i.c"
Add a new member variable to the CBankClientDlg class. The new member variable is an ATL smart pointer that will store a pointer to the IVcBank interface. In Listing 32.4, the modification to the CBankClientDlg class is shown in bold, with most existing lines in the class removed to conserve space.
Example 32.4. Modifications (in bold) to the CBankClientDlg Declaration
class CBankClientDlg : public CDialog
{
// Implementation
protected:
HICON m_hIcon;
CComQIPtr<IVcBank> m_pBank;
};
The m_pBank interface pointer is set when the dialog box is initialized. The initialization code is provided in Listing 32.5 and is located in the CBankClientDlg::OnInitDialog function. As with the preceding listing, the new code is shown in bold, and many existing lines have been removed for clarity and to conserve space.
Example 32.5. Modifications (in bold) to the CBankClientDlg::OnInitDialog Function
BOOL CBankClientDlg::OnInitDialog()
{
// TODO: Add extra initialization here
CoInitializeEx(NULL, COINIT_MULTITHREADED);
HRESULT hr = m_pBank.CoCreateInstance(CLSID_VcBank);
if(FAILED(hr))
{
ErrorHandling(hr);
}
return TRUE;
}
The m_pBank member variable is an ATL smart pointer. In order to use this type of variable, you must include one of the ATL header files into the project. Add the following #include directive to the StdAfx.h header file after the existing #include directives.
#include "atlbase.h"
Also, in order to use multithreaded COM features, you must add the following preprocessor directive to the top of the StdAfx.h header file before any existing #include directives.
#define _WIN32_WINNT 0x0400
Retrieving an Account Balance
Listing 32.6 provides the code required to retrieve an account balance. Add this code to the CBankClientDlg::OnBalance member function.
Example 32.6. Retrieving an Account Balance in BankClient
void CBankClientDlg::OnBalance()
{
long nBalance = 0;
BOOL fValid = FALSE;
int nAccount = GetDlgItemInt(IDC_ACCOUNT, &fValid);
if(!fValid)
{
AfxMessageBox("Please enter an account number");
return;
}
ASSERT(m_pBank);
HRESULT hr = m_pBank->Balance(nAccount, &nBalance);
if(SUCCEEDED(hr))
SetDlgItemInt(IDC_BALANCE_LABEL, nBalance);
}
The OnBalance function begins by retrieving the account ID from the account edit control. The account number and a pointer to a variable that will store the account balance then are passed the IVcBank::Balance function. If the function succeeds, the balance label is updated with the account balance.
Making a Deposit
Listing 32.7 provides the code used to deposit additional money into an account. Add this code to the CBankClientDlg::OnDeposit member function.
Example 32.7. Depositing Money into an Account in BankClient
void CBankClientDlg::OnDeposit()
{
CDlgDeposit dlg;
BOOL fValid = FALSE;
int nAccount = GetDlgItemInt(IDC_ACCOUNT, &fValid);
if(!fValid)
{
AfxMessageBox("Please enter an account number");
return;
}
dlg.m_nAccount = nAccount;
if(!dlg.DoModal())
{
return;
}
ASSERT(m_pBank);
HRESULT hr = m_pBank->Deposit(nAccount, dlg.m_nAmount);
if(FAILED(hr))
AfxMessageBox("Could not deposit to account");
long nBalance = 0;
hr = m_pBank->Balance(nAccount, &nBalance);
if(SUCCEEDED(hr))
SetDlgItemInt(IDC_BALANCE_LABEL, nBalance);
}
Like the OnBalance function, the OnDeposit function begins by retrieving the account ID from the account edit control. The CDlgDeposit class is used to collect the amount of money to be added to the account. The account number and the amount of money to be deposited are passed the IVcBank::Withdraw function. If the function succeeds, the balance label is updated with the account balance.
The OnDeposit function uses the CDlgDeposit class to collect information about the deposit from the user. Add the following #include directive below the existing #include directives in the BankClientDlg.cpp file:
#include "dlgdeposit.h"
Making a Withdrawal
Listing 32.8 shows the code used to make a withdrawal from an account. Add this code to the CBankClientDlg::OnWithdraw member function.
Example 32.8. Withdrawing Money from an Account in BankClient
void CBankClientDlg::OnWithdraw()
{
CDlgWithdraw dlg;
BOOL fValid = FALSE;
int nAccount = GetDlgItemInt(IDC_ACCOUNT, &fValid);
if(!fValid)
{
AfxMessageBox("Please enter an account number");
return;
}
dlg.m_nAccount = nAccount;
if(!dlg.DoModal())
{
// User cancelled dialog box.
return;
}
ASSERT(m_pBank);
HRESULT hr = m_pBank->Withdraw(nAccount, dlg.m_nAmount);
if(FAILED(hr))
AfxMessageBox("Could not withdraw from account");
long nBalance = 0;
hr = m_pBank->Balance(nAccount, &nBalance);
if(SUCCEEDED(hr))
SetDlgItemInt(IDC_BALANCE_LABEL, nBalance);
}
The OnWithdraw function works very much like the OnDeposit function. The OnWithdraw function begins by retrieving the account ID from the account edit control. The CDlgWithdraw class is used to collect the amount of money to be withdrawn from the account. The account number and the amount of money to be withdrawn are passed the IVcBank::Withdraw function. If the function succeeds, the balance label is updated with the account balance.
The OnWithdraw function uses the CDlgWithdraw class to collect information about the deposit from the user. Add the following #include directive below the existing #include directives in the BankClientDlg.cpp file:
#include "dlgwithdraw.h"
Transferring Money Between Accounts
Money is transferred between accounts using the code provided in Listing 32.9. Add this code to the CBankClientDlg::OnTransfer member function.
Example 32.9. Transferring Money Between Accounts in BankClient
void CBankClientDlg::OnTransfer()
{
CDlgTransfer dlg;
BOOL fValid = FALSE;
int nAccount = GetDlgItemInt(IDC_ACCOUNT, &fValid);
if(!fValid)
{
AfxMessageBox("Please enter an account number");
return;
}
dlg.m_nAccount = nAccount;
if(!dlg.DoModal())
{
// User cancelled dialog box.
return;
}
ASSERT(m_pBank);
HRESULT hr = m_pBank->Transfer(nAccount, dlg.m_nDestination, dlg.m_nAmount);
if(FAILED(hr))
AfxMessageBox("Could not transfer from account");
long nBalance = 0;
hr = m_pBank->Balance(nAccount, &nBalance);
if(SUCCEEDED(hr))
SetDlgItemInt(IDC_BALANCE_LABEL, nBalance);
}
The OnTransfer function works like the previous two functions. The account number is retrieved from the account edit control, and the CDlgTransfer class is used to retrieve the destination account and transfer amount. The account number, destination account, and amount of money to be transferred are passed the IVcBank::Transfer function. If the function succeeds, the balance label is updated with the account balance.
The OnTransfer function uses the CDlgTransfer class to collect information about the money transfer from the user. Add the following #include directive below the existing #include directives in the BankClientDlg.cpp file:
#include "dlgtransfer.h"
Using BankClient
Compile and run the BankClient project. The database supplied with the CD-ROM has two account numbers: 1111 and 1234. Use the BankClient application to retrieve the account balances, make deposits, and transfer money between the accounts.
You may notice a delay when the COM+ component is executed for the first time. This is normal, and the call time is typically much faster for additional method calls.
Summary | Next Section

Account Sign In
View your cart