Visual C++ 6 Unleashed

Visual C++ 6 Unleashed

By MICKEY WILLIAMS and David Bennett

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.

32fig18.gif

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.

32fig19.gif

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.

32fig20.gif

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.

32fig21.gif

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.

32fig22.gif

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:

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:

  1. Open the Project Settings dialog box by choosing Settings from the Project menu.
  2. Select the C++ tab.
  3. Select All Configurations from the Settings combo box. Selecting All Configurations will apply these changes to Release and Debug builds of the project.
  4. Select C++ Language from the Category combo box.
  5. Enable the Enable Exception Handling check box.
  6. 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:

  1. Open the Project Settings dialog box by choosing Settings from the Project menu.
  2. Select the C++ tab.
  3. 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.
  4. Select Preprocessor from the Category combo box.
  5. Remove the _ATL_MIN_CRT macro from the Preprocessor definitions edit control.
  6. 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:

  1. Right-click on the COM+ applications node; then choose New, Application from the context menu. The COM Application Install Wizard appears.
  2. Click Next to move past the welcome page.
  3. Click the icon to create an empty application.
  4. For the application name, enter Visual C++ Bank. Leave the application type set to the default value of Server application, and click Next.
  5. Leave the application identity set to the default value of the interactive user. Click Next.
  6. 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:

  1. Right-click on the Components node; then choose New, Component from the context menu. The COM Component Install Wizard appears.
  2. Click Next to move past the welcome page.
  3. Click the icon to install a new component. A File Open dialog box appears.
  4. Navigate to the directory that contains VcBankApp.dll, select the file, and click Open.
  5. The VcBank component is listed as a component found in the DLL. Click Next to continue.
  6. 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:

  1. Right-click on the VcBank component, and choose Properties from the context menu.
  2. Select the Transactions tab, and click the Transactions Required radio button.
  3. Select the Activation tab, and enable object pooling.
  4. 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:

  1. Open the project workspace Resources tab.
  2. Right-click on the dialog box icon, and choose Insert Dialog from the context menu.
  3. 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.

32fig23.jpg

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.

32fig24.jpg

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.

32fig25.jpg

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.

32fig26.jpg

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.

Share ThisShare This

Informit Network