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;
}
};