RESOLUTION
For any existing applications relying on the functionality of the
COleCurrency::operator/() function that shipped in
MFC42.DLL with
Visual C++ 4.2 or 5.0, you can copy the older
Mfc42.dll into the application's directory. By doing so, the older
Mfc42.dll is not used nor the newer one located in the windows system directory. If you are using Visual C++ 4.2 or 5.0 currently, you could link to MFC statically to prevent using any version of Mfc42.dll that may be on the target machines.
For newer applications being developed with Visual C++ 6.0, the best solution is to not call
COleCurrency::operator/(). You can work around the bug in Visual C++ 6.0 by writing a new class that subclasses
COleCurrency. To do so, add a new header file to your project called
MyOleCurrency.h and insert the following code into it:
#ifndef MYOLECURRENCY_H
#define MYOLECURRENCY_H
// Return the highest order bit composing dwTarget in wBit.
#define HI_BIT(dwTarget, wBit) do \
{ \
if (dwTarget != 0) \
for (wBit = 32; (dwTarget & (0x00000001 << (wBit-1))) == 0; wBit--) \
; \
else \
wBit = 0; \
} while (0)
// Left shift an (assumed unsigned) currency by wBits.
#define LSHIFT_UCUR(cur, wBits) do \
{ \
for (WORD wTempBits = wBits; wTempBits > 0; wTempBits--) \
{ \
cur.m_cur.Hi = ((DWORD)cur.m_cur.Hi << 1); \
cur.m_cur.Hi |= (cur.m_cur.Lo & 0x80000000) >> 31; \
cur.m_cur.Lo = cur.m_cur.Lo << 1; \
} \
} while (0)
// Right shift an (assumed unsigned) currency by wBits.
#define RSHIFT_UCUR(cur, wBits) do \
{ \
for (WORD wTempBits = wBits; wTempBits> 0; wTempBits--) \
{ \
cur.m_cur.Lo = cur.m_cur.Lo >> 1; \
cur.m_cur.Lo |= (cur.m_cur.Hi & 0x00000001) << 31; \
cur.m_cur.Hi = ((DWORD)cur.m_cur.Hi >> 1); \
} \
} while (0)
#define DELETE_EXCEPTION(e) do { e->Delete(); } while (0)
class CMyOleCurrency : public COleCurrency
{
public:
const COleCurrency& operator=(CURRENCY cySrc)
{
m_cur = cySrc;
SetStatus(valid);
return *this;
}
const COleCurrency& operator=(const COleCurrency& curSrc)
{
m_cur = curSrc.m_cur;
m_status = curSrc.m_status;
return *this;
}
const COleCurrency& operator=(const VARIANT& varSrc)
{
if (varSrc.vt != VT_CY)
{
TRY
{
COleVariant varTemp(varSrc);
varTemp.ChangeType(VT_CY);
m_cur = varTemp.cyVal;
SetStatus(valid);
}
// Catch COleException from ChangeType, but not CMemoryException
CATCH(COleException, e)
{
// Not able to convert VARIANT to CURRENCY
m_cur.Hi = 0;
m_cur.Lo = 0;
SetStatus(invalid);
DELETE_EXCEPTION(e);
}
END_CATCH
}
else
{
m_cur = varSrc.cyVal;
SetStatus(valid);
}
return *this;
}
COleCurrency CMyOleCurrency::operator/(long nOperand) const
{
// If operand not Valid, just return
if (!GetStatus() == valid)
return *this;
COleCurrency curTemp(m_cur);
DWORD nTempOp;
// Check for divide by 0b
if (nOperand == 0)
{
curTemp.SetStatus(invalid);
// Set to maximum negative value
curTemp.m_cur.Hi = 0x80000000;
curTemp.m_cur.Lo = 0x00000000;
return curTemp;
}
// Compute absolute values
if (curTemp.m_cur.Hi < 0)
curTemp = -curTemp;
nTempOp = labs(nOperand);
// Optimization - division is simple if Hi == 0
if (curTemp.m_cur.Hi == 0x0000)
{
//vc5 SP3 done this..., changed back to VC++ 5.0 SP3 behavior
curTemp.m_cur.Lo /= nTempOp;
//vc6 did this...
//curTemp.m_cur.Lo = m_cur.Lo / nTempOp;
// Compute result sign
if ((m_cur.Hi ^ nOperand) & 0x80000000)
curTemp = -curTemp;
return curTemp;
}
// Now curTemp represents remainder
COleCurrency curResult; // Initializes to zero
COleCurrency curTempResult;
COleCurrency curOperand;
curOperand.m_cur.Lo = nTempOp;
WORD wHiBitRem;
WORD wScaleOp;
// Quit if remainder can be truncated
while (curTemp >= curOperand)
{
// Scale up and divide Hi portion
HI_BIT(curTemp.m_cur.Hi, wHiBitRem);
if (wHiBitRem != 0)
wHiBitRem += 32;
else
HI_BIT(curTemp.m_cur.Lo, wHiBitRem);
WORD wShift = (WORD)(64 - wHiBitRem);
LSHIFT_UCUR(curTemp, wShift);
// If Operand bigger than Hi it must be scaled
wScaleOp = (WORD)((nTempOp > (DWORD)curTemp.m_cur.Hi) ? 1 : 0);
// Perform synthetic division
curTempResult.m_cur.Hi = (DWORD)curTemp.m_cur.Hi / (nTempOp >> wScaleOp);
// Scale back to get correct result and remainder
RSHIFT_UCUR(curTemp, wShift);
wShift = (WORD)(wShift - wScaleOp);
RSHIFT_UCUR(curTempResult, wShift);
// Now calculate result and remainder
curResult += curTempResult;
curTemp -= curTempResult * nTempOp;
}
// Compute result sign
if ((m_cur.Hi ^ nOperand) & 0x80000000)
curResult = -curResult;
return curResult;
}
};
#endif MYOLECURRENCY_H
Instead of using
COleCurrency in your code, use
CMyOleCurrency instead. Also, be sure to use
#include "MyOleCurrency.h" after
#include "stdafx.h" before using the
CMyOleCurrency class in any source files.