Figure 1   The COM+ BarcodeScanner1 Class


 coclass BarcodeScanner1 
 {
 public:
     BarcodeScanner1();
     ~BarcodeScanner1();
 
 private:
     long    m_lStatus;
 };
 
 BarcodeScanner1::BarcodeScanner1() : m_lStatus(SCANNER_OK)
 {
     // code to initialize scanner hardware
     // (updates m_lStatus…)
 •
•
•
}
 
 BarcodeScanner1::~BarcodeScanner1()
 {
     if (m_lStatus != SCANNER_DEAD)
     {
         // code to terminate scanner hardware
     }
 }


Figure 2   The COM+ Register1 Class


 #import "BarcodeScanner1"
 
 coclass Register1
 {
 public:
     Register1();
     ~Register1();
 
 private:
     transient BarcodeScanner1* m_pScanner;
 
 };
 
 // Constructor
 Register1::Register1()
 {
     // To create a new COM+ object, just call new
     m_pScanner = new BarcodeScanner1();
 }
 
 // Destructor
 Register1::~Register1()
 {
     // No need to delete COM+ objects, just get rid of
     // the reference
     m_pScanner = NULL;
 }

Figure 3   Data Types Supported by COM+

Type Size (bits)
Boolean 8
BSTR 32
Byte 8
Char 16
ClassRef (any class type) 32
COM interface pointer 32
Const (any native type)
Currency 64
Date 64
Double 64
Float 32
HRESULT 32
Int 32
Java array (any native type)
Long 64
Pointer (any native type) 32
Reference counted object reference 32
Safearray
Short 16
Sized array 32
Unsigned char 8
Unsigned int 32
Unsigned long 64
Unsigned short 16
UUID 128
Variant 128
Void 0


Figure 4   Barcode Scanner Using Cointerface IScanner


 // this is an interface definition in C++ 
 // methods are pure and abstract by default, no
 // need to clutter up the source code with modifiers.
 cointerface IScanner
 {
     long Test();
     long Reset();
 };
 
 // this is an event interface definition
 cointerface IScanEvent
 {
     void NewScan(String strBarcode);
 }
 
 // BarcodeScanner class, now using interfaces, events, 
 // and attributes
 coclass BarcodeScanner : 
     implements IScanner, 
     fires IScanEvent
 {
 attributes:
     threading="rental";
 
 public:
     BarcodeScanner();
     ~BarcodeScanner();
     long Test();
     long Reset();
 
 private:
     long    m_lStatus;
 
     void CaptureBarcodes();
 };
 
 BarcodeScanner::BarcodeScanner() : m_lStatus(SCANNER_OK)
 {
 •
•
•
    CaptureBarcodes();
 }
 
 •
•
•

 void BarcodeScanner::CaptureBarcodes()
 {
     // of course, we'd really spin off a separate 
     // thread to watch for input, but this snippet
     // will just show the code here…
     for (;;)
     {
         String strScan;
         // lots of work to read barcode into strScan
   •
  •
  •
        // hey, we got one - fire an event
         NewScan(strScan);
    •
   •
   •
    }
 }
 
 // Just in case the barcode scanner doesn't work,
 // the cashier can enter barcodes at her keypad.
 coclass CashierKeypad :  
     fires IScanEvent
 {
 attributes:
     threading="rental";
 
 public:
     CashierKeypad();
 
 private:
     void MonitorKeypad();
     void OnCaptureBarcode();
 };
 
 •
•
•

 // assume the MonitorKeypad method sits in a loop that
 // detects keypad commands and calls this method when
 // the "Enter Barcode" button is pressed.
 void CashierKeypad::OnCaptureBarcode()
 {
     String strScan;
     // lots of work to read keypad into strScan
 •
•
•
    // hey, we got one - fire an event
     NewScan(strScan);
 •
•
•
}

Figure 5   The COM+ Register Class


 #import "BarcodeScanner"
 #import "CashierKeypad"
 #import "IScanEvent"
 
 coclass Register : implements IScanEvent
 {
 public:
     Register();
     ~Register();
 
     // IScanEvent
     void OnNewScan(String strScan);
 
 private:
     transient BarcodeScanner* m_pScanner;
     transient CashierKeypad*  m_pKeypad;
 
 };
 
 // Constructor
 Register::Register()
 {
     // To create a new COM+ object, just call new
     m_pScanner = new BarcodeScanner();
     m_pKeypad = new CashierKeypad();
 
     // Hook up events. Note that both sources route to the
     // same function. We don't care where the barcode scan
     // comes from, as long as we get one
     m_pScanner->NewScan = OnNewScan;
     m_pKeypad->NewScan = OnNewScan;
 }
 
 // Destructor
 Register::~Register()
 {
     // No need to delete COM+ objects, just get rid of
     // the references
     m_pScanner = NULL;
     m_pKeypad = NULL;
 }
 
 // Handle new barcode scan event
 void Register::OnNewScan(String newScan)
 {
     // do a bunch of work to look up barcode in inventory
     // and create a new sales line item
 }


Figure 6   Attribute-based Programming


 cointerface IBank
 {
     double DebitCredit([in]long lAccount, 
                        [in]double dAmount);
 }
 
 coclass Bank : implements IBank
 {
 attributes:
     transaction = "required";
     data_source = "DSN=BankDatabase";
     state = "stateless";
     threading = "rental";
 
 public:
     DataSource m_dsBank;
     
     [ source=m_dsBank, column="balance" ] 
     double m_dBalance;
 
     double DebitCredit(long lAccount, double dAmount)
         throws SQLException
     {
         m_dsBank.Source = "select * from Accounts where id=" 
             + ToString(lAccount);
         m_dBalance = m_dBalance + dAmount;
         return m_dBalance;
     }
 };