|
#include "stdafx.h"
#include <atlcurr.h>
#include <comutil.h>
/////////////////////////////////////////////////////////////////////////////
// COleCurrency class (internally currency is 8-byte int scaled by 10,000)
// This was taken from olevar.cpp in the atlmfc/src/mfc directory.
const COleCurrency COleCurrency::zero(0, 0);
COleCurrency::COleCurrency(long nUnits, long nFractionalUnits)
{
SetCurrency(nUnits, nFractionalUnits);
SetStatus(valid);
}
const COleCurrency& COleCurrency::operator=(CURRENCY cySrc)
{
m_cur = cySrc;
SetStatus(valid);
return *this;
}
const COleCurrency& COleCurrency::operator=(const COleCurrency& curSrc)
{
m_cur = curSrc.m_cur;
m_status = curSrc.m_status;
return *this;
}
const COleCurrency& COleCurrency::operator=(const VARIANT& varSrc)
{
if (varSrc.vt != VT_CY)
{
//try
{
_variant_t varTemp(varSrc);
varTemp.ChangeType(VT_CY);
m_cur = varTemp.cyVal;
SetStatus(valid);
}
// Catch COleException from ChangeType, but not CMemoryException
//catch (_com_error& e)
//{
// // Not able to convert VARIANT to CURRENCY
// m_cur.int64 = 0;
// SetStatus(invalid);
// DELETE_EXCEPTION(e);
//}
//END_CATCH
}
else
{
m_cur = varSrc.cyVal;
SetStatus(valid);
}
return *this;
}
BOOL COleCurrency::operator<(const COleCurrency& cur) const
{
ATLASSERT(GetStatus() == valid);
ATLASSERT(cur.GetStatus() == valid);
return (m_cur.int64 < cur.m_cur.int64);
}
BOOL COleCurrency::operator>(const COleCurrency& cur) const
{
ATLASSERT(GetStatus() == valid);
ATLASSERT(cur.GetStatus() == valid);
return (m_cur.int64 > cur.m_cur.int64);
}
BOOL COleCurrency::operator<=(const COleCurrency& cur) const
{
ATLASSERT(GetStatus() == valid);
ATLASSERT(cur.GetStatus() == valid);
return (m_cur.int64 <= cur.m_cur.int64);
}
BOOL COleCurrency::operator>=(const COleCurrency& cur) const
{
ATLASSERT(GetStatus() == valid);
ATLASSERT(cur.GetStatus() == valid);
return (m_cur.int64 >= cur.m_cur.int64);
}
COleCurrency COleCurrency::operator+(const COleCurrency& cur) const
{
COleCurrency curResult;
// If either operand Null, result Null
if (GetStatus() == null || cur.GetStatus() == null)
{
curResult.SetStatus(null);
return curResult;
}
// If either operand Invalid, result Invalid
if (GetStatus() == invalid || cur.GetStatus() == invalid)
{
curResult.SetStatus(invalid);
return curResult;
}
// Add separate CURRENCY components
curResult.m_cur.int64 = m_cur.int64+cur.m_cur.int64;
// Overflow if operands same sign and result sign different
if (!((m_cur.Hi ^ cur.m_cur.Hi) & 0x80000000) &&
((m_cur.Hi ^ curResult.m_cur.Hi) & 0x80000000))
{
curResult.SetStatus(invalid);
}
return curResult;
}
COleCurrency COleCurrency::operator-(const COleCurrency& cur) const
{
COleCurrency curResult;
// If either operand Null, result Null
if (GetStatus() == null || cur.GetStatus() == null)
{
curResult.SetStatus(null);
return curResult;
}
// If either operand Invalid, result Invalid
if (GetStatus() == invalid || cur.GetStatus() == invalid)
{
curResult.SetStatus(invalid);
return curResult;
}
// Subtract separate CURRENCY components
curResult.m_cur.int64 = m_cur.int64-cur.m_cur.int64;
// Overflow if operands not same sign and result not same sign
if (((m_cur.Hi ^ cur.m_cur.Hi) & 0x80000000) &&
((m_cur.Hi ^ curResult.m_cur.Hi) & 0x80000000))
{
curResult.SetStatus(invalid);
}
return curResult;
}
COleCurrency COleCurrency::operator-() const
{
// If operand not Valid, just return
if (!GetStatus() == valid)
return *this;
COleCurrency curResult;
// Negating MIN_CURRENCY,will set invalid
if (m_cur.int64 == _I64_MIN)
{
curResult.SetStatus(invalid);
}
curResult.m_cur.int64 = -m_cur.int64;
return curResult;
}
COleCurrency COleCurrency::operator*(long nOperand) const
{
// If operand not Valid, just return
if (GetStatus() != valid)
return *this;
COleCurrency curResult(m_cur);
// Return now if one operand is 0 (optimization)
if ((m_cur.int64 == 0) || (nOperand == 0))
{
curResult.m_cur.int64 = 0;
return curResult;
}
ULONGLONG nAbsCur; // |m_cur.int64|
ULONG nAbsOp; // |nOperand|
ULONGLONG nTempHi; // Product of nAbsOp and high-order 32 bits of nAbsCur
ULONGLONG nTempLo; // Product of nAbsOp and low-order 32 bits of nAbsCur
ULONGLONG nTempProduct; // Sum of both partial products
bool bProductNegative;
bool bOverflow;
if((nOperand^m_cur.Hi)&0x80000000)
{
bProductNegative = true;
}
else
{
bProductNegative = false;
}
bOverflow = false;
// Compute absolute values.
nAbsCur = (m_cur.int64 < 0) ? -m_cur.int64 : m_cur.int64;
nAbsOp = labs(nOperand);
// Compute the high-order partial product
nTempHi = (nAbsCur>>32)*nAbsOp;
if(nTempHi > (ULONGLONG(LONG_MAX)+1))
{
// High-order multiplication overflowed
bOverflow = true;
}
else
{
// Compute the low-order partial product. Since nAbsOp is no larger
// than 2**31, this multiplication can't overflow.
nTempLo = ULONGLONG(ULONG(nAbsCur))*nAbsOp;
// Sum the two partial products
nTempProduct = nTempLo+(nTempHi<<32);
if(nTempProduct < nTempLo)
{
// The sum overflowed the 64-bit result
bOverflow = true;
}
else
{
// At this point, nTempProduct may be still be out of range of a
// positive signed 64-bit integer, but we do know that we haven't
// overflowed out of our unsigned 64-bit integer variable.
// If nTempProduct is greater than _I64_MAX, it will appear to be
// a negative signed 64-bit integer, so our result will appear to
// have the wrong sign. The special case of nTempProduct ==
// -_I64_MIN works correctly, since negating that number is a NOP.
// That will
// Try to give the result the correct sign.
if(bProductNegative)
{
curResult.m_cur.int64 = -LONGLONG(nTempProduct);
// Possible cases:
// a) nTempProduct <= _I64_MAX: No problem.
// b) nTempProduct > -_I64_MIN: The result of the negation will
// be positive, which will fail our check for the correct
// sign (which we'll do below).
// c) nTempProduct == -I64_MIN: The result of the negation will
// be _I64_MIN, which is the correct result.
}
else
{
curResult.m_cur.int64 = nTempProduct;
// Possible cases:
// a) nTempProduct <= _I64_MAX: No problem.
// b) nTempProduct > _I64_MAX: The result of the signed result
// will be negative, which will fail our check for the
// correct sign (which we'll do below).
}
if((curResult.m_cur.Hi^m_cur.Hi^nOperand)&0x80000000)
{
// The sign of the result isn't what we wanted, so there must have
// been an overflow.
bOverflow = true;
}
}
}
if(bOverflow)
{
curResult.SetStatus(invalid);
if(bProductNegative)
{
curResult.m_cur.int64 = _I64_MIN;
}
else
{
curResult.m_cur.int64 = _I64_MAX;
}
}
return curResult;
}
COleCurrency COleCurrency::operator/(long nOperand) const
{
// If operand not Valid, just return
if (!GetStatus() == valid)
return *this;
COleCurrency curResult;
// Check for divide by 0
if (nOperand == 0)
{
curResult.SetStatus(invalid);
// Set to maximum negative value
curResult.m_cur.int64 = _I64_MIN;
return curResult;
}
// Check for MIN_CURRENCY/-1
if ((nOperand == -1) && (m_cur.int64 == _I64_MIN))
{
curResult.SetStatus(invalid);
curResult.m_cur.int64 = _I64_MAX;
return curResult;
}
curResult.m_cur.int64 = m_cur.int64/nOperand;
return curResult;
}
void COleCurrency::SetCurrency(long nUnits, long nFractionalUnits)
{
COleCurrency curUnits; // Initializes to 0
COleCurrency curFractionalUnits; // Initializes to 0
// Set temp currency value to Units (need to multiply by 10,000)
curUnits.m_cur.Lo = (DWORD)labs(nUnits);
curUnits = curUnits * 10000;
if (nUnits < 0)
curUnits = -curUnits;
curFractionalUnits.m_cur.Lo = (DWORD)labs(nFractionalUnits);
if (nFractionalUnits < 0)
curFractionalUnits = -curFractionalUnits;
// Now add together Units and FractionalUnits
*this = curUnits + curFractionalUnits;
SetStatus(valid);
}
BOOL COleCurrency::ParseCurrency(LPCTSTR lpszCurrency,
DWORD dwFlags, LCID lcid)
{
USES_CONVERSION;
CString strCurrency = lpszCurrency;
SCODE sc = VarCyFromStr((LPOLESTR)T2COLE(strCurrency), lcid, dwFlags, &m_cur);
if (FAILED(sc))
{
if (sc == DISP_E_TYPEMISMATCH)
{
// Can't convert string to CURRENCY, set 0 & invalid
m_cur.int64 = 0;
SetStatus(invalid);
return FALSE;
}
else if (sc == DISP_E_OVERFLOW)
{
// Can't convert string to CURRENCY, set max neg & invalid
m_cur.int64 = _I64_MIN;
SetStatus(invalid);
return FALSE;
}
//else
//{
// TRACE(traceOle, 0, "\nCOleCurrency VarCyFromStr call failed.\n\t");
// if (sc == E_OUTOFMEMORY)
// AfxThrowMemoryException();
// else
// AfxThrowOleException(sc);
//}
}
SetStatus(valid);
return TRUE;
}
CString COleCurrency::Format(DWORD dwFlags, LCID lcid) const
{
USES_CONVERSION;
CString strCur;
// If null, return empty string
if (GetStatus() == null)
{
return strCur;
}
// If invalid, return Currency resource string
if (GetStatus() == invalid)
{
return "Invalid Currency Value.";
}
_variant_t var;
// Don't need to trap error. Should not fail due to type mismatch
VarBstrFromCy(m_cur, lcid, dwFlags, &V_BSTR(&var));
var.vt = VT_BSTR;
return OLE2CT(V_BSTR(&var));
}
// This is a really quick and dirty formatter that converts the
// currency value to float, and then uses the mask in a common
// or garden sprintf.
CString COleCurrency::Format(LPCTSTR lpszMask) const
{
CString ret = "Invalid Currency Value.";
if (GetStatus() == valid)
{
char* buf = new char[strlen(lpszMask) + 30];
double dVal = (double)(m_cur.int64 % 10000);
dVal /= 10000.0;
dVal += m_cur.int64 / 10000;
sprintf(buf, lpszMask, dVal);
ret = buf;
delete[] buf;
}
return ret;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.