home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLEVAR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-11  |  63.7 KB  |  2,806 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include <afxtempl.h>
  13. #include <math.h>
  14.  
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19.  
  20. /////////////////////////////////////////////////////////////////////////////
  21. // helpers
  22.  
  23. static void PASCAL CheckError(SCODE sc);
  24. static BOOL PASCAL CompareSafeArrays(SAFEARRAY* parray1, SAFEARRAY* parray2);
  25. static void PASCAL CreateOneDimArray(VARIANT& varSrc, DWORD dwSize);
  26. static void PASCAL CopyBinaryData(SAFEARRAY* parray,
  27.     const void* pSrc, DWORD dwSize);
  28.  
  29. /////////////////////////////////////////////////////////////////////////////
  30. // COleVariant class
  31.  
  32. COleVariant::COleVariant(const VARIANT& varSrc)
  33. {
  34.     AfxVariantInit(this);
  35.     CheckError(::VariantCopy(this, (LPVARIANT)&varSrc));
  36. }
  37.  
  38. COleVariant::COleVariant(LPCVARIANT pSrc)
  39. {
  40.     AfxVariantInit(this);
  41.     CheckError(::VariantCopy(this, (LPVARIANT)pSrc));
  42. }
  43.  
  44. COleVariant::COleVariant(const COleVariant& varSrc)
  45. {
  46.     AfxVariantInit(this);
  47.     CheckError(::VariantCopy(this, (LPVARIANT)&varSrc));
  48. }
  49.  
  50. COleVariant::COleVariant(LPCTSTR lpszSrc, VARTYPE vtSrc)
  51. {
  52.     USES_CONVERSION;
  53.     ASSERT(vtSrc == VT_BSTR || vtSrc == VT_BSTRT);
  54.     UNUSED(vtSrc);
  55.  
  56.     vt = VT_BSTR;
  57.     bstrVal = NULL;
  58.  
  59.     if (lpszSrc != NULL)
  60.     {
  61. #ifndef _UNICODE
  62.         if (vtSrc == VT_BSTRT)
  63.         {
  64.             int nLen = lstrlen(lpszSrc);
  65.             bstrVal = ::SysAllocStringByteLen(lpszSrc, nLen);
  66.         }
  67.         else
  68. #endif
  69.         {
  70.             bstrVal = ::SysAllocString(T2COLE(lpszSrc));
  71.         }
  72.  
  73.         if (bstrVal == NULL)
  74.             AfxThrowMemoryException();
  75.     }
  76. }
  77.  
  78.  
  79.  
  80. void COleVariant::SetString(LPCTSTR lpszSrc, VARTYPE vtSrc)
  81. {
  82.     USES_CONVERSION;
  83.     ASSERT(vtSrc == VT_BSTR || vtSrc == VT_BSTRT);
  84.     UNUSED(vtSrc);
  85.  
  86.     // Free up previous VARIANT
  87.     Clear();
  88.  
  89.     vt = VT_BSTR;
  90.     bstrVal = NULL;
  91.  
  92.     if (lpszSrc != NULL)
  93.     {
  94. #ifndef _UNICODE
  95.         if (vtSrc == VT_BSTRT)
  96.         {
  97.             int nLen = lstrlen(lpszSrc);
  98.             bstrVal = ::SysAllocStringByteLen(lpszSrc, nLen);
  99.         }
  100.         else
  101. #endif
  102.         {
  103.             bstrVal = ::SysAllocString(T2COLE(lpszSrc));
  104.         }
  105.  
  106.         if (bstrVal == NULL)
  107.             AfxThrowMemoryException();
  108.     }
  109. }
  110.  
  111. COleVariant::COleVariant(short nSrc, VARTYPE vtSrc)
  112. {
  113.     ASSERT(vtSrc == VT_I2 || vtSrc == VT_BOOL);
  114.  
  115.     if (vtSrc == VT_BOOL)
  116.     {
  117.         vt = VT_BOOL;
  118.         if (nSrc == FALSE)
  119.             V_BOOL(this) = AFX_OLE_FALSE;
  120.         else
  121.             V_BOOL(this) = AFX_OLE_TRUE;
  122.     }
  123.     else
  124.     {
  125.         vt = VT_I2;
  126.         iVal = nSrc;
  127.     }
  128. }
  129.  
  130. COleVariant::COleVariant(long lSrc, VARTYPE vtSrc)
  131. {
  132.     ASSERT(vtSrc == VT_I4 || vtSrc == VT_ERROR || vtSrc == VT_BOOL);
  133.  
  134.     if (vtSrc == VT_ERROR)
  135.     {
  136.         vt = VT_ERROR;
  137.         scode = lSrc;
  138.     }
  139.     else if (vtSrc == VT_BOOL)
  140.     {
  141.         vt = VT_BOOL;
  142.         if (lSrc == FALSE)
  143.             V_BOOL(this) = AFX_OLE_FALSE;
  144.         else
  145.             V_BOOL(this) = AFX_OLE_TRUE;
  146.     }
  147.     else
  148.     {
  149.         vt = VT_I4;
  150.         lVal = lSrc;
  151.     }
  152. }
  153.  
  154. // Operations
  155. void COleVariant::Clear()
  156. {
  157. #ifndef _UNICODE
  158.     if (vt == VT_BSTRT)
  159.         ::SysFreeString(bstrVal);
  160.     else
  161. #endif
  162.     {
  163.         VERIFY(::VariantClear(this) == NOERROR);
  164.     }
  165. }
  166.  
  167. void COleVariant::ChangeType(VARTYPE vartype, LPVARIANT pSrc)
  168. {
  169.     // If pSrc is NULL, convert type in place
  170.     if (pSrc == NULL)
  171.         pSrc = this;
  172.     if (pSrc != this || vartype != vt)
  173.         CheckError(::VariantChangeType(this, pSrc, 0, vartype));
  174. }
  175.  
  176. void COleVariant::Attach(VARIANT& varSrc)
  177. {
  178.     // Free up previous VARIANT
  179.     Clear();
  180.  
  181.     // give control of data to COleVariant
  182.     memcpy(this, &varSrc, sizeof(varSrc));
  183.     varSrc.vt = VT_EMPTY;
  184. }
  185.  
  186. VARIANT COleVariant::Detach()
  187. {
  188.     VARIANT varResult = *this;
  189.     vt = VT_EMPTY;
  190.     return varResult;
  191. }
  192.  
  193. // Literal comparison. Types and values must match.
  194. BOOL COleVariant::operator==(const VARIANT& var) const
  195. {
  196.     if (&var == this)
  197.         return TRUE;
  198.  
  199.     // Variants not equal if types don't match
  200.     if (var.vt != vt)
  201.         return FALSE;
  202.  
  203.     // Check type specific values
  204.     switch (vt)
  205.     {
  206.     case VT_EMPTY:
  207.     case VT_NULL:
  208.         return TRUE;
  209.  
  210.     case VT_BOOL:
  211.         return V_BOOL(&var) == V_BOOL(this);
  212.  
  213.     case VT_UI1:
  214.         return var.bVal == bVal;
  215.  
  216.     case VT_I2:
  217.         return var.iVal == iVal;
  218.  
  219.     case VT_I4:
  220.         return var.lVal == lVal;
  221.  
  222.     case VT_CY:
  223.         return (var.cyVal.Hi == cyVal.Hi && var.cyVal.Lo == cyVal.Lo);
  224.  
  225.     case VT_R4:
  226.         return var.fltVal == fltVal;
  227.  
  228.     case VT_R8:
  229.         return var.dblVal == dblVal;
  230.  
  231.     case VT_DATE:
  232.         return var.date == date;
  233.  
  234.     case VT_BSTR:
  235.         return SysStringByteLen(var.bstrVal) == SysStringByteLen(bstrVal) &&
  236.             memcmp(var.bstrVal, bstrVal, SysStringByteLen(bstrVal)) == 0;
  237.  
  238.     case VT_ERROR:
  239.         return var.scode == scode;
  240.  
  241.     case VT_DISPATCH:
  242.     case VT_UNKNOWN:
  243.         return var.punkVal == punkVal;
  244.  
  245.     default:
  246.         if (vt & VT_ARRAY && !(vt & VT_BYREF))
  247.             return CompareSafeArrays(var.parray, parray);
  248.         else
  249.             ASSERT(FALSE);  // VT_BYREF not supported
  250.         // fall through
  251.     }
  252.  
  253.     return FALSE;
  254. }
  255.  
  256. const COleVariant& COleVariant::operator=(const VARIANT& varSrc)
  257. {
  258.     CheckError(::VariantCopy(this, (LPVARIANT)&varSrc));
  259.     return *this;
  260. }
  261.  
  262. const COleVariant& COleVariant::operator=(LPCVARIANT pSrc)
  263. {
  264.     CheckError(::VariantCopy(this, (LPVARIANT)pSrc));
  265.     return *this;
  266. }
  267.  
  268. const COleVariant& COleVariant::operator=(const COleVariant& varSrc)
  269. {
  270.     CheckError(::VariantCopy(this, (LPVARIANT)&varSrc));
  271.     return *this;
  272. }
  273.  
  274. const COleVariant& COleVariant::operator=(const LPCTSTR lpszSrc)
  275. {
  276.     USES_CONVERSION;
  277.     // Free up previous VARIANT
  278.     Clear();
  279.  
  280.     vt = VT_BSTR;
  281.     if (lpszSrc == NULL)
  282.         bstrVal = NULL;
  283.     else
  284.     {
  285.         bstrVal = ::SysAllocString(T2COLE(lpszSrc));
  286.         if (bstrVal == NULL)
  287.             AfxThrowMemoryException();
  288.     }
  289.     return *this;
  290. }
  291.  
  292. const COleVariant& COleVariant::operator=(const CString& strSrc)
  293. {
  294.     USES_CONVERSION;
  295.     // Free up previous VARIANT
  296.     Clear();
  297.  
  298.     vt = VT_BSTR;
  299.     bstrVal = ::SysAllocString(T2COLE(strSrc));
  300.     if (bstrVal == NULL)
  301.         AfxThrowMemoryException();
  302.  
  303.     return *this;
  304. }
  305.  
  306. const COleVariant& COleVariant::operator=(BYTE nSrc)
  307. {
  308.     // Free up previous VARIANT if necessary
  309.     if (vt != VT_UI1)
  310.     {
  311.         Clear();
  312.         vt = VT_UI1;
  313.     }
  314.  
  315.     bVal = nSrc;
  316.     return *this;
  317. }
  318.  
  319. const COleVariant& COleVariant::operator=(short nSrc)
  320. {
  321.     if (vt == VT_I2)
  322.         iVal = nSrc;
  323.     else if (vt == VT_BOOL)
  324.     {
  325.         if (nSrc == FALSE)
  326.             V_BOOL(this) = AFX_OLE_FALSE;
  327.         else
  328.             V_BOOL(this) = AFX_OLE_TRUE;
  329.     }
  330.     else
  331.     {
  332.         // Free up previous VARIANT
  333.         Clear();
  334.         vt = VT_I2;
  335.         iVal = nSrc;
  336.     }
  337.  
  338.     return *this;
  339. }
  340.  
  341. const COleVariant& COleVariant::operator=(long lSrc)
  342. {
  343.     if (vt == VT_I4)
  344.         lVal = lSrc;
  345.     else if (vt == VT_ERROR)
  346.         scode = lSrc;
  347.     else if (vt == VT_BOOL)
  348.     {
  349.         if (lSrc == FALSE)
  350.             V_BOOL(this) = AFX_OLE_FALSE;
  351.         else
  352.             V_BOOL(this) = AFX_OLE_TRUE;
  353.     }
  354.     else
  355.     {
  356.         // Free up previous VARIANT
  357.         Clear();
  358.         vt = VT_I4;
  359.         lVal = lSrc;
  360.     }
  361.  
  362.     return *this;
  363. }
  364.  
  365. const COleVariant& COleVariant::operator=(const COleCurrency& curSrc)
  366. {
  367.     // Free up previous VARIANT if necessary
  368.     if (vt != VT_CY)
  369.     {
  370.         Clear();
  371.         vt = VT_CY;
  372.     }
  373.  
  374.     cyVal = curSrc.m_cur;
  375.     return *this;
  376. }
  377.  
  378. const COleVariant& COleVariant::operator=(float fltSrc)
  379. {
  380.     // Free up previous VARIANT if necessary
  381.     if (vt != VT_R4)
  382.     {
  383.         Clear();
  384.         vt = VT_R4;
  385.     }
  386.  
  387.     fltVal = fltSrc;
  388.     return *this;
  389. }
  390.  
  391. const COleVariant& COleVariant::operator=(double dblSrc)
  392. {
  393.     // Free up previous VARIANT if necessary
  394.     if (vt != VT_R8)
  395.     {
  396.         Clear();
  397.         vt = VT_R8;
  398.     }
  399.  
  400.     dblVal = dblSrc;
  401.     return *this;
  402. }
  403.  
  404. const COleVariant& COleVariant::operator=(const COleDateTime& dateSrc)
  405. {
  406.     // Free up previous VARIANT if necessary
  407.     if (vt != VT_DATE)
  408.     {
  409.         Clear();
  410.         vt = VT_DATE;
  411.     }
  412.  
  413.     date = dateSrc.m_dt;
  414.     return *this;
  415. }
  416.  
  417. const COleVariant& COleVariant::operator=(const CByteArray& arrSrc)
  418. {
  419.     int nSize = arrSrc.GetSize();
  420.  
  421.     // Set the correct type and make sure SafeArray can hold data
  422.     CreateOneDimArray(*this, (DWORD)nSize);
  423.  
  424.     // Copy the data into the SafeArray
  425.     CopyBinaryData(parray, arrSrc.GetData(), (DWORD)nSize);
  426.  
  427.     return *this;
  428. }
  429.  
  430. const COleVariant& COleVariant::operator=(const CLongBinary& lbSrc)
  431. {
  432.     // Set the correct type and make sure SafeArray can hold data
  433.     CreateOneDimArray(*this, lbSrc.m_dwDataLength);
  434.  
  435.     // Copy the data into the SafeArray
  436.     BYTE* pData = (BYTE*)::GlobalLock(lbSrc.m_hData);
  437.     CopyBinaryData(parray, pData, lbSrc.m_dwDataLength);
  438.     ::GlobalUnlock(lbSrc.m_hData);
  439.  
  440.     return *this;
  441. }
  442.  
  443. void AFXAPI AfxVariantInit(LPVARIANT pVar)
  444. {
  445.     memset(pVar, 0, sizeof(*pVar));
  446. }
  447.  
  448. /////////////////////////////////////////////////////////////////////////////
  449. // Diagnostics
  450.  
  451. #ifdef _DEBUG
  452. CDumpContext& AFXAPI operator <<(CDumpContext& dc, COleVariant varSrc)
  453. {
  454.     LPCVARIANT pSrc = (LPCVARIANT)varSrc;
  455.  
  456.     dc << "\nCOleVariant Object:";
  457.     dc << "\n\t vt = " << pSrc->vt;
  458.  
  459.     // No support for VT_BYREF & VT_ARRAY
  460.     if (pSrc->vt & VT_BYREF || pSrc->vt & VT_ARRAY)
  461.         return dc;
  462.  
  463.     switch (pSrc->vt)
  464.     {
  465.     case VT_BOOL:
  466.         return dc << "\n\t VT_BOOL = " << V_BOOL(pSrc);
  467.  
  468.     case VT_UI1:
  469.         return dc << "\n\t bVal = " << pSrc->bVal;
  470.  
  471.     case VT_I2:
  472.         return dc << "\n\t iVal = " << pSrc->iVal;
  473.  
  474.     case VT_I4:
  475.         return dc << "\n\t lVal = " << pSrc->lVal;
  476.  
  477.     case VT_CY:
  478.         {
  479.             COleVariant var(varSrc);
  480.             var.ChangeType(VT_BSTR);
  481.             return dc << "\n\t cyVal = " << (LPCTSTR)var.bstrVal;
  482.         }
  483.  
  484.     case VT_R4:
  485.         return dc << "\n\t fltVal = " << pSrc->fltVal;
  486.  
  487.     case VT_R8:
  488.         return dc << "\n\t dblVal = " << pSrc->dblVal;
  489.  
  490.     case VT_DATE:
  491.         {
  492.             COleVariant var(varSrc);
  493.             var.ChangeType(VT_BSTR);
  494.             return dc << "\n\t date = " << (LPCTSTR)var.bstrVal;
  495.         }
  496.  
  497.     case VT_BSTR:
  498.         return dc << "\n\t bstrVal = " << (LPCTSTR)pSrc->bstrVal;
  499.  
  500.     case VT_ERROR:
  501.         return dc << "\n\t scode = " << pSrc->scode;
  502.  
  503.     case VT_DISPATCH:
  504.     case VT_UNKNOWN:
  505.         return dc << "\n\t punkVal = " << pSrc->punkVal;
  506.  
  507.     case VT_EMPTY:
  508.     case VT_NULL:
  509.         return dc;
  510.  
  511.     default:
  512.         ASSERT(FALSE);
  513.         return dc;
  514.     }
  515. }
  516. #endif // _DEBUG
  517.  
  518. CArchive& AFXAPI operator<<(CArchive& ar, COleVariant varSrc)
  519. {
  520.     LPCVARIANT pSrc = (LPCVARIANT)varSrc;
  521.  
  522.     ar << pSrc->vt;
  523.  
  524.     // No support for VT_BYREF & VT_ARRAY
  525.     if (pSrc->vt & VT_BYREF || pSrc->vt & VT_ARRAY)
  526.         return ar;
  527.  
  528.     switch (pSrc->vt)
  529.     {
  530.     case VT_BOOL:
  531.         return ar << (WORD)V_BOOL(pSrc);
  532.  
  533.     case VT_UI1:
  534.         return ar << pSrc->bVal;
  535.  
  536.     case VT_I2:
  537.         return ar << (WORD)pSrc->iVal;
  538.  
  539.     case VT_I4:
  540.         return ar << pSrc->lVal;
  541.  
  542.     case VT_CY:
  543.         ar << pSrc->cyVal.Lo;
  544.         return ar << pSrc->cyVal.Hi;
  545.  
  546.     case VT_R4:
  547.         return ar << pSrc->fltVal;
  548.  
  549.     case VT_R8:
  550.         return ar << pSrc->dblVal;
  551.  
  552.     case VT_DATE:
  553.         return ar << pSrc->date;
  554.  
  555.     case VT_BSTR:
  556.         {
  557.             DWORD nLen = SysStringByteLen(pSrc->bstrVal);
  558.             ar << nLen;
  559.             if (nLen > 0)
  560.                 ar.Write(pSrc->bstrVal, nLen * sizeof(BYTE));
  561.  
  562.             return ar;
  563.         }
  564.  
  565.     case VT_ERROR:
  566.         return ar << pSrc->scode;
  567.  
  568.     case VT_DISPATCH:
  569.     case VT_UNKNOWN:
  570.         {
  571.             LPPERSISTSTREAM pPersistStream;
  572.             CArchiveStream stm(&ar);
  573.  
  574.             // QI for IPersistStream or IPeristStreamInit
  575.             SCODE sc = pSrc->punkVal->QueryInterface(
  576.                 IID_IPersistStream, (void**)&pPersistStream);
  577. #ifndef _AFX_NO_OCC_SUPPORT
  578.             if (FAILED(sc))
  579.                 sc = pSrc->punkVal->QueryInterface(
  580.                     IID_IPersistStreamInit, (void**)&pPersistStream);
  581. #endif
  582.             CheckError(sc);
  583.  
  584.             TRY
  585.             {
  586.                 // Get and archive the CLSID (GUID)
  587.                 CLSID clsid;
  588.                 CheckError(pPersistStream->GetClassID(&clsid));
  589.                 ar << clsid.Data1;
  590.                 ar << clsid.Data2;
  591.                 ar << clsid.Data3;
  592.                 ar.Write(&clsid.Data4[0], sizeof clsid.Data4);
  593.  
  594.                 // Always assume object is dirty
  595.                 CheckError(pPersistStream->Save(&stm, TRUE));
  596.             }
  597.             CATCH_ALL(e)
  598.             {
  599.                 pPersistStream->Release();
  600.                 THROW_LAST();
  601.             }
  602.             END_CATCH_ALL
  603.             pPersistStream->Release();
  604.         }
  605.         return ar;
  606.  
  607.     case VT_EMPTY:
  608.     case VT_NULL:
  609.         // do nothing
  610.         return ar;
  611.  
  612.     default:
  613.         ASSERT(FALSE);
  614.         return ar;
  615.     }
  616. }
  617.  
  618. CArchive& AFXAPI operator>>(CArchive& ar, COleVariant& varSrc)
  619. {
  620.     LPVARIANT pSrc = &varSrc;
  621.  
  622.     // Free up current data if necessary
  623.     if (pSrc->vt != VT_EMPTY)
  624.         VariantClear(pSrc);
  625.     ar >> pSrc->vt;
  626.  
  627.     // No support for VT_BYREF & VT_ARRAY
  628.     if (pSrc->vt & VT_BYREF || pSrc->vt & VT_ARRAY)
  629.         return ar;
  630.  
  631.     switch (pSrc->vt)
  632.     {
  633.     case VT_BOOL:
  634.         return ar >> (WORD&)V_BOOL(pSrc);
  635.  
  636.     case VT_UI1:
  637.         return ar >> pSrc->bVal;
  638.  
  639.     case VT_I2:
  640.         return ar >> (WORD&)pSrc->iVal;
  641.  
  642.     case VT_I4:
  643.         return ar >> pSrc->lVal;
  644.  
  645.     case VT_CY:
  646.         ar >> pSrc->cyVal.Lo;
  647.         return ar >> pSrc->cyVal.Hi;
  648.  
  649.     case VT_R4:
  650.         return ar >> pSrc->fltVal;
  651.  
  652.     case VT_R8:
  653.         return ar >> pSrc->dblVal;
  654.  
  655.     case VT_DATE:
  656.         return ar >> pSrc->date;
  657.  
  658.     case VT_BSTR:
  659.         {
  660.             DWORD nLen;
  661.             ar >> nLen;
  662.             if (nLen > 0)
  663.             {
  664.                 pSrc->bstrVal = SysAllocStringByteLen(NULL, nLen);
  665.                 if (pSrc->bstrVal == NULL)
  666.                     AfxThrowMemoryException();
  667.                 ar.Read(pSrc->bstrVal, nLen * sizeof(BYTE));
  668.             }
  669.             else
  670.                 pSrc->bstrVal = NULL;
  671.  
  672.             return ar;
  673.         }
  674.         break;
  675.  
  676.     case VT_ERROR:
  677.         return ar >> pSrc->scode;
  678.  
  679.     case VT_DISPATCH:
  680.     case VT_UNKNOWN:
  681.         {
  682.             LPPERSISTSTREAM pPersistStream = NULL;
  683.             CArchiveStream stm(&ar);
  684.  
  685.             // Retrieve the CLSID (GUID) and create an instance
  686.             CLSID clsid;
  687.             ar >> clsid.Data1;
  688.             ar >> clsid.Data2;
  689.             ar >> clsid.Data3;
  690.             ar.Read(&clsid.Data4[0], sizeof clsid.Data4);
  691.  
  692.             // Create the object
  693.             SCODE sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL | CLSCTX_REMOTE_SERVER,
  694.                 pSrc->vt == VT_UNKNOWN ? IID_IUnknown : IID_IDispatch,
  695.                 (void**)&pSrc->punkVal);
  696.             if (sc == E_INVALIDARG)
  697.             {
  698.                 // may not support CLSCTX_REMOTE_SERVER, so try without
  699.                 sc = CoCreateInstance(clsid, NULL,
  700.                     CLSCTX_ALL & ~CLSCTX_REMOTE_SERVER,
  701.                     pSrc->vt == VT_UNKNOWN ? IID_IUnknown : IID_IDispatch,
  702.                     (void**)&pSrc->punkVal);
  703.             }
  704.             CheckError(sc);
  705.  
  706.             TRY
  707.             {
  708.                 // QI for IPersistStream or IPeristStreamInit
  709.                 sc = pSrc->punkVal->QueryInterface(
  710.                     IID_IPersistStream, (void**)&pPersistStream);
  711. #ifndef _AFX_NO_OCC_SUPPORT
  712.                 if (FAILED(sc))
  713.                     sc = pSrc->punkVal->QueryInterface(
  714.                         IID_IPersistStreamInit, (void**)&pPersistStream);
  715. #endif
  716.                 CheckError(sc);
  717.  
  718.                 // Always assumes object is dirty
  719.                 CheckError(pPersistStream->Load(&stm));
  720.             }
  721.             CATCH_ALL(e)
  722.             {
  723.                 // Clean up
  724.                 if (pPersistStream != NULL)
  725.                     pPersistStream->Release();
  726.  
  727.                 pSrc->punkVal->Release();
  728.                 THROW_LAST();
  729.             }
  730.             END_CATCH_ALL
  731.  
  732.             pPersistStream->Release();
  733.         }
  734.         return ar;
  735.  
  736.     case VT_EMPTY:
  737.     case VT_NULL:
  738.         // do nothing
  739.         return ar;
  740.  
  741.     default:
  742.         ASSERT(FALSE);
  743.         return ar;
  744.     }
  745. }
  746.  
  747. /////////////////////////////////////////////////////////////////////////////
  748. // COleVariant Helpers
  749.  
  750. #if _MSC_VER >= 1100
  751. template <> void AFXAPI ConstructElements<COleVariant> (COleVariant* pElements, int nCount)
  752. #else
  753. void AFXAPI ConstructElements(COleVariant* pElements, int nCount)
  754. #endif
  755. {
  756.     ASSERT(nCount == 0 ||
  757.         AfxIsValidAddress(pElements, nCount * sizeof(COleVariant)));
  758.  
  759.     for (; nCount--; ++pElements)
  760.         new(pElements) COleVariant;
  761. }
  762.  
  763. #if _MSC_VER >= 1100
  764. template <> void AFXAPI DestructElements<COleVariant> (COleVariant* pElements, int nCount)
  765. #else
  766. void AFXAPI DestructElements(COleVariant* pElements, int nCount)
  767. #endif
  768. {
  769.     ASSERT(nCount == 0 ||
  770.         AfxIsValidAddress(pElements, nCount * sizeof(COleVariant)));
  771.  
  772.     for (; nCount--; ++pElements)
  773.         pElements->~COleVariant();
  774. }
  775.  
  776. #if _MSC_VER >= 1100
  777. template <> void AFXAPI CopyElements<COleVariant> (COleVariant* pDest, const COleVariant* pSrc, int nCount)
  778. #else
  779. void AFXAPI CopyElements(COleVariant* pDest, const COleVariant* pSrc, int nCount)
  780. #endif
  781. {
  782.     ASSERT(nCount == 0 ||
  783.         AfxIsValidAddress(pDest, nCount * sizeof(COleVariant)));
  784.     ASSERT(nCount == 0 ||
  785.         AfxIsValidAddress(pSrc, nCount * sizeof(COleVariant)));
  786.  
  787.     for (; nCount--; ++pDest, ++pSrc)
  788.         *pDest = *pSrc;
  789. }
  790.  
  791. #if _MSC_VER >= 1100
  792. template <> void AFXAPI SerializeElements<COleVariant> (CArchive& ar, COleVariant* pElements, int nCount)
  793. #else
  794. void AFXAPI SerializeElements(CArchive& ar, COleVariant* pElements, int nCount)
  795. #endif
  796. {
  797.     ASSERT(nCount == 0 ||
  798.         AfxIsValidAddress(pElements, nCount * sizeof(COleVariant)));
  799.  
  800.     if (ar.IsStoring())
  801.     {
  802.         for (; nCount--; ++pElements)
  803.             ar << *pElements;
  804.     }
  805.     else
  806.     {
  807.         for (; nCount--; ++pElements)
  808.             ar >> *pElements;
  809.     }
  810. }
  811.  
  812. #ifdef _DEBUG
  813. #if _MSC_VER >= 1100
  814. template <> void AFXAPI DumpElements<COleVariant> (CDumpContext& dc, const COleVariant* pElements, int nCount)
  815. #else
  816. void AFXAPI DumpElements(CDumpContext& dc, const COleVariant* pElements, int nCount)
  817. #endif
  818. {
  819.     for (; nCount--; ++pElements)
  820.         dc << *pElements;
  821. }
  822. #endif // _DEBUG
  823.  
  824. #if _MSC_VER >= 1100
  825. template<> UINT AFXAPI HashKey<const struct tagVARIANT&> (const struct tagVARIANT& var)
  826. #else
  827. UINT AFXAPI HashKey(const struct tagVARIANT& var)
  828. #endif
  829. {
  830.     switch (var.vt)
  831.     {
  832.     case VT_EMPTY:
  833.     case VT_NULL:
  834.         return 0;
  835.     case VT_I2:
  836. #if _MSC_VER >= 1100
  837.         return HashKey<DWORD>((DWORD)var.iVal);
  838. #else
  839.         return HashKey((DWORD)var.iVal);
  840. #endif
  841.     case VT_I4:
  842. #if _MSC_VER >= 1100
  843.         return HashKey<DWORD>((DWORD)var.lVal);
  844. #else
  845.         return HashKey((DWORD)var.lVal);
  846. #endif
  847.     case VT_R4:
  848.         return (UINT)(var.fltVal / 16);
  849.     case VT_R8:
  850.     case VT_CY:
  851.         return (UINT)(var.dblVal / 16);
  852.     case VT_BOOL:
  853. #if _MSC_VER >= 1100
  854.         return HashKey<DWORD>((DWORD)V_BOOL(&var));
  855. #else
  856.         return HashKey((DWORD)V_BOOL(&var));
  857. #endif
  858.     case VT_ERROR:
  859. #if _MSC_VER >= 1100
  860.         return HashKey<DWORD>((DWORD)var.scode);
  861. #else
  862.         return HashKey((DWORD)var.scode);
  863. #endif
  864.     case VT_DATE:
  865.         return (UINT)(var.date / 16);
  866.     case VT_BSTR:
  867. #if _MSC_VER >= 1100
  868.         return HashKey<LPCOLESTR>(var.bstrVal);
  869. #else
  870.         return HashKey((LPCOLESTR)var.bstrVal);
  871. #endif
  872.     case VT_DISPATCH:
  873.     case VT_UNKNOWN:
  874. #if _MSC_VER >= 1100
  875.         return HashKey<DWORD>((DWORD)var.punkVal);
  876. #else
  877.         return HashKey((DWORD)var.punkVal);
  878. #endif
  879.  
  880.     default:
  881.         // No support for VT_BYREF, VT_ARRAY, VT_VARIANT, VT_DECIMAL, & VT_UI1
  882.         ASSERT(FALSE);
  883.  
  884.         // Fall through
  885.     }
  886.  
  887.     return 0;
  888. }
  889.  
  890. static void PASCAL CheckError(SCODE sc)
  891. {
  892.     if (FAILED(sc))
  893.     {
  894.         if (sc == E_OUTOFMEMORY)
  895.             AfxThrowMemoryException();
  896.         else
  897.             AfxThrowOleException(sc);
  898.     }
  899. }
  900.  
  901. static BOOL PASCAL CompareSafeArrays(SAFEARRAY* parray1, SAFEARRAY* parray2)
  902. {
  903.     BOOL bCompare = FALSE;
  904.  
  905.     // If one is NULL they must both be NULL to compare
  906.     if (parray1 == NULL || parray2 == NULL)
  907.     {
  908.         return parray1 == parray2;
  909.     }
  910.  
  911.     // Dimension must match and if 0, then arrays compare
  912.     DWORD dwDim1 = ::SafeArrayGetDim(parray1);
  913.     DWORD dwDim2 = ::SafeArrayGetDim(parray2);
  914.     if (dwDim1 != dwDim2)
  915.         return FALSE;
  916.     else if (dwDim1 == 0)
  917.         return TRUE;
  918.  
  919.     // Element size must match
  920.     DWORD dwSize1 = ::SafeArrayGetElemsize(parray1);
  921.     DWORD dwSize2 = ::SafeArrayGetElemsize(parray2);
  922.     if (dwSize1 != dwSize2)
  923.         return FALSE;
  924.  
  925.     long* pLBound1 = NULL;
  926.     long* pLBound2 = NULL;
  927.     long* pUBound1 = NULL;
  928.     long* pUBound2 = NULL;
  929.  
  930.     void* pData1 = NULL;
  931.     void* pData2 = NULL;
  932.  
  933.     TRY
  934.     {
  935.         // Bounds must match
  936.         pLBound1 = new long[dwDim1];
  937.         pLBound2 = new long[dwDim2];
  938.         pUBound1 = new long[dwDim1];
  939.         pUBound2 = new long[dwDim2];
  940.  
  941.         size_t nTotalElements = 1;
  942.  
  943.         // Get and compare bounds
  944.         for (DWORD dwIndex = 0; dwIndex < dwDim1; dwIndex++)
  945.         {
  946.             CheckError(::SafeArrayGetLBound(
  947.                 parray1, dwIndex+1, &pLBound1[dwIndex]));
  948.             CheckError(::SafeArrayGetLBound(
  949.                 parray2, dwIndex+1, &pLBound2[dwIndex]));
  950.             CheckError(::SafeArrayGetUBound(
  951.                 parray1, dwIndex+1, &pUBound1[dwIndex]));
  952.             CheckError(::SafeArrayGetUBound(
  953.                 parray2, dwIndex+1, &pUBound2[dwIndex]));
  954.  
  955.             // Check the magnitude of each bound
  956.             if (pUBound1[dwIndex] - pLBound1[dwIndex] !=
  957.                 pUBound2[dwIndex] - pLBound2[dwIndex])
  958.             {
  959.                 delete[] pLBound1;
  960.                 delete[] pLBound2;
  961.                 delete[] pUBound1;
  962.                 delete[] pUBound2;
  963.  
  964.                 return FALSE;
  965.             }
  966.  
  967.             // Increment the element count
  968.             nTotalElements *= pUBound1[dwIndex] - pLBound1[dwIndex] + 1;
  969.         }
  970.  
  971.         // Access the data
  972.         CheckError(::SafeArrayAccessData(parray1, &pData1));
  973.         CheckError(::SafeArrayAccessData(parray2, &pData2));
  974.  
  975.         // Calculate the number of bytes of data and compare
  976.         size_t nSize = nTotalElements * dwSize1;
  977.         int nOffset = memcmp(pData1, pData2, nSize);
  978.         bCompare = nOffset == 0;
  979.  
  980.         // Release the array locks
  981.         CheckError(::SafeArrayUnaccessData(parray1));
  982.         CheckError(::SafeArrayUnaccessData(parray2));
  983.     }
  984.     CATCH_ALL(e)
  985.     {
  986.         // Clean up bounds arrays
  987.         delete[] pLBound1;
  988.         delete[] pLBound2;
  989.         delete[] pUBound1;
  990.         delete[] pUBound2;
  991.  
  992.         // Release the array locks
  993.         if (pData1 != NULL)
  994.             CheckError(::SafeArrayUnaccessData(parray1));
  995.         if (pData2 != NULL)
  996.             CheckError(::SafeArrayUnaccessData(parray2));
  997.  
  998.         THROW_LAST();
  999.     }
  1000.     END_CATCH_ALL
  1001.  
  1002.     // Clean up bounds arrays
  1003.     delete[] pLBound1;
  1004.     delete[] pLBound2;
  1005.     delete[] pUBound1;
  1006.     delete[] pUBound2;
  1007.  
  1008.     return bCompare;
  1009. }
  1010.  
  1011. static void PASCAL CreateOneDimArray(VARIANT& varSrc, DWORD dwSize)
  1012. {
  1013.     UINT nDim;
  1014.  
  1015.     // Clear VARIANT and re-create SafeArray if necessary
  1016.     if (varSrc.vt != (VT_UI1 | VT_ARRAY) ||
  1017.         (nDim = ::SafeArrayGetDim(varSrc.parray)) != 1)
  1018.     {
  1019.         VERIFY(::VariantClear(&varSrc) == NOERROR);
  1020.         varSrc.vt = VT_UI1 | VT_ARRAY;
  1021.  
  1022.         SAFEARRAYBOUND bound;
  1023.         bound.cElements = dwSize;
  1024.         bound.lLbound = 0;
  1025.         varSrc.parray = ::SafeArrayCreate(VT_UI1, 1, &bound);
  1026.         if (varSrc.parray == NULL)
  1027.             AfxThrowMemoryException();
  1028.     }
  1029.     else
  1030.     {
  1031.         // Must redimension array if necessary
  1032.         long lLower, lUpper;
  1033.         CheckError(::SafeArrayGetLBound(varSrc.parray, 1, &lLower));
  1034.         CheckError(::SafeArrayGetUBound(varSrc.parray, 1, &lUpper));
  1035.  
  1036.         // Upper bound should always be greater than lower bound
  1037.         long lSize = lUpper - lLower;
  1038.         if (lSize < 0)
  1039.         {
  1040.             ASSERT(FALSE);
  1041.             lSize = 0;
  1042.  
  1043.         }
  1044.  
  1045.         if ((DWORD)lSize != dwSize)
  1046.         {
  1047.             SAFEARRAYBOUND bound;
  1048.             bound.cElements = dwSize;
  1049.             bound.lLbound = lLower;
  1050.             CheckError(::SafeArrayRedim(varSrc.parray, &bound));
  1051.         }
  1052.     }
  1053. }
  1054.  
  1055. static void PASCAL CopyBinaryData(SAFEARRAY* parray, const void* pvSrc, DWORD dwSize)
  1056. {
  1057.     // Access the data, copy it and unaccess it.
  1058.     void* pDest;
  1059.     CheckError(::SafeArrayAccessData(parray, &pDest));
  1060.     memcpy(pDest, pvSrc, dwSize);
  1061.     CheckError(::SafeArrayUnaccessData(parray));
  1062. }
  1063.  
  1064. /////////////////////////////////////////////////////////////////////////////
  1065. // COleCurrency class helpers
  1066.  
  1067. // Return the highest order bit composing dwTarget in wBit
  1068. #define HI_BIT(dwTarget, wBit) \
  1069.     do \
  1070.     { \
  1071.         if (dwTarget != 0) \
  1072.             for (wBit = 32; (dwTarget & (0x00000001 << wBit-1)) == 0; wBit--);\
  1073.         else \
  1074.             wBit = 0; \
  1075.     } while (0)
  1076.  
  1077. // Left shift an (assumed unsigned) currency by wBits
  1078. #define LSHIFT_UCUR(cur, wBits) \
  1079.     do \
  1080.     { \
  1081.         for (WORD wTempBits = wBits; wTempBits > 0; wTempBits--) \
  1082.         { \
  1083.             cur.m_cur.Hi = ((DWORD)cur.m_cur.Hi << 1); \
  1084.             cur.m_cur.Hi |= (cur.m_cur.Lo & 0x80000000) >> 31; \
  1085.             cur.m_cur.Lo = cur.m_cur.Lo << 1; \
  1086.         } \
  1087.     } while (0)
  1088.  
  1089. // Right shift an (assumed unsigned) currency by wBits
  1090. #define RSHIFT_UCUR(cur, wBits) \
  1091.     do \
  1092.     { \
  1093.         for (WORD wTempBits = wBits; wTempBits > 0; wTempBits--) \
  1094.         { \
  1095.             cur.m_cur.Lo = cur.m_cur.Lo >> 1; \
  1096.             cur.m_cur.Lo |= (cur.m_cur.Hi & 0x00000001) << 31; \
  1097.             cur.m_cur.Hi = ((DWORD)cur.m_cur.Hi >> 1); \
  1098.         } \
  1099.     } while (0)
  1100.  
  1101. /////////////////////////////////////////////////////////////////////////////
  1102. // COleCurrency class (internally currency is 8-byte int scaled by 10,000)
  1103.  
  1104. COleCurrency::COleCurrency(long nUnits, long nFractionalUnits)
  1105. {
  1106.     SetCurrency(nUnits, nFractionalUnits);
  1107.     SetStatus(valid);
  1108. }
  1109.  
  1110. const COleCurrency& COleCurrency::operator=(CURRENCY cySrc)
  1111. {
  1112.     m_cur = cySrc;
  1113.     SetStatus(valid);
  1114.     return *this;
  1115. }
  1116.  
  1117. const COleCurrency& COleCurrency::operator=(const COleCurrency& curSrc)
  1118. {
  1119.     m_cur = curSrc.m_cur;
  1120.     m_status = curSrc.m_status;
  1121.     return *this;
  1122. }
  1123.  
  1124. const COleCurrency& COleCurrency::operator=(const VARIANT& varSrc)
  1125. {
  1126.     if (varSrc.vt != VT_CY)
  1127.     {
  1128.         TRY
  1129.         {
  1130.             COleVariant varTemp(varSrc);
  1131.             varTemp.ChangeType(VT_CY);
  1132.             m_cur = varTemp.cyVal;
  1133.             SetStatus(valid);
  1134.         }
  1135.         // Catch COleException from ChangeType, but not CMemoryException
  1136.         CATCH(COleException, e)
  1137.         {
  1138.             // Not able to convert VARIANT to CURRENCY
  1139.             m_cur.Hi = 0;
  1140.             m_cur.Lo = 0;
  1141.             SetStatus(invalid);
  1142.             DELETE_EXCEPTION(e);
  1143.         }
  1144.         END_CATCH
  1145.     }
  1146.     else
  1147.     {
  1148.         m_cur = varSrc.cyVal;
  1149.         SetStatus(valid);
  1150.     }
  1151.  
  1152.     return *this;
  1153. }
  1154.  
  1155. BOOL COleCurrency::operator<(const COleCurrency& cur) const
  1156. {
  1157.     ASSERT(GetStatus() == valid);
  1158.     ASSERT(cur.GetStatus() == valid);
  1159.  
  1160.     return((m_cur.Hi == cur.m_cur.Hi) ?
  1161.         (m_cur.Lo < cur.m_cur.Lo) : (m_cur.Hi < cur.m_cur.Hi));
  1162. }
  1163.  
  1164. BOOL COleCurrency::operator>(const COleCurrency& cur) const
  1165. {
  1166.     ASSERT(GetStatus() == valid);
  1167.     ASSERT(cur.GetStatus() == valid);
  1168.  
  1169.     return((m_cur.Hi == cur.m_cur.Hi) ?
  1170.         (m_cur.Lo > cur.m_cur.Lo) : (m_cur.Hi > cur.m_cur.Hi));
  1171. }
  1172.  
  1173. BOOL COleCurrency::operator<=(const COleCurrency& cur) const
  1174. {
  1175.     ASSERT(GetStatus() == valid);
  1176.     ASSERT(cur.GetStatus() == valid);
  1177.  
  1178.     return((m_cur.Hi == cur.m_cur.Hi) ?
  1179.         (m_cur.Lo <= cur.m_cur.Lo) : (m_cur.Hi < cur.m_cur.Hi));
  1180. }
  1181.  
  1182. BOOL COleCurrency::operator>=(const COleCurrency& cur) const
  1183. {
  1184.     ASSERT(GetStatus() == valid);
  1185.     ASSERT(cur.GetStatus() == valid);
  1186.  
  1187.     return((m_cur.Hi == cur.m_cur.Hi) ?
  1188.         (m_cur.Lo >= cur.m_cur.Lo) : (m_cur.Hi > cur.m_cur.Hi));
  1189. }
  1190.  
  1191. COleCurrency COleCurrency::operator+(const COleCurrency& cur) const
  1192. {
  1193.     COleCurrency curResult;
  1194.  
  1195.     // If either operand Null, result Null
  1196.     if (GetStatus() == null || cur.GetStatus() == null)
  1197.     {
  1198.         curResult.SetStatus(null);
  1199.         return curResult;
  1200.     }
  1201.  
  1202.     // If either operand Invalid, result Invalid
  1203.     if (GetStatus() == invalid || cur.GetStatus() == invalid)
  1204.     {
  1205.         curResult.SetStatus(invalid);
  1206.         return curResult;
  1207.     }
  1208.  
  1209.     // Add separate CURRENCY components
  1210.     curResult.m_cur.Hi = m_cur.Hi + cur.m_cur.Hi;
  1211.     curResult.m_cur.Lo = m_cur.Lo + cur.m_cur.Lo;
  1212.  
  1213.     // Increment Hi if Lo overflows
  1214.     if (m_cur.Lo > curResult.m_cur.Lo)
  1215.         curResult.m_cur.Hi++;
  1216.  
  1217.     // Overflow if operands same sign and result sign different
  1218.     if (!((m_cur.Hi ^ cur.m_cur.Hi) & 0x80000000) &&
  1219.         ((m_cur.Hi ^ curResult.m_cur.Hi) & 0x80000000))
  1220.     {
  1221.         curResult.SetStatus(invalid);
  1222.     }
  1223.  
  1224.     return curResult;
  1225. }
  1226.  
  1227. COleCurrency COleCurrency::operator-(const COleCurrency& cur) const
  1228. {
  1229.     COleCurrency curResult;
  1230.  
  1231.     // If either operand Null, result Null
  1232.     if (GetStatus() == null || cur.GetStatus() == null)
  1233.     {
  1234.         curResult.SetStatus(null);
  1235.         return curResult;
  1236.     }
  1237.  
  1238.     // If either operand Invalid, result Invalid
  1239.     if (GetStatus() == invalid || cur.GetStatus() == invalid)
  1240.     {
  1241.         curResult.SetStatus(invalid);
  1242.         return curResult;
  1243.     }
  1244.  
  1245.     // Subtract separate CURRENCY components
  1246.     curResult.m_cur.Hi = m_cur.Hi - cur.m_cur.Hi;
  1247.     curResult.m_cur.Lo = m_cur.Lo - cur.m_cur.Lo;
  1248.  
  1249.     // Decrement Hi if Lo overflows
  1250.     if (m_cur.Lo < curResult.m_cur.Lo)
  1251.         curResult.m_cur.Hi--;
  1252.  
  1253.     // Overflow if operands not same sign and result not same sign
  1254.     if (((m_cur.Hi ^ cur.m_cur.Hi) & 0x80000000) &&
  1255.         ((m_cur.Hi ^ curResult.m_cur.Hi) & 0x80000000))
  1256.     {
  1257.         curResult.SetStatus(invalid);
  1258.     }
  1259.  
  1260.     return curResult;
  1261. }
  1262.  
  1263. COleCurrency COleCurrency::operator-() const
  1264. {
  1265.     // If operand not Valid, just return
  1266.     if (!GetStatus() == valid)
  1267.         return *this;
  1268.  
  1269.     COleCurrency curResult;
  1270.  
  1271.     // Negating MIN_CURRENCY,will set invalid
  1272.     if (m_cur.Hi == 0x80000000 && m_cur.Lo == 0x00000000)
  1273.     {
  1274.         curResult.SetStatus(invalid);
  1275.     }
  1276.  
  1277.     curResult.m_cur.Hi = ~m_cur.Hi;
  1278.     curResult.m_cur.Lo = -(long)m_cur.Lo;
  1279.  
  1280.     // If cy was -1 make sure Hi correctly set
  1281.     if (curResult.m_cur.Lo == 0)
  1282.         curResult.m_cur.Hi++;
  1283.  
  1284.     return curResult;
  1285. }
  1286.  
  1287. COleCurrency COleCurrency::operator*(long nOperand) const
  1288. {
  1289.     // If operand not Valid, just return
  1290.     if (!GetStatus() == valid)
  1291.         return *this;
  1292.  
  1293.     COleCurrency curResult(m_cur);
  1294.     DWORD nTempOp;
  1295.  
  1296.     // Return now if one operand is 0 (optimization)
  1297.     if ((m_cur.Hi == 0x00000000 && m_cur.Lo == 0x00000000) || nOperand == 0)
  1298.     {
  1299.         curResult.m_cur.Hi = 0;
  1300.         curResult.m_cur.Lo = 0;
  1301.         return curResult;
  1302.     }
  1303.  
  1304.     // Handle only valid case of multiplying MIN_CURRENCY
  1305.     if (m_cur.Hi == 0x80000000 && m_cur.Lo == 0x00000000 && nOperand == 1)
  1306.         return curResult;
  1307.  
  1308.     // Compute absolute values.
  1309.     if (m_cur.Hi < 0)
  1310.         curResult = -curResult;
  1311.  
  1312.     nTempOp = labs(nOperand);
  1313.  
  1314.     // Check for overflow
  1315.     if (curResult.m_cur.Hi != 0)
  1316.     {
  1317.         WORD wHiBitCur, wHiBitOp;
  1318.         HI_BIT(curResult.m_cur.Hi, wHiBitCur);
  1319.         HI_BIT(nTempOp, wHiBitOp);
  1320.  
  1321.         // 63-bit limit on result. (n bits)*(m bits) = (n+m-1) bits.
  1322.         if (wHiBitCur + wHiBitOp - 1 > 63)
  1323.         {
  1324.             // Overflow!
  1325.             curResult.SetStatus(invalid);
  1326.  
  1327.             // Set to maximum negative value
  1328.             curResult.m_cur.Hi = 0x80000000;
  1329.             curResult.m_cur.Lo = 0x00000000;
  1330.  
  1331.             return curResult;
  1332.         }
  1333.     }
  1334.  
  1335.     // Break up into WORDs
  1336.     WORD wCy4, wCy3, wCy2, wCy1, wL2, wL1;
  1337.  
  1338.     wCy4 = HIWORD(curResult.m_cur.Hi);
  1339.     wCy3 = LOWORD(curResult.m_cur.Hi);
  1340.     wCy2 = HIWORD(curResult.m_cur.Lo);
  1341.     wCy1 = LOWORD(curResult.m_cur.Lo);
  1342.  
  1343.     wL2 = HIWORD(nTempOp);
  1344.     wL1 = LOWORD(nTempOp);
  1345.  
  1346.     // Multiply each set of WORDs
  1347.     DWORD dwRes11, dwRes12, dwRes21, dwRes22;
  1348.     DWORD dwRes31, dwRes32, dwRes41;  // Don't need dwRes42
  1349.  
  1350.     dwRes11 = wCy1 * wL1;
  1351.     dwRes12 = wCy1 * wL2;
  1352.     dwRes21 = wCy2 * wL1;
  1353.     dwRes22 = wCy2 * wL2;
  1354.  
  1355.     dwRes31 = wCy3 * wL1;
  1356.     dwRes32 = wCy3 * wL2;
  1357.     dwRes41 = wCy4 * wL1;
  1358.  
  1359.     // Add up low order pieces
  1360.     dwRes11 += dwRes12<<16;
  1361.     curResult.m_cur.Lo = dwRes11 + (dwRes21<<16);
  1362.     curResult.m_cur.Hi = 0;
  1363.  
  1364.     // Check if carry required
  1365.     if (dwRes11 < dwRes12<<16)
  1366.         curResult.m_cur.Hi++;
  1367.     if ((DWORD)curResult.m_cur.Lo < dwRes11)
  1368.         curResult.m_cur.Hi++;
  1369.  
  1370.     // Add up the high order pieces
  1371.     curResult.m_cur.Hi += dwRes31 + (dwRes32<<16) + (dwRes41<<16) +
  1372.         dwRes22 + (dwRes12>>16) + (dwRes21>>16);
  1373.  
  1374.     // Compute result sign
  1375.     if ((m_cur.Hi ^ nOperand) & 0x80000000)
  1376.         curResult = -curResult;
  1377.  
  1378.     return curResult;
  1379. }
  1380.  
  1381. COleCurrency COleCurrency::operator/(long nOperand) const
  1382. {
  1383.     // If operand not Valid, just return
  1384.     if (!GetStatus() == valid)
  1385.         return *this;
  1386.  
  1387.     COleCurrency curTemp(m_cur);
  1388.     DWORD nTempOp;
  1389.  
  1390.     // Check for divide by 0
  1391.     if (nOperand == 0)
  1392.     {
  1393.         curTemp.SetStatus(invalid);
  1394.  
  1395.         // Set to maximum negative value
  1396.         curTemp.m_cur.Hi = 0x80000000;
  1397.         curTemp.m_cur.Lo = 0x00000000;
  1398.  
  1399.         return curTemp;
  1400.     }
  1401.  
  1402.     // Compute absolute values
  1403.     if (curTemp.m_cur.Hi < 0)
  1404.         curTemp = -curTemp;
  1405.  
  1406.     nTempOp = labs(nOperand);
  1407.  
  1408.     // Optimization - division is simple if Hi == 0
  1409.     if (curTemp.m_cur.Hi == 0x0000)
  1410.     {
  1411.         curTemp.m_cur.Lo = m_cur.Lo / nTempOp;
  1412.  
  1413.         // Compute result sign
  1414.         if ((m_cur.Hi ^ nOperand) & 0x80000000)
  1415.             curTemp = -curTemp;
  1416.  
  1417.         return curTemp;
  1418.     }
  1419.  
  1420.     // Now curTemp represents remainder
  1421.     COleCurrency curResult; // Initializes to zero
  1422.     COleCurrency curTempResult;
  1423.     COleCurrency curOperand;
  1424.  
  1425.     curOperand.m_cur.Lo = nTempOp;
  1426.  
  1427.     WORD wHiBitRem;
  1428.     WORD wScaleOp;
  1429.  
  1430.     // Quit if remainder can be truncated
  1431.     while (curTemp >= curOperand)
  1432.     {
  1433.         // Scale up and divide Hi portion
  1434.         HI_BIT(curTemp.m_cur.Hi, wHiBitRem);
  1435.  
  1436.         if (wHiBitRem != 0)
  1437.             wHiBitRem += 32;
  1438.         else
  1439.             HI_BIT(curTemp.m_cur.Lo, wHiBitRem);
  1440.  
  1441.         WORD wShift = (WORD)(64 - wHiBitRem);
  1442.         LSHIFT_UCUR(curTemp, wShift);
  1443.  
  1444.         // If Operand bigger than Hi it must be scaled
  1445.         wScaleOp = (WORD)((nTempOp > (DWORD)curTemp.m_cur.Hi) ? 1 : 0);
  1446.  
  1447.         // Perform synthetic division
  1448.         curTempResult.m_cur.Hi =
  1449.             (DWORD)curTemp.m_cur.Hi / (nTempOp >> wScaleOp);
  1450.  
  1451.         // Scale back to get correct result and remainder
  1452.         RSHIFT_UCUR(curTemp, wShift);
  1453.         wShift = (WORD)(wShift - wScaleOp);
  1454.         RSHIFT_UCUR(curTempResult, wShift);
  1455.  
  1456.         // Now calculate result and remainder
  1457.         curResult += curTempResult;
  1458.         curTemp -= curTempResult * nTempOp;
  1459.     }
  1460.  
  1461.     // Compute result sign
  1462.     if ((m_cur.Hi ^ nOperand) & 0x80000000)
  1463.         curResult = -curResult;
  1464.  
  1465.     return curResult;
  1466. }
  1467.  
  1468. void COleCurrency::SetCurrency(long nUnits, long nFractionalUnits)
  1469. {
  1470.     COleCurrency curUnits;              // Initializes to 0
  1471.     COleCurrency curFractionalUnits;    // Initializes to 0
  1472.  
  1473.     // Set temp currency value to Units (need to multiply by 10,000)
  1474.     curUnits.m_cur.Lo = (DWORD)labs(nUnits);
  1475.     curUnits = curUnits * 10000;
  1476.     if (nUnits < 0)
  1477.         curUnits = -curUnits;
  1478.  
  1479.     curFractionalUnits.m_cur.Lo = (DWORD)labs(nFractionalUnits);
  1480.     if (nFractionalUnits < 0)
  1481.         curFractionalUnits = -curFractionalUnits;
  1482.  
  1483.     // Now add together Units and FractionalUnits
  1484.     *this = curUnits + curFractionalUnits;
  1485.  
  1486.     SetStatus(valid);
  1487. }
  1488.  
  1489. BOOL COleCurrency::ParseCurrency(LPCTSTR lpszCurrency,
  1490.     DWORD dwFlags,  LCID lcid)
  1491. {
  1492.     USES_CONVERSION;
  1493.     CString strCurrency = lpszCurrency;
  1494.  
  1495.     SCODE sc;
  1496.     if ( FAILED(sc = VarCyFromStr((LPOLESTR)T2COLE(strCurrency),
  1497.         lcid, dwFlags, &m_cur)))
  1498.     {
  1499.         if (sc == DISP_E_TYPEMISMATCH)
  1500.         {
  1501.             // Can't convert string to CURRENCY, set 0 & invalid
  1502.             m_cur.Hi = 0x00000000;
  1503.             m_cur.Lo = 0x00000000;
  1504.             SetStatus(invalid);
  1505.             return FALSE;
  1506.         }
  1507.         else if (sc == DISP_E_OVERFLOW)
  1508.         {
  1509.             // Can't convert string to CURRENCY, set max neg & invalid
  1510.             m_cur.Hi = 0x80000000;
  1511.             m_cur.Lo = 0x00000000;
  1512.             SetStatus(invalid);
  1513.             return FALSE;
  1514.         }
  1515.         else
  1516.         {
  1517.             TRACE0("\nCOleCurrency VarCyFromStr call failed.\n\t");
  1518.             if (sc == E_OUTOFMEMORY)
  1519.                 AfxThrowMemoryException();
  1520.             else
  1521.                 AfxThrowOleException(sc);
  1522.         }
  1523.     }
  1524.  
  1525.     SetStatus(valid);
  1526.     return TRUE;
  1527. }
  1528.  
  1529. CString COleCurrency::Format(DWORD dwFlags, LCID lcid) const
  1530. {
  1531.     USES_CONVERSION;
  1532.     CString strCur;
  1533.  
  1534.     // If null, return empty string
  1535.     if (GetStatus() == null)
  1536.         return strCur;
  1537.  
  1538.     // If invalid, return Currency resource string
  1539.     if (GetStatus() == invalid)
  1540.     {
  1541.         VERIFY(strCur.LoadString(AFX_IDS_INVALID_CURRENCY));
  1542.         return strCur;
  1543.     }
  1544.  
  1545.     COleVariant var;
  1546.     // Don't need to trap error. Should not fail due to type mismatch
  1547.     CheckError(VarBstrFromCy(m_cur, lcid, dwFlags, &V_BSTR(&var)));
  1548.     var.vt = VT_BSTR;
  1549.     return OLE2CT(V_BSTR(&var));
  1550. }
  1551.  
  1552.  
  1553. // serialization
  1554. #ifdef _DEBUG
  1555. CDumpContext& AFXAPI operator<<(CDumpContext& dc, COleCurrency curSrc)
  1556. {
  1557.     dc << "\nCOleCurrency Object:";
  1558.     dc << "\n\tm_status = " << (long)curSrc.m_status;
  1559.  
  1560.     COleVariant var(curSrc);
  1561.     var.ChangeType(VT_CY);
  1562.     return dc << "\n\tCurrency = " << (LPCTSTR)var.bstrVal;
  1563. }
  1564. #endif // _DEBUG
  1565.  
  1566. CArchive& AFXAPI operator<<(CArchive& ar, COleCurrency curSrc)
  1567. {
  1568.     ar << (long)curSrc.m_status;
  1569.     ar << curSrc.m_cur.Hi;
  1570.     return ar << curSrc.m_cur.Lo;
  1571. }
  1572.  
  1573. CArchive& AFXAPI operator>>(CArchive& ar, COleCurrency& curSrc)
  1574. {
  1575.     ar >> (long&)curSrc.m_status;
  1576.     ar >> curSrc.m_cur.Hi;
  1577.     return ar >> curSrc.m_cur.Lo;
  1578. }
  1579.  
  1580.  
  1581. /////////////////////////////////////////////////////////////////////////////
  1582. // COleDateTime class HELPER definitions
  1583.  
  1584. // Verifies will fail if the needed buffer size is too large
  1585. #define MAX_TIME_BUFFER_SIZE    128         // matches that in timecore.cpp
  1586. #define MIN_DATE                (-657434L)  // about year 100
  1587. #define MAX_DATE                2958465L    // about year 9999
  1588.  
  1589. // Half a second, expressed in days
  1590. #define HALF_SECOND  (1.0/172800.0)
  1591.  
  1592. // One-based array of days in year at month start
  1593. static int rgMonthDays[13] =
  1594.     {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
  1595.  
  1596. static BOOL OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay,
  1597.     WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest);
  1598. static BOOL TmFromOleDate(DATE dtSrc, struct tm& tmDest);
  1599. static void TmConvertToStandardFormat(struct tm& tmSrc);
  1600. static double DoubleFromDate(DATE dt);
  1601. static DATE DateFromDouble(double dbl);
  1602.  
  1603. /////////////////////////////////////////////////////////////////////////////
  1604. // COleDateTime class
  1605.  
  1606. COleDateTime PASCAL COleDateTime::GetCurrentTime()
  1607. {
  1608.     return COleDateTime(::time(NULL));
  1609. }
  1610.  
  1611. int COleDateTime::GetYear() const
  1612. {
  1613.     struct tm tmTemp;
  1614.  
  1615.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1616.         return tmTemp.tm_year;
  1617.     else
  1618.         return AFX_OLE_DATETIME_ERROR;
  1619. }
  1620.  
  1621. int COleDateTime::GetMonth() const
  1622. {
  1623.     struct tm tmTemp;
  1624.  
  1625.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1626.         return tmTemp.tm_mon;
  1627.     else
  1628.         return AFX_OLE_DATETIME_ERROR;
  1629. }
  1630.  
  1631. int COleDateTime::GetDay() const
  1632. {
  1633.     struct tm tmTemp;
  1634.  
  1635.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1636.         return tmTemp.tm_mday;
  1637.     else
  1638.         return AFX_OLE_DATETIME_ERROR;
  1639. }
  1640.  
  1641. int COleDateTime::GetHour() const
  1642. {
  1643.     struct tm tmTemp;
  1644.  
  1645.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1646.         return tmTemp.tm_hour;
  1647.     else
  1648.         return AFX_OLE_DATETIME_ERROR;
  1649. }
  1650.  
  1651. int COleDateTime::GetMinute() const
  1652. {
  1653.     struct tm tmTemp;
  1654.  
  1655.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1656.         return tmTemp.tm_min;
  1657.     else
  1658.         return AFX_OLE_DATETIME_ERROR;
  1659. }
  1660.  
  1661. int COleDateTime::GetSecond() const
  1662. {
  1663.     struct tm tmTemp;
  1664.  
  1665.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1666.         return tmTemp.tm_sec;
  1667.     else
  1668.         return AFX_OLE_DATETIME_ERROR;
  1669. }
  1670.  
  1671. int COleDateTime::GetDayOfWeek() const
  1672. {
  1673.     struct tm tmTemp;
  1674.  
  1675.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1676.         return tmTemp.tm_wday;
  1677.     else
  1678.         return AFX_OLE_DATETIME_ERROR;
  1679. }
  1680.  
  1681. int COleDateTime::GetDayOfYear() const
  1682. {
  1683.     struct tm tmTemp;
  1684.  
  1685.     if (GetStatus() == valid && TmFromOleDate(m_dt, tmTemp))
  1686.         return tmTemp.tm_yday;
  1687.     else
  1688.         return AFX_OLE_DATETIME_ERROR;
  1689. }
  1690.  
  1691. const COleDateTime& COleDateTime::operator=(const VARIANT& varSrc)
  1692. {
  1693.     if (varSrc.vt != VT_DATE)
  1694.     {
  1695.         TRY
  1696.         {
  1697.             COleVariant varTemp(varSrc);
  1698.             varTemp.ChangeType(VT_DATE);
  1699.             m_dt = varTemp.date;
  1700.             SetStatus(valid);
  1701.         }
  1702.         // Catch COleException from ChangeType, but not CMemoryException
  1703.         CATCH(COleException, e)
  1704.         {
  1705.             // Not able to convert VARIANT to DATE
  1706.             DELETE_EXCEPTION(e);
  1707.             m_dt = 0;
  1708.             SetStatus(invalid);
  1709.         }
  1710.         END_CATCH
  1711.     }
  1712.     else
  1713.     {
  1714.         m_dt = varSrc.date;
  1715.         SetStatus(valid);
  1716.     }
  1717.  
  1718.     return *this;
  1719. }
  1720.  
  1721. const COleDateTime& COleDateTime::operator=(DATE dtSrc)
  1722. {
  1723.     m_dt = dtSrc;
  1724.     SetStatus(valid);
  1725.  
  1726.     return *this;
  1727. }
  1728.  
  1729. const COleDateTime& COleDateTime::operator=(const time_t& timeSrc)
  1730. {
  1731.     // Convert time_t to struct tm
  1732.     tm *ptm = localtime(&timeSrc);
  1733.  
  1734.     if (ptm != NULL)
  1735.     {
  1736.         m_status = OleDateFromTm((WORD)(ptm->tm_year + 1900),
  1737.             (WORD)(ptm->tm_mon + 1), (WORD)ptm->tm_mday,
  1738.             (WORD)ptm->tm_hour, (WORD)ptm->tm_min,
  1739.             (WORD)ptm->tm_sec, m_dt) ? valid : invalid;
  1740.     }
  1741.     else
  1742.     {
  1743.         // Local time must have failed (timsSrc before 1/1/70 12am)
  1744.         SetStatus(invalid);
  1745.         ASSERT(FALSE);
  1746.     }
  1747.  
  1748.     return *this;
  1749. }
  1750.  
  1751. const COleDateTime& COleDateTime::operator=(const SYSTEMTIME& systimeSrc)
  1752. {
  1753.     m_status = OleDateFromTm(systimeSrc.wYear, systimeSrc.wMonth,
  1754.         systimeSrc.wDay, systimeSrc.wHour, systimeSrc.wMinute,
  1755.         systimeSrc.wSecond, m_dt) ? valid : invalid;
  1756.  
  1757.     return *this;
  1758. }
  1759.  
  1760. const COleDateTime& COleDateTime::operator=(const FILETIME& filetimeSrc)
  1761. {
  1762.     // Assume UTC FILETIME, so convert to LOCALTIME
  1763.     FILETIME filetimeLocal;
  1764.     if (!FileTimeToLocalFileTime( &filetimeSrc, &filetimeLocal))
  1765.     {
  1766. #ifdef _DEBUG
  1767.         DWORD dwError = GetLastError();
  1768.         TRACE1("\nFileTimeToLocalFileTime failed. Error = %lu.\n\t", dwError);
  1769. #endif // _DEBUG
  1770.         m_status = invalid;
  1771.     }
  1772.     else
  1773.     {
  1774.         // Take advantage of SYSTEMTIME -> FILETIME conversion
  1775.         SYSTEMTIME systime;
  1776.         m_status = FileTimeToSystemTime(&filetimeLocal, &systime) ?
  1777.             valid : invalid;
  1778.  
  1779.         // At this point systime should always be valid, but...
  1780.         if (GetStatus() == valid)
  1781.         {
  1782.             m_status = OleDateFromTm(systime.wYear, systime.wMonth,
  1783.                 systime.wDay, systime.wHour, systime.wMinute,
  1784.                 systime.wSecond, m_dt) ? valid : invalid;
  1785.         }
  1786.     }
  1787.  
  1788.     return *this;
  1789. }
  1790.  
  1791. BOOL COleDateTime::operator<(const COleDateTime& date) const
  1792. {
  1793.     ASSERT(GetStatus() == valid);
  1794.     ASSERT(date.GetStatus() == valid);
  1795.  
  1796.     // Handle negative dates
  1797.     return DoubleFromDate(m_dt) < DoubleFromDate(date.m_dt);
  1798. }
  1799.  
  1800. BOOL COleDateTime::operator>(const COleDateTime& date) const
  1801. {   ASSERT(GetStatus() == valid);
  1802.     ASSERT(date.GetStatus() == valid);
  1803.  
  1804.     // Handle negative dates
  1805.     return DoubleFromDate(m_dt) > DoubleFromDate(date.m_dt);
  1806. }
  1807.  
  1808. BOOL COleDateTime::operator<=(const COleDateTime& date) const
  1809. {
  1810.     ASSERT(GetStatus() == valid);
  1811.     ASSERT(date.GetStatus() == valid);
  1812.  
  1813.     // Handle negative dates
  1814.     return DoubleFromDate(m_dt) <= DoubleFromDate(date.m_dt);
  1815. }
  1816.  
  1817. BOOL COleDateTime::operator>=(const COleDateTime& date) const
  1818. {
  1819.     ASSERT(GetStatus() == valid);
  1820.     ASSERT(date.GetStatus() == valid);
  1821.  
  1822.     // Handle negative dates
  1823.     return DoubleFromDate(m_dt) >= DoubleFromDate(date.m_dt);
  1824. }
  1825.  
  1826. COleDateTime COleDateTime::operator+(const COleDateTimeSpan& dateSpan) const
  1827. {
  1828.     COleDateTime dateResult;    // Initializes m_status to valid
  1829.  
  1830.     // If either operand NULL, result NULL
  1831.     if (GetStatus() == null || dateSpan.GetStatus() == null)
  1832.     {
  1833.         dateResult.SetStatus(null);
  1834.         return dateResult;
  1835.     }
  1836.  
  1837.     // If either operand invalid, result invalid
  1838.     if (GetStatus() == invalid || dateSpan.GetStatus() == invalid)
  1839.     {
  1840.         dateResult.SetStatus(invalid);
  1841.         return dateResult;
  1842.     }
  1843.  
  1844.     // Compute the actual date difference by adding underlying dates
  1845.     dateResult = DateFromDouble(DoubleFromDate(m_dt) + dateSpan.m_span);
  1846.  
  1847.     // Validate within range
  1848.     dateResult.CheckRange();
  1849.  
  1850.     return dateResult;
  1851. }
  1852.  
  1853. COleDateTime COleDateTime::operator-(const COleDateTimeSpan& dateSpan) const
  1854. {
  1855.     COleDateTime dateResult;    // Initializes m_status to valid
  1856.  
  1857.     // If either operand NULL, result NULL
  1858.     if (GetStatus() == null || dateSpan.GetStatus() == null)
  1859.     {
  1860.         dateResult.SetStatus(null);
  1861.         return dateResult;
  1862.     }
  1863.  
  1864.     // If either operand invalid, result invalid
  1865.     if (GetStatus() == invalid || dateSpan.GetStatus() == invalid)
  1866.     {
  1867.         dateResult.SetStatus(invalid);
  1868.         return dateResult;
  1869.     }
  1870.  
  1871.     // Compute the actual date difference by subtracting underlying dates
  1872.     dateResult = DateFromDouble(DoubleFromDate(m_dt) - dateSpan.m_span);
  1873.  
  1874.     // Validate within range
  1875.     dateResult.CheckRange();
  1876.  
  1877.     return dateResult;
  1878. }
  1879.  
  1880. COleDateTimeSpan COleDateTime::operator-(const COleDateTime& date) const
  1881. {
  1882.     COleDateTimeSpan spanResult;
  1883.  
  1884.     // If either operand NULL, result NULL
  1885.     if (GetStatus() == null || date.GetStatus() == null)
  1886.     {
  1887.         spanResult.SetStatus(COleDateTimeSpan::null);
  1888.         return spanResult;
  1889.     }
  1890.  
  1891.     // If either operand invalid, result invalid
  1892.     if (GetStatus() == invalid || date.GetStatus() == invalid)
  1893.     {
  1894.         spanResult.SetStatus(COleDateTimeSpan::invalid);
  1895.         return spanResult;
  1896.     }
  1897.  
  1898.     // Return result (span can't be invalid, so don't check range)
  1899.     return DoubleFromDate(m_dt) - DoubleFromDate(date.m_dt);
  1900. }
  1901.  
  1902. int COleDateTime::SetDateTime(int nYear, int nMonth, int nDay,
  1903.     int nHour, int nMin, int nSec)
  1904. {
  1905.     return m_status = OleDateFromTm((WORD)nYear, (WORD)nMonth,
  1906.         (WORD)nDay, (WORD)nHour, (WORD)nMin, (WORD)nSec, m_dt) ?
  1907.         valid : invalid;
  1908. }
  1909.  
  1910. BOOL COleDateTime::ParseDateTime(LPCTSTR lpszDate, DWORD dwFlags, LCID lcid)
  1911. {
  1912.     USES_CONVERSION;
  1913.     CString strDate = lpszDate;
  1914.  
  1915.     SCODE sc;
  1916.     if (FAILED(sc = VarDateFromStr((LPOLESTR)T2COLE(strDate), lcid,
  1917.         dwFlags, &m_dt)))
  1918.     {
  1919.         if (sc == DISP_E_TYPEMISMATCH)
  1920.         {
  1921.             // Can't convert string to date, set 0 and invalidate
  1922.             m_dt = 0;
  1923.             SetStatus(invalid);
  1924.             return FALSE;
  1925.         }
  1926.         else if (sc == DISP_E_OVERFLOW)
  1927.         {
  1928.             // Can't convert string to date, set -1 and invalidate
  1929.             m_dt = -1;
  1930.             SetStatus(invalid);
  1931.             return FALSE;
  1932.         }
  1933.         else
  1934.         {
  1935.             TRACE0("\nCOleDateTime VarDateFromStr call failed.\n\t");
  1936.             if (sc == E_OUTOFMEMORY)
  1937.                 AfxThrowMemoryException();
  1938.             else
  1939.                 AfxThrowOleException(sc);
  1940.         }
  1941.     }
  1942.  
  1943.     SetStatus(valid);
  1944.     return TRUE;
  1945. }
  1946.  
  1947. CString COleDateTime::Format(DWORD dwFlags, LCID lcid) const
  1948. {
  1949.     USES_CONVERSION;
  1950.     CString strDate;
  1951.  
  1952.     // If null, return empty string
  1953.     if (GetStatus() == null)
  1954.         return strDate;
  1955.  
  1956.     // If invalid, return DateTime resource string
  1957.     if (GetStatus() == invalid)
  1958.     {
  1959.         VERIFY(strDate.LoadString(AFX_IDS_INVALID_DATETIME));
  1960.         return strDate;
  1961.     }
  1962.  
  1963.     COleVariant var;
  1964.     // Don't need to trap error. Should not fail due to type mismatch
  1965.     CheckError(VarBstrFromDate(m_dt, lcid, dwFlags, &V_BSTR(&var)));
  1966.     var.vt = VT_BSTR;
  1967.     return OLE2CT(V_BSTR(&var));
  1968. }
  1969.  
  1970. CString COleDateTime::Format(LPCTSTR pFormat) const
  1971. {
  1972.     CString strDate;
  1973.     struct tm tmTemp;
  1974.  
  1975.     // If null, return empty string
  1976.     if (GetStatus() == null)
  1977.         return strDate;
  1978.  
  1979.     // If invalid, return DateTime resource string
  1980.     if (GetStatus() == invalid || !TmFromOleDate(m_dt, tmTemp))
  1981.     {
  1982.         VERIFY(strDate.LoadString(AFX_IDS_INVALID_DATETIME));
  1983.         return strDate;
  1984.     }
  1985.  
  1986.     // Convert tm from afx internal format to standard format
  1987.     TmConvertToStandardFormat(tmTemp);
  1988.  
  1989.     // Fill in the buffer, disregard return value as it's not necessary
  1990.     LPTSTR lpszTemp = strDate.GetBufferSetLength(MAX_TIME_BUFFER_SIZE);
  1991.     _tcsftime(lpszTemp, strDate.GetLength(), pFormat, &tmTemp);
  1992.     strDate.ReleaseBuffer();
  1993.  
  1994.     return strDate;
  1995. }
  1996.  
  1997. CString COleDateTime::Format(UINT nFormatID) const
  1998. {
  1999.     CString strFormat;
  2000.     VERIFY(strFormat.LoadString(nFormatID) != 0);
  2001.     return Format(strFormat);
  2002. }
  2003.  
  2004. void COleDateTime::CheckRange()
  2005. {
  2006.     if (m_dt > MAX_DATE || m_dt < MIN_DATE) // about year 100 to about 9999
  2007.         SetStatus(invalid);
  2008. }
  2009.  
  2010. // serialization
  2011. #ifdef _DEBUG
  2012. CDumpContext& AFXAPI operator<<(CDumpContext& dc, COleDateTime dateSrc)
  2013. {
  2014.     dc << "\nCOleDateTime Object:";
  2015.     dc << "\n\tm_status = " << (long)dateSrc.m_status;
  2016.  
  2017.     COleVariant var(dateSrc);
  2018.     var.ChangeType(VT_BSTR);
  2019.  
  2020.     return dc << "\n\tdate = " << (LPCTSTR)var.bstrVal;
  2021. }
  2022. #endif // _DEBUG
  2023.  
  2024. CArchive& AFXAPI operator<<(CArchive& ar, COleDateTime dateSrc)
  2025. {
  2026.     ar << (long)dateSrc.m_status;
  2027.     return ar << dateSrc.m_dt;
  2028. }
  2029.  
  2030. CArchive& AFXAPI operator>>(CArchive& ar, COleDateTime& dateSrc)
  2031. {
  2032.     ar >> (long&)dateSrc.m_status;
  2033.     return ar >> dateSrc.m_dt;
  2034. }
  2035.  
  2036. /////////////////////////////////////////////////////////////////////////////
  2037. // COleDateTimeSpan class helpers
  2038.  
  2039. #define MAX_DAYS_IN_SPAN    3615897L
  2040.  
  2041. /////////////////////////////////////////////////////////////////////////////
  2042. // COleDateTimeSpan class
  2043. long COleDateTimeSpan::GetHours() const
  2044. {
  2045.     ASSERT(GetStatus() == valid);
  2046.  
  2047.     double dblTemp;
  2048.  
  2049.     // Truncate days and scale up
  2050.     dblTemp = modf(m_span, &dblTemp);
  2051.     return (long)(dblTemp * 24);
  2052. }
  2053.  
  2054. long COleDateTimeSpan::GetMinutes() const
  2055. {
  2056.     ASSERT(GetStatus() == valid);
  2057.  
  2058.     double dblTemp;
  2059.  
  2060.     // Truncate hours and scale up
  2061.     dblTemp = modf(m_span * 24, &dblTemp);
  2062.     return (long)(dblTemp * 60);
  2063. }
  2064.  
  2065. long COleDateTimeSpan::GetSeconds() const
  2066. {
  2067.     ASSERT(GetStatus() == valid);
  2068.  
  2069.     double dblTemp;
  2070.  
  2071.     // Truncate minutes and scale up
  2072.     dblTemp = modf(m_span * 24 * 60, &dblTemp);
  2073.     return (long)(dblTemp * 60);
  2074. }
  2075.  
  2076. const COleDateTimeSpan& COleDateTimeSpan::operator=(double dblSpanSrc)
  2077. {
  2078.     m_span = dblSpanSrc;
  2079.     SetStatus(valid);
  2080.     return *this;
  2081. }
  2082.  
  2083. const COleDateTimeSpan& COleDateTimeSpan::operator=(const COleDateTimeSpan& dateSpanSrc)
  2084. {
  2085.     m_span = dateSpanSrc.m_span;
  2086.     m_status = dateSpanSrc.m_status;
  2087.     return *this;
  2088. }
  2089.  
  2090. COleDateTimeSpan COleDateTimeSpan::operator+(const COleDateTimeSpan& dateSpan) const
  2091. {
  2092.     COleDateTimeSpan dateSpanTemp;
  2093.  
  2094.     // If either operand Null, result Null
  2095.     if (GetStatus() == null || dateSpan.GetStatus() == null)
  2096.     {
  2097.         dateSpanTemp.SetStatus(null);
  2098.         return dateSpanTemp;
  2099.     }
  2100.  
  2101.     // If either operand Invalid, result Invalid
  2102.     if (GetStatus() == invalid || dateSpan.GetStatus() == invalid)
  2103.     {
  2104.         dateSpanTemp.SetStatus(invalid);
  2105.         return dateSpanTemp;
  2106.     }
  2107.  
  2108.     // Add spans and validate within legal range
  2109.     dateSpanTemp.m_span = m_span + dateSpan.m_span;
  2110.     dateSpanTemp.CheckRange();
  2111.  
  2112.     return dateSpanTemp;
  2113. }
  2114.  
  2115. COleDateTimeSpan COleDateTimeSpan::operator-(const COleDateTimeSpan& dateSpan) const
  2116. {
  2117.     COleDateTimeSpan dateSpanTemp;
  2118.  
  2119.     // If either operand Null, result Null
  2120.     if (GetStatus() == null || dateSpan.GetStatus() == null)
  2121.     {
  2122.         dateSpanTemp.SetStatus(null);
  2123.         return dateSpanTemp;
  2124.     }
  2125.  
  2126.     // If either operand Invalid, result Invalid
  2127.     if (GetStatus() == invalid || dateSpan.GetStatus() == invalid)
  2128.     {
  2129.         dateSpanTemp.SetStatus(invalid);
  2130.         return dateSpanTemp;
  2131.     }
  2132.  
  2133.     // Subtract spans and validate within legal range
  2134.     dateSpanTemp.m_span = m_span - dateSpan.m_span;
  2135.     dateSpanTemp.CheckRange();
  2136.  
  2137.     return dateSpanTemp;
  2138. }
  2139.  
  2140. void COleDateTimeSpan::SetDateTimeSpan(
  2141.     long lDays, int nHours, int nMins, int nSecs)
  2142. {
  2143.     // Set date span by breaking into fractional days (all input ranges valid)
  2144.     m_span = lDays + ((double)nHours)/24 + ((double)nMins)/(24*60) +
  2145.         ((double)nSecs)/(24*60*60);
  2146.  
  2147.     SetStatus(valid);
  2148. }
  2149.  
  2150. CString COleDateTimeSpan::Format(LPCTSTR pFormat) const
  2151. {
  2152.     CString strSpan;
  2153.     struct tm tmTemp;
  2154.  
  2155.     // If null, return empty string
  2156.     if (GetStatus() == null)
  2157.         return strSpan;
  2158.  
  2159.     // If invalid, return DateTimeSpan resource string
  2160.     if (GetStatus() == invalid || !TmFromOleDate(m_span, tmTemp))
  2161.     {
  2162.         VERIFY(strSpan.LoadString(AFX_IDS_INVALID_DATETIMESPAN));
  2163.         return strSpan;
  2164.     }
  2165.  
  2166.     // Convert tm from afx internal format to standard format
  2167.     TmConvertToStandardFormat(tmTemp);
  2168.  
  2169.     // Fill in the buffer, disregard return value as it's not necessary
  2170.     LPTSTR lpszTemp = strSpan.GetBufferSetLength(MAX_TIME_BUFFER_SIZE);
  2171.     _tcsftime(lpszTemp, strSpan.GetLength(), pFormat, &tmTemp);
  2172.     strSpan.ReleaseBuffer();
  2173.  
  2174.     return strSpan;
  2175. }
  2176.  
  2177. CString COleDateTimeSpan::Format(UINT nFormatID) const
  2178. {
  2179.     CString strFormat;
  2180.     VERIFY(strFormat.LoadString(nFormatID) != 0);
  2181.     return Format(strFormat);
  2182. }
  2183.  
  2184. void COleDateTimeSpan::CheckRange()
  2185. {
  2186.     if(m_span < -MAX_DAYS_IN_SPAN || m_span > MAX_DAYS_IN_SPAN)
  2187.         SetStatus(invalid);
  2188. }
  2189.  
  2190. // serialization
  2191. #ifdef _DEBUG
  2192. CDumpContext& AFXAPI operator<<(CDumpContext& dc, COleDateTimeSpan dateSpanSrc)
  2193. {
  2194.     dc << "\nCOleDateTimeSpan Object:";
  2195.     dc << "\n\tm_status = " << (long)dateSpanSrc.m_status;
  2196.  
  2197.     COleVariant var(dateSpanSrc.m_span);
  2198.     var.ChangeType(VT_BSTR);
  2199.  
  2200.     return dc << "\n\tdateSpan = " << (LPCTSTR)var.bstrVal;
  2201. }
  2202. #endif // _DEBUG
  2203.  
  2204. CArchive& AFXAPI operator<<(CArchive& ar, COleDateTimeSpan dateSpanSrc)
  2205. {
  2206.     ar << (long)dateSpanSrc.m_status;
  2207.     return ar << dateSpanSrc.m_span;
  2208. }
  2209.  
  2210. CArchive& AFXAPI operator>>(CArchive& ar, COleDateTimeSpan& dateSpanSrc)
  2211. {
  2212.     ar >> (long&)dateSpanSrc.m_status;
  2213.     return ar >> dateSpanSrc.m_span;
  2214. }
  2215.  
  2216. /////////////////////////////////////////////////////////////////////////////
  2217. // COleDateTime class HELPERS - implementation
  2218.  
  2219. BOOL OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay,
  2220.     WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest)
  2221. {
  2222.     // Validate year and month (ignore day of week and milliseconds)
  2223.     if (wYear > 9999 || wMonth < 1 || wMonth > 12)
  2224.         return FALSE;
  2225.  
  2226.     //  Check for leap year and set the number of days in the month
  2227.     BOOL bLeapYear = ((wYear & 3) == 0) &&
  2228.         ((wYear % 100) != 0 || (wYear % 400) == 0);
  2229.  
  2230.     int nDaysInMonth =
  2231.         rgMonthDays[wMonth] - rgMonthDays[wMonth-1] +
  2232.         ((bLeapYear && wDay == 29 && wMonth == 2) ? 1 : 0);
  2233.  
  2234.     // Finish validating the date
  2235.     if (wDay < 1 || wDay > nDaysInMonth ||
  2236.         wHour > 23 || wMinute > 59 ||
  2237.         wSecond > 59)
  2238.     {
  2239.         return FALSE;
  2240.     }
  2241.  
  2242.     // Cache the date in days and time in fractional days
  2243.     long nDate;
  2244.     double dblTime;
  2245.  
  2246.     //It is a valid date; make Jan 1, 1AD be 1
  2247.     nDate = wYear*365L + wYear/4 - wYear/100 + wYear/400 +
  2248.         rgMonthDays[wMonth-1] + wDay;
  2249.  
  2250.     //  If leap year and it's before March, subtract 1:
  2251.     if (wMonth <= 2 && bLeapYear)
  2252.         --nDate;
  2253.  
  2254.     //  Offset so that 12/30/1899 is 0
  2255.     nDate -= 693959L;
  2256.  
  2257.     dblTime = (((long)wHour * 3600L) +  // hrs in seconds
  2258.         ((long)wMinute * 60L) +  // mins in seconds
  2259.         ((long)wSecond)) / 86400.;
  2260.  
  2261.     dtDest = (double) nDate + ((nDate >= 0) ? dblTime : -dblTime);
  2262.  
  2263.     return TRUE;
  2264. }
  2265.  
  2266. BOOL TmFromOleDate(DATE dtSrc, struct tm& tmDest)
  2267. {
  2268.     // The legal range does not actually span year 0 to 9999.
  2269.     if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999
  2270.         return FALSE;
  2271.  
  2272.     long nDays;             // Number of days since Dec. 30, 1899
  2273.     long nDaysAbsolute;     // Number of days since 1/1/0
  2274.     long nSecsInDay;        // Time in seconds since midnight
  2275.     long nMinutesInDay;     // Minutes in day
  2276.  
  2277.     long n400Years;         // Number of 400 year increments since 1/1/0
  2278.     long n400Century;       // Century within 400 year block (0,1,2 or 3)
  2279.     long n4Years;           // Number of 4 year increments since 1/1/0
  2280.     long n4Day;             // Day within 4 year block
  2281.                             //  (0 is 1/1/yr1, 1460 is 12/31/yr4)
  2282.     long n4Yr;              // Year within 4 year block (0,1,2 or 3)
  2283.     BOOL bLeap4 = TRUE;     // TRUE if 4 year block includes leap year
  2284.  
  2285.     double dblDate = dtSrc; // tempory serial date
  2286.  
  2287.     // If a valid date, then this conversion should not overflow
  2288.     nDays = (long)dblDate;
  2289.  
  2290.     // Round to the second
  2291.     dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND);
  2292.  
  2293.     nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899
  2294.  
  2295.     dblDate = fabs(dblDate);
  2296.     nSecsInDay = (long)((dblDate - floor(dblDate)) * 86400.);
  2297.  
  2298.     // Calculate the day of week (sun=1, mon=2...)
  2299.     //   -1 because 1/1/0 is Sat.  +1 because we want 1-based
  2300.     tmDest.tm_wday = (int)((nDaysAbsolute - 1) % 7L) + 1;
  2301.  
  2302.     // Leap years every 4 yrs except centuries not multiples of 400.
  2303.     n400Years = (long)(nDaysAbsolute / 146097L);
  2304.  
  2305.     // Set nDaysAbsolute to day within 400-year block
  2306.     nDaysAbsolute %= 146097L;
  2307.  
  2308.     // -1 because first century has extra day
  2309.     n400Century = (long)((nDaysAbsolute - 1) / 36524L);
  2310.  
  2311.     // Non-leap century
  2312.     if (n400Century != 0)
  2313.     {
  2314.         // Set nDaysAbsolute to day within century
  2315.         nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;
  2316.  
  2317.         // +1 because 1st 4 year increment has 1460 days
  2318.         n4Years = (long)((nDaysAbsolute + 1) / 1461L);
  2319.  
  2320.         if (n4Years != 0)
  2321.             n4Day = (long)((nDaysAbsolute + 1) % 1461L);
  2322.         else
  2323.         {
  2324.             bLeap4 = FALSE;
  2325.             n4Day = (long)nDaysAbsolute;
  2326.         }
  2327.     }
  2328.     else
  2329.     {
  2330.         // Leap century - not special case!
  2331.         n4Years = (long)(nDaysAbsolute / 1461L);
  2332.         n4Day = (long)(nDaysAbsolute % 1461L);
  2333.     }
  2334.  
  2335.     if (bLeap4)
  2336.     {
  2337.         // -1 because first year has 366 days
  2338.         n4Yr = (n4Day - 1) / 365;
  2339.  
  2340.         if (n4Yr != 0)
  2341.             n4Day = (n4Day - 1) % 365;
  2342.     }
  2343.     else
  2344.     {
  2345.         n4Yr = n4Day / 365;
  2346.         n4Day %= 365;
  2347.     }
  2348.  
  2349.     // n4Day is now 0-based day of year. Save 1-based day of year, year number
  2350.     tmDest.tm_yday = (int)n4Day + 1;
  2351.     tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;
  2352.  
  2353.     // Handle leap year: before, on, and after Feb. 29.
  2354.     if (n4Yr == 0 && bLeap4)
  2355.     {
  2356.         // Leap Year
  2357.         if (n4Day == 59)
  2358.         {
  2359.             /* Feb. 29 */
  2360.             tmDest.tm_mon = 2;
  2361.             tmDest.tm_mday = 29;
  2362.             goto DoTime;
  2363.         }
  2364.  
  2365.         // Pretend it's not a leap year for month/day comp.
  2366.         if (n4Day >= 60)
  2367.             --n4Day;
  2368.     }
  2369.  
  2370.     // Make n4DaY a 1-based day of non-leap year and compute
  2371.     //  month/day for everything but Feb. 29.
  2372.     ++n4Day;
  2373.  
  2374.     // Month number always >= n/32, so save some loop time */
  2375.     for (tmDest.tm_mon = (n4Day >> 5) + 1;
  2376.         n4Day > rgMonthDays[tmDest.tm_mon]; tmDest.tm_mon++);
  2377.  
  2378.     tmDest.tm_mday = (int)(n4Day - rgMonthDays[tmDest.tm_mon-1]);
  2379.  
  2380. DoTime:
  2381.     if (nSecsInDay == 0)
  2382.         tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0;
  2383.     else
  2384.     {
  2385.         tmDest.tm_sec = (int)nSecsInDay % 60L;
  2386.         nMinutesInDay = nSecsInDay / 60L;
  2387.         tmDest.tm_min = (int)nMinutesInDay % 60;
  2388.         tmDest.tm_hour = (int)nMinutesInDay / 60;
  2389.     }
  2390.  
  2391.     return TRUE;
  2392. }
  2393.  
  2394. void TmConvertToStandardFormat(struct tm& tmSrc)
  2395. {
  2396.     // Convert afx internal tm to format expected by runtimes (_tcsftime, etc)
  2397.     tmSrc.tm_year -= 1900;  // year is based on 1900
  2398.     tmSrc.tm_mon -= 1;      // month of year is 0-based
  2399.     tmSrc.tm_wday -= 1;     // day of week is 0-based
  2400.     tmSrc.tm_yday -= 1;     // day of year is 0-based
  2401. }
  2402.  
  2403. double DoubleFromDate(DATE dt)
  2404. {
  2405.     // No problem if positive
  2406.     if (dt >= 0)
  2407.         return dt;
  2408.  
  2409.     // If negative, must convert since negative dates not continuous
  2410.     // (examples: -1.25 to -.75, -1.50 to -.50, -1.75 to -.25)
  2411.     double temp = ceil(dt);
  2412.     return temp - (dt - temp);
  2413. }
  2414.  
  2415. DATE DateFromDouble(double dbl)
  2416. {
  2417.     // No problem if positive
  2418.     if (dbl >= 0)
  2419.         return dbl;
  2420.  
  2421.     // If negative, must convert since negative dates not continuous
  2422.     // (examples: -.75 to -1.25, -.50 to -1.50, -.25 to -1.75)
  2423.     double temp = floor(dbl); // dbl is now whole part
  2424.     return temp + (temp - dbl);
  2425. }
  2426.  
  2427. /////////////////////////////////////////////////////////////////////////////
  2428. // COleSafeArray class
  2429. COleSafeArray::COleSafeArray(const SAFEARRAY& saSrc, VARTYPE vtSrc)
  2430. {
  2431.     AfxSafeArrayInit(this);
  2432.     vt = (VARTYPE)(vtSrc | VT_ARRAY);
  2433.     CheckError(::SafeArrayCopy((LPSAFEARRAY)&saSrc, &parray));
  2434.     m_dwDims = GetDim();
  2435.     m_dwElementSize = GetElemSize();
  2436. }
  2437.  
  2438. COleSafeArray::COleSafeArray(LPCSAFEARRAY pSrc, VARTYPE vtSrc)
  2439. {
  2440.     AfxSafeArrayInit(this);
  2441.     vt = (VARTYPE)(vtSrc | VT_ARRAY);
  2442.     CheckError(::SafeArrayCopy((LPSAFEARRAY)pSrc, &parray));
  2443.     m_dwDims = GetDim();
  2444.     m_dwElementSize = GetElemSize();
  2445. }
  2446.  
  2447. COleSafeArray::COleSafeArray(const COleSafeArray& saSrc)
  2448. {
  2449.     AfxSafeArrayInit(this);
  2450.     *this = saSrc;
  2451.     m_dwDims = GetDim();
  2452.     m_dwElementSize = GetElemSize();
  2453. }
  2454.  
  2455. COleSafeArray::COleSafeArray(const VARIANT& varSrc)
  2456. {
  2457.     AfxSafeArrayInit(this);
  2458.     *this = varSrc;
  2459.     m_dwDims = GetDim();
  2460.     m_dwElementSize = GetElemSize();
  2461. }
  2462.  
  2463. COleSafeArray::COleSafeArray(LPCVARIANT pSrc)
  2464. {
  2465.     AfxSafeArrayInit(this);
  2466.     *this = pSrc;
  2467.     m_dwDims = GetDim();
  2468.     m_dwElementSize = GetElemSize();
  2469. }
  2470.  
  2471. // Operations
  2472. void COleSafeArray::Attach(VARIANT& varSrc)
  2473. {
  2474.     ASSERT(varSrc.vt & VT_ARRAY);
  2475.  
  2476.     // Free up previous safe array if necessary
  2477.     Clear();
  2478.  
  2479.     // give control of data to COleSafeArray
  2480.     memcpy(this, &varSrc, sizeof(varSrc));
  2481.     varSrc.vt = VT_EMPTY;
  2482. }
  2483.  
  2484. VARIANT COleSafeArray::Detach()
  2485. {
  2486.     VARIANT varResult = *this;
  2487.     vt = VT_EMPTY;
  2488.     return varResult;
  2489. }
  2490.  
  2491. // Assignment operators
  2492. COleSafeArray& COleSafeArray::operator=(const COleSafeArray& saSrc)
  2493. {
  2494.     ASSERT(saSrc.vt & VT_ARRAY);
  2495.  
  2496.     CheckError(::VariantCopy(this, (LPVARIANT)&saSrc));
  2497.     return *this;
  2498. }
  2499.  
  2500. COleSafeArray& COleSafeArray::operator=(const VARIANT& varSrc)
  2501. {
  2502.     ASSERT(varSrc.vt & VT_ARRAY);
  2503.  
  2504.     CheckError(::VariantCopy(this, (LPVARIANT)&varSrc));
  2505.     return *this;
  2506. }
  2507.  
  2508. COleSafeArray& COleSafeArray::operator=(LPCVARIANT pSrc)
  2509. {
  2510.     ASSERT(pSrc->vt & VT_ARRAY);
  2511.  
  2512.     CheckError(::VariantCopy(this, (LPVARIANT)pSrc));
  2513.     return *this;
  2514. }
  2515.  
  2516. COleSafeArray& COleSafeArray::operator=(const COleVariant& varSrc)
  2517. {
  2518.     ASSERT(varSrc.vt & VT_ARRAY);
  2519.  
  2520.     CheckError(::VariantCopy(this, (LPVARIANT)&varSrc));
  2521.     return *this;
  2522. }
  2523.  
  2524. // Comparison operators
  2525. BOOL COleSafeArray::operator==(const SAFEARRAY& saSrc) const
  2526. {
  2527.     return CompareSafeArrays(parray, (LPSAFEARRAY)&saSrc);
  2528. }
  2529.  
  2530. BOOL COleSafeArray::operator==(LPCSAFEARRAY pSrc) const
  2531. {
  2532.     return CompareSafeArrays(parray, (LPSAFEARRAY)pSrc);
  2533. }
  2534.  
  2535. BOOL COleSafeArray::operator==(const COleSafeArray& saSrc) const
  2536. {
  2537.     if (vt != saSrc.vt)
  2538.         return FALSE;
  2539.  
  2540.     return CompareSafeArrays(parray, saSrc.parray);
  2541. }
  2542.  
  2543. BOOL COleSafeArray::operator==(const VARIANT& varSrc) const
  2544. {
  2545.     if (vt != varSrc.vt)
  2546.         return FALSE;
  2547.  
  2548.     return CompareSafeArrays(parray, varSrc.parray);
  2549. }
  2550.  
  2551. BOOL COleSafeArray::operator==(LPCVARIANT pSrc) const
  2552. {
  2553.     if (vt != pSrc->vt)
  2554.         return FALSE;
  2555.  
  2556.     return CompareSafeArrays(parray, pSrc->parray);
  2557. }
  2558.  
  2559. BOOL COleSafeArray::operator==(const COleVariant& varSrc) const
  2560. {
  2561.     if (vt != varSrc.vt)
  2562.         return FALSE;
  2563.  
  2564.     return CompareSafeArrays(parray, varSrc.parray);
  2565. }
  2566.  
  2567. void COleSafeArray::CreateOneDim(VARTYPE vtSrc, DWORD dwElements,
  2568.     void* pvSrcData, long nLBound)
  2569. {
  2570.     ASSERT(dwElements > 0);
  2571.  
  2572.     // Setup the bounds and create the array
  2573.     SAFEARRAYBOUND rgsabound;
  2574.     rgsabound.cElements = dwElements;
  2575.     rgsabound.lLbound = nLBound;
  2576.     Create(vtSrc, 1, &rgsabound);
  2577.  
  2578.     // Copy over the data if neccessary
  2579.     if (pvSrcData != NULL)
  2580.     {
  2581.         void* pvDestData;
  2582.         AccessData(&pvDestData);
  2583.         memcpy(pvDestData, pvSrcData, GetElemSize() * dwElements);
  2584.         UnaccessData();
  2585.     }
  2586. }
  2587.  
  2588. DWORD COleSafeArray::GetOneDimSize()
  2589. {
  2590.     ASSERT(GetDim() == 1);
  2591.  
  2592.     long nUBound, nLBound;
  2593.  
  2594.     GetUBound(1, &nUBound);
  2595.     GetLBound(1, &nLBound);
  2596.  
  2597.     return nUBound + 1 - nLBound;
  2598. }
  2599.  
  2600. void COleSafeArray::ResizeOneDim(DWORD dwElements)
  2601. {
  2602.     ASSERT(GetDim() == 1);
  2603.  
  2604.     SAFEARRAYBOUND rgsabound;
  2605.  
  2606.     rgsabound.cElements = dwElements;
  2607.     rgsabound.lLbound = 0;
  2608.  
  2609.     Redim(&rgsabound);
  2610. }
  2611.  
  2612. void COleSafeArray::Create(VARTYPE vtSrc, DWORD dwDims, DWORD* rgElements)
  2613. {
  2614.     ASSERT(rgElements != NULL);
  2615.  
  2616.     // Allocate and fill proxy array of bounds (with lower bound of zero)
  2617.     SAFEARRAYBOUND* rgsaBounds = new SAFEARRAYBOUND[dwDims];
  2618.  
  2619.     for (DWORD dwIndex = 0; dwIndex < dwDims; dwIndex++)
  2620.     {
  2621.         // Assume lower bound is 0 and fill in element count
  2622.         rgsaBounds[dwIndex].lLbound = 0;
  2623.         rgsaBounds[dwIndex].cElements = rgElements[dwIndex];
  2624.     }
  2625.  
  2626.     TRY
  2627.     {
  2628.         Create(vtSrc, dwDims, rgsaBounds);
  2629.     }
  2630.     CATCH_ALL(e)
  2631.     {
  2632.         // Must free up memory
  2633.         delete [] rgsaBounds;
  2634.         THROW_LAST();
  2635.     }
  2636.     END_CATCH_ALL
  2637.  
  2638.     delete [] rgsaBounds;
  2639. }
  2640.  
  2641. void COleSafeArray::Create(VARTYPE vtSrc, DWORD dwDims, SAFEARRAYBOUND* rgsabound)
  2642. {
  2643.     ASSERT(dwDims > 0);
  2644.     ASSERT(rgsabound != NULL);
  2645.  
  2646.     // Validate the VARTYPE for SafeArrayCreate call
  2647.     ASSERT(!(vtSrc & VT_ARRAY));
  2648.     ASSERT(!(vtSrc & VT_BYREF));
  2649.     ASSERT(!(vtSrc & VT_VECTOR));
  2650.     ASSERT(vtSrc != VT_EMPTY);
  2651.     ASSERT(vtSrc != VT_NULL);
  2652.  
  2653.     // Free up old safe array if necessary
  2654.     Clear();
  2655.  
  2656.     parray = ::SafeArrayCreate(vtSrc, dwDims, rgsabound);
  2657.  
  2658.     if (parray == NULL)
  2659.         AfxThrowMemoryException();
  2660.  
  2661.     vt = unsigned short(vtSrc | VT_ARRAY);
  2662.     m_dwDims = dwDims;
  2663.     m_dwElementSize = GetElemSize();
  2664. }
  2665.  
  2666. void COleSafeArray::AccessData(void** ppvData)
  2667. {
  2668.     CheckError(::SafeArrayAccessData(parray, ppvData));
  2669. }
  2670.  
  2671. void COleSafeArray::UnaccessData()
  2672. {
  2673.     CheckError(::SafeArrayUnaccessData(parray));
  2674. }
  2675.  
  2676. void COleSafeArray::AllocData()
  2677. {
  2678.     CheckError(::SafeArrayAllocData(parray));
  2679. }
  2680.  
  2681. void COleSafeArray::AllocDescriptor(DWORD dwDims)
  2682. {
  2683.     CheckError(::SafeArrayAllocDescriptor(dwDims, &parray));
  2684. }
  2685.  
  2686. void COleSafeArray::Copy(LPSAFEARRAY* ppsa)
  2687. {
  2688.     CheckError(::SafeArrayCopy(parray, ppsa));
  2689. }
  2690.  
  2691. void COleSafeArray::GetLBound(DWORD dwDim, long* pLbound)
  2692. {
  2693.     CheckError(::SafeArrayGetLBound(parray, dwDim, pLbound));
  2694. }
  2695.  
  2696. void COleSafeArray::GetUBound(DWORD dwDim, long* pUbound)
  2697. {
  2698.     CheckError(::SafeArrayGetUBound(parray, dwDim, pUbound));
  2699. }
  2700.  
  2701. void COleSafeArray::GetElement(long* rgIndices, void* pvData)
  2702. {
  2703.     CheckError(::SafeArrayGetElement(parray, rgIndices, pvData));
  2704. }
  2705.  
  2706. void COleSafeArray::PtrOfIndex(long* rgIndices, void** ppvData)
  2707. {
  2708.     CheckError(::SafeArrayPtrOfIndex(parray, rgIndices, ppvData));
  2709. }
  2710.  
  2711. void COleSafeArray::PutElement(long* rgIndices, void* pvData)
  2712. {
  2713.     CheckError(::SafeArrayPutElement(parray, rgIndices, pvData));
  2714. }
  2715.  
  2716. void COleSafeArray::Redim(SAFEARRAYBOUND* psaboundNew)
  2717. {
  2718.     CheckError(::SafeArrayRedim(parray, psaboundNew));
  2719. }
  2720.  
  2721. void COleSafeArray::Lock()
  2722. {
  2723.     CheckError(::SafeArrayLock(parray));
  2724. }
  2725.  
  2726. void COleSafeArray::Unlock()
  2727. {
  2728.     CheckError(::SafeArrayUnlock(parray));
  2729. }
  2730.  
  2731. void COleSafeArray::Destroy()
  2732. {
  2733.     CheckError(::SafeArrayDestroy(parray));
  2734. }
  2735.  
  2736. void COleSafeArray::DestroyData()
  2737. {
  2738.     CheckError(::SafeArrayDestroyData(parray));
  2739. }
  2740.  
  2741. void COleSafeArray::DestroyDescriptor()
  2742. {
  2743.     CheckError(::SafeArrayDestroyDescriptor(parray));
  2744. }
  2745.  
  2746. ///////////////////////////////////////////////////////////////////////////////
  2747. // COleSafeArray Helpers
  2748. void AFXAPI AfxSafeArrayInit(COleSafeArray* psa)
  2749. {
  2750.     memset(psa, 0, sizeof(*psa));
  2751. }
  2752.  
  2753. /////////////////////////////////////////////////////////////////////////////
  2754. // Simple field formatting to text item - see dlgdata.cpp for base types
  2755. void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, COleDateTime& value)
  2756. {
  2757.     HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
  2758.     if (pDX->m_bSaveAndValidate)
  2759.     {
  2760.         int nLen = ::GetWindowTextLength(hWndCtrl);
  2761.         CString strTemp;
  2762.  
  2763.         ::GetWindowText(hWndCtrl, strTemp.GetBufferSetLength(nLen), nLen+1);
  2764.         strTemp.ReleaseBuffer();
  2765.  
  2766.         if (!value.ParseDateTime(strTemp))  // throws exception
  2767.         {
  2768.             // Can't convert string to datetime
  2769.             AfxMessageBox(AFX_IDP_PARSE_DATETIME);
  2770.             pDX->Fail();    // throws exception
  2771.         }
  2772.     }
  2773.     else
  2774.     {
  2775.         CString strTemp = value.Format();
  2776.         AfxSetWindowText(hWndCtrl, strTemp);
  2777.     }
  2778. }
  2779.  
  2780. void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, COleCurrency& value)
  2781. {
  2782.     HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
  2783.     if (pDX->m_bSaveAndValidate)
  2784.     {
  2785.         int nLen = ::GetWindowTextLength(hWndCtrl);
  2786.         CString strTemp;
  2787.  
  2788.         ::GetWindowText(hWndCtrl, strTemp.GetBufferSetLength(nLen), nLen+1);
  2789.         strTemp.ReleaseBuffer();
  2790.  
  2791.         if (!value.ParseCurrency(strTemp))  // throws exception
  2792.         {
  2793.             // Can't convert string to currency
  2794.             AfxMessageBox(AFX_IDP_PARSE_CURRENCY);
  2795.             pDX->Fail();    // throws exception
  2796.         }
  2797.     }
  2798.     else
  2799.     {
  2800.         CString strTemp = value.Format();
  2801.         AfxSetWindowText(hWndCtrl, strTemp);
  2802.     }
  2803. }
  2804.  
  2805. /////////////////////////////////////////////////////////////////////////////
  2806.