home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / wcedb.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  34.3 KB  |  1,462 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 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.  
  13. #include "wcedb.h"
  14.  
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[]=__FILE__;
  18. #define new DEBUG_NEW
  19. #endif
  20.  
  21. // The propid's HIWORD is the application-defined identifier (ident)
  22. // The propid's LOWORD is the datatype (CEVT_* values)
  23.  
  24. inline void SET_PROPID_CEVT(CEPROPID& propid,WORD wType)
  25. {
  26.     propid = MAKELONG(wType,HIWORD(propid));
  27. }
  28.  
  29. inline WORD GET_PROPID_CEVT(CEPROPID propid) 
  30. {
  31.     return LOWORD(propid);
  32. }
  33.  
  34. inline void SET_PROPID_IDENT(CEPROPID& propid,WORD wIdent)
  35. {
  36.     propid = MAKELONG(LOWORD(propid),wIdent);
  37. }
  38.  
  39. inline WORD GET_PROPID_IDENT(CEPROPID propid) 
  40. {
  41.     return HIWORD(propid);
  42. }
  43.  
  44. inline CEPROPID MAKE_PROPID(WORD wType,WORD wIndent)
  45. {
  46.     return MAKELONG(wType,wIndent);
  47. }
  48.  
  49. //////////////////////////////////////////////////////////////////////
  50. // CCeDBDatabase construction/Destruction
  51. //////////////////////////////////////////////////////////////////////
  52.  
  53. CCeDBDatabase::CCeDBDatabase()
  54. {
  55.     m_CEOID  = NULL;
  56.     m_hHandle = INVALID_HANDLE_VALUE;
  57.     m_bAutoSeekNext = FALSE;
  58.     m_bEOF = FALSE; // maintained via SeekNext() (so you should set
  59.                     // m_bAutoSeekNext if you want to use EOF() when 
  60.                     // reading records in sequentially)
  61. }
  62.  
  63.  
  64. CCeDBDatabase::~CCeDBDatabase()
  65. {
  66.     if(m_hHandle != INVALID_HANDLE_VALUE)
  67.         Close();
  68. }
  69.  
  70. //////////////////////////////////////////////////////////////////////
  71.  
  72.  
  73. //////////////////////////////////////////////////////////////////////
  74. // Basic operations
  75. //////////////////////////////////////////////////////////////////////
  76.  
  77. CEOID CCeDBDatabase::Create(LPCWSTR szName,
  78.                               DWORD dwIdent /*= 0*/,
  79.                               int nNumSortProps /*= 0*/,
  80.                               const CCeDBProp* pSortProps /*= NULL*/)
  81. {
  82.     AssertValidDbaseName(szName);  
  83.     ASSERT(m_hHandle == INVALID_HANDLE_VALUE);
  84.     ASSERT((nNumSortProps >= 0) && (nNumSortProps <= 4));
  85.     if(nNumSortProps == 0)
  86.         m_CEOID = CeCreateDatabase((LPWSTR)szName,dwIdent,0,NULL); 
  87.     else
  88.     {
  89.         ASSERT(pSortProps != NULL);
  90.         int i;
  91.  
  92.     // The WinCE database doesn't allow multiple sort keys on a single property,
  93.     // so check for it
  94. #ifdef _DEBUG
  95.         for(i=0; i < nNumSortProps-1; i++)
  96.             for(int j=i+1; j < nNumSortProps; j++)
  97.                 if(pSortProps[i].GetIdent() == pSortProps[j].GetIdent())
  98.                     ASSERT(FALSE); // A single property appeared more than once in the sort order!
  99. #endif
  100.  
  101.         SORTORDERSPEC Spec[4];
  102.         for(i=0; i < nNumSortProps; i++)
  103.         {
  104.             Spec[i].propid = pSortProps[i].GetPropid();
  105.             Spec[i].dwFlags = (DWORD)pSortProps[i].m_wSortFlags;
  106.         }
  107.  
  108.         WORD wCnt = (WORD)nNumSortProps;
  109.         m_CEOID = CeCreateDatabase((LPWSTR)szName,dwIdent,wCnt,Spec); 
  110.     }
  111.     
  112.     return m_CEOID;
  113. }
  114.  
  115.  
  116.  
  117. BOOL CCeDBDatabase::Open(CEOID CeOID,
  118.                           const CCeDBProp* pKeyProp /*= NULL*/, 
  119.                           const CWnd* pWndNotify /*= NULL*/)
  120. {
  121.     HWND hWnd;
  122.     CEPROPID propid = pKeyProp?pKeyProp->GetPropid():0;
  123.  
  124.     ASSERT(m_hHandle == INVALID_HANDLE_VALUE);
  125.  
  126.     if(pWndNotify == NULL)
  127.         hWnd = NULL;
  128.     else
  129.     {
  130. #ifdef _DEBUG
  131.         pWndNotify->AssertValid();
  132. #endif
  133.         hWnd = pWndNotify->GetSafeHwnd();
  134.     }
  135.  
  136.     m_CEOID = CeOID;
  137.     m_bEOF = FALSE;
  138.     m_hHandle = CeOpenDatabase(&m_CEOID,NULL,propid,0,hWnd);
  139.     return (m_hHandle != INVALID_HANDLE_VALUE);
  140. }
  141.  
  142.  
  143. BOOL CCeDBDatabase::Open(LPCWSTR szName,
  144.                           const CCeDBProp* pKeyProp /*= NULL*/, 
  145.                           const CWnd* pWndNotify /*= NULL*/)
  146. {
  147.     CEPROPID propid = pKeyProp?pKeyProp->GetPropid():0;
  148.     HWND hWnd;
  149.  
  150.     ASSERT(m_hHandle == INVALID_HANDLE_VALUE);
  151.  
  152.     if(pWndNotify == NULL)
  153.         hWnd = NULL;
  154.     else
  155.     {
  156. #ifdef _DEBUG
  157.         pWndNotify->AssertValid();
  158. #endif
  159.         hWnd = pWndNotify->GetSafeHwnd();
  160.     }
  161.     m_CEOID = 0;
  162.     m_bEOF = FALSE;
  163.     m_hHandle = CeOpenDatabase(&m_CEOID,(LPWSTR)szName,propid,0,hWnd);
  164.     return (m_hHandle != INVALID_HANDLE_VALUE);
  165. }
  166.  
  167.  
  168. BOOL CCeDBDatabase::Close() // Note, closing is optional, since the
  169.                            // destructor calls this automatically.
  170. {
  171.     if(m_hHandle == INVALID_HANDLE_VALUE)
  172.         return FALSE;
  173.  
  174.     if(!CloseHandle(m_hHandle))
  175.         return FALSE;
  176.  
  177.     m_hHandle = INVALID_HANDLE_VALUE;
  178.     return TRUE;
  179. }
  180.  
  181. BOOL CCeDBDatabase::Delete() // Note, we might want to make this a static function instead.
  182.                               // It's silly to open it, then delete it, but then again, we 
  183.                               // can take advantage of ref by name.
  184. {
  185.     ASSERT(m_CEOID != NULL);
  186.  
  187.     Close();
  188.  
  189.     if(!CeDeleteDatabase(m_CEOID))
  190.         return FALSE;
  191.  
  192.     m_CEOID = FALSE;
  193.     return TRUE;
  194. }
  195.  
  196. //////////////////////////////////////////////////////////////////////
  197.  
  198.  
  199.  
  200. //////////////////////////////////////////////////////////////////////
  201. // Static information functions (i.e. no open database used)
  202. //////////////////////////////////////////////////////////////////////
  203.  
  204. BOOL CCeDBDatabase::Exists(LPCWSTR szName)
  205. {
  206.     AssertValidDbaseName(szName);
  207.     
  208.     CEOID CeOID = NULL;
  209.  
  210.     // Note: this is a hack because we actually try to open it
  211.     // instead of using an existence function (I'm not sure if
  212.     // it exists.)
  213.     HANDLE hHandle = CeOpenDatabase(&CeOID,(LPWSTR)szName,0,0,NULL);
  214.  
  215.     // Need to find out what POD does when you give it a valid
  216.     // CeOID that is NOT a database.  If so, return FALSE.
  217.  
  218.     // Otherwise, this "hack" created a new resource, get rid of it
  219.     if(hHandle != INVALID_HANDLE_VALUE)
  220.     {
  221.         CloseHandle(hHandle); // not concerned about failure here
  222.         return TRUE;
  223.     }
  224.  
  225.     if(::GetLastError() == ERROR_FILE_NOT_FOUND)
  226.         return FALSE;
  227.  
  228.     // ASSUMPTION NOTE:
  229.     // The other expected error is ERROR_NOT_ENOUGH_MEMORY,
  230.     // we are assuming that the file exists in this case, i.e.
  231.     // CeOpenDatabase() DID find a file, BUT couldn't open it.
  232.  
  233.     return TRUE;
  234. }
  235.  
  236.  
  237.  
  238. BOOL CCeDBDatabase::Exists(CEOID CeOID)
  239. {
  240.     ASSERT(CeOID != NULL);
  241.  
  242.     // Note: this is a hack because we actually try to open it
  243.     // instead of using an existence function (I'm not sure if
  244.     // it exists.)
  245.     HANDLE hHandle = CeOpenDatabase(&CeOID,NULL,0,0,NULL);
  246.  
  247.     // Need to find out what POD does when you give it a valid
  248.     // CeOID that is NOT a database.  If so, return FALSE.
  249.  
  250.     // Otherwise, this "hack" created a new resource, get rid of it
  251.     if(hHandle != INVALID_HANDLE_VALUE)
  252.     {
  253.         CloseHandle(hHandle); // not concerned about failure here
  254.         return TRUE;
  255.     }
  256.  
  257.     if(::GetLastError() == ERROR_FILE_NOT_FOUND)
  258.         return FALSE;
  259.  
  260.     // ASSUMPTION NOTE:
  261.     // The other expected error is ERROR_NOT_ENOUGH_MEMORY,
  262.     // we are assuming that the file exists in this case, i.e.
  263.     // CeOpenDatabase() DID find a file, BUT couldn't open it.
  264.  
  265.     return FALSE;
  266. }
  267.  
  268. //////////////////////////////////////////////////////////////////////
  269.  
  270.  
  271.  
  272. //////////////////////////////////////////////////////////////////////
  273. // Database enumeration
  274. //////////////////////////////////////////////////////////////////////
  275.  
  276. CCeDBEnum::CCeDBEnum(DWORD dwIdent /*= 0*/)
  277. {
  278.     m_hHandle = CeFindFirstDatabase(dwIdent);
  279. }
  280.  
  281. CEOID CCeDBEnum::Next()
  282. {
  283.     if(m_hHandle == INVALID_HANDLE_VALUE)
  284.         return FALSE;
  285.  
  286.     return CeFindNextDatabase(m_hHandle);
  287. }
  288.  
  289. CCeDBEnum::~CCeDBEnum()
  290. {
  291.     if(m_hHandle != INVALID_HANDLE_VALUE)
  292.         CloseHandle(m_hHandle); 
  293. }
  294.  
  295. //////////////////////////////////////////////////////////////////////
  296.  
  297.  
  298.  
  299.  
  300. //////////////////////////////////////////////////////////////////////
  301. // Read/write/delete operations 
  302. //////////////////////////////////////////////////////////////////////
  303.  
  304. // O(1)
  305. BOOL CCeDBDatabase::ReadCurrRecord(CCeDBRecord* pRecord,
  306.                                       int nNumFilterProps /*= 0*/,
  307.                                      CCeDBProp* PropFilterArray /*= NULL*/)
  308. {
  309.     AssertValid();
  310.  
  311.     if(m_bAutoSeekNext && m_bEOF)
  312.     {
  313.         ::SetLastError(ERROR_HANDLE_EOF);
  314.         return FALSE; // no more records to read
  315.     }
  316.  
  317.     CEOID CeOID;
  318.     DWORD dwSize;
  319.     CEPROPID* inputPropIDArray = NULL;
  320.  
  321.     if(nNumFilterProps > 0)
  322.     {
  323.         TRY
  324.         {
  325.             inputPropIDArray = new CEPROPID[nNumFilterProps];
  326.         }
  327.         CATCH(CException,e)
  328.         {
  329.             ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  330.             return FALSE;
  331.         }
  332.         END_CATCH;
  333.  
  334.         for(int nCnt=0; nCnt < nNumFilterProps; nCnt++)
  335.             inputPropIDArray[nCnt] = PropFilterArray[nCnt].GetPropid(); 
  336.     }
  337.  
  338.     pRecord->FreeRecord();   // clear up this record before filling in again...
  339.                              // this will delete strings and blobs used by
  340.                              // the current properties in this record
  341.     
  342.     WORD wNumPropIdents = (WORD)nNumFilterProps;
  343.  
  344.     // NOTE: this will return the last record even if the seek has gone off the edge.
  345.  
  346.     CeOID = CeReadRecordProps(m_hHandle,CEDB_ALLOWREALLOC,
  347.                                 &wNumPropIdents,inputPropIDArray,
  348.                                 &pRecord->m_pbBuffer,&dwSize);
  349.  
  350.     int nNumProps = (int)wNumPropIdents;
  351.  
  352.     if(CeOID != NULL)
  353.     {
  354.         CEPROPVAL* PropValArray = (CEPROPVAL*)pRecord->m_pbBuffer;
  355.         CCeDBProp* pProp;
  356.         for(int n=0; n < (int)nNumProps; n++)
  357.         {
  358.             pProp = new CCeDBProp;
  359.             *pProp = CCeDBProp(PropValArray[n],CCeDBProp::NoCopy);
  360.             pProp->m_bDeletePtr = TRUE;
  361.             pRecord->AddProp(pProp);
  362.         }
  363.  
  364.         // Note: lpwstr and blob properties point into pRecord->m_pbBuffer.
  365.         // That was why we passed in CCePDBProp::NoCopy.  The record
  366.         // will free up the buffer when destructed or when Free() is called.
  367.  
  368.         if(m_bAutoSeekNext)
  369.             SeekNext();
  370.     }
  371.  
  372.     if(inputPropIDArray != NULL)
  373.         delete[] inputPropIDArray;
  374.  
  375.     return (CeOID != NULL);
  376. }
  377.  
  378.  
  379.  
  380.  
  381. // private function that implements the above.
  382.  
  383. BOOL CCeDBDatabase::WriteRecordProps(CCeDBRecord *pRecord,
  384.                                       int nMode /*= CCeDBDatabase::ModifyProps*/,
  385.                                        int nNumFilterProps /*= 0*/, 
  386.                                       CCeDBProp *PropFilterArray /*= NULL*/)
  387. {
  388.     AssertValid();
  389.  
  390.     CEOID CeOID;
  391.     CEPROPVAL* inputPropValArray = NULL;
  392.     BOOL bAll = FALSE;
  393.     int nNumRecordPropsAvail = pRecord->m_pPropArray.GetSize();
  394.     CCeDBProp* pProp;
  395.  
  396.     if(nNumFilterProps == 0) // zero means all
  397.     {
  398.         nNumFilterProps = nNumRecordPropsAvail;
  399.         bAll = TRUE;
  400.  
  401.         if(nNumFilterProps == 0)
  402.         {
  403.             ::SetLastError(ERROR_NO_DATA);
  404.             return FALSE;
  405.         }
  406.     }
  407.  
  408.     TRY
  409.     {
  410.         inputPropValArray = new CEPROPVAL[nNumFilterProps];
  411.     }
  412.     CATCH(CException,e)
  413.     {
  414.         ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  415.         return FALSE;
  416.     }
  417.     END_CATCH;
  418.  
  419.  
  420.     if(bAll)
  421.     {
  422.         for(int nCnt1=0; nCnt1 < (int)nNumFilterProps; nCnt1++)
  423.         {
  424.             pProp = pRecord->GetPropFromIndex(nCnt1);
  425.             CEPROPID propid = pProp->m_CePropVal.propid;
  426.             inputPropValArray[nCnt1] = pProp->m_CePropVal;
  427.         }
  428.     }
  429.     else
  430.     {
  431.         ASSERT(PropFilterArray != NULL);
  432.  
  433.         int nSkip = 0;
  434.         for(int nCnt1=0; nCnt1 < nNumFilterProps; nCnt1++)
  435.         {
  436.             for(int nCnt2=0; nCnt2 < nNumRecordPropsAvail; nCnt2++)
  437.             {
  438.                 pProp = pRecord->GetPropFromIndex(nCnt2);
  439.                 if(GET_PROPID_IDENT(PropFilterArray[nCnt1].m_CePropVal.propid) == 
  440.                    GET_PROPID_IDENT(pProp->m_CePropVal.propid))
  441.                 {
  442.                     inputPropValArray[nCnt1-nSkip] = pProp->m_CePropVal;
  443.                     break;
  444.                 }
  445.             }
  446.  
  447.             if(nCnt2 == nNumRecordPropsAvail) // requested ident not in record, so inc. skip
  448.                 nSkip++;
  449.         }
  450.  
  451.         nNumFilterProps -= nSkip; // adjust for skipped idents
  452.     }
  453.  
  454.  
  455.     if(nNumFilterProps == 0)
  456.     {
  457.         ::SetLastError(ERROR_NO_DATA);
  458.         delete[] inputPropValArray;
  459.         return FALSE;
  460.     }
  461.  
  462.     if(nMode == NewRecord)
  463.     {
  464.         CeOID = CeWriteRecordProps(m_hHandle,0,(WORD)nNumFilterProps,inputPropValArray);
  465.     }
  466.     else
  467.     {
  468.         if(nMode == DeleteProps)
  469.         {
  470.             for(int nCnt=0; nCnt < nNumFilterProps; nCnt++)
  471.                 inputPropValArray[nCnt].wFlags = CEDB_PROPDELETE;
  472.         }
  473.  
  474.         CeOID = CeWriteRecordProps(m_hHandle,GetCurrRecord(),
  475.                                      (WORD)nNumFilterProps,inputPropValArray);
  476.         if(nMode == DeleteProps)
  477.             ASSERT(CeOID == GetCurrRecord());
  478.     }
  479.  
  480.     
  481.     if(CeOID != NULL)
  482.     {
  483.         if(m_bAutoSeekNext)
  484.             SeekNext();
  485.     }
  486.  
  487.     if(inputPropValArray != NULL)
  488.         delete[] inputPropValArray;
  489.  
  490.     return (CeOID != NULL);
  491. }
  492.  
  493.  
  494. BOOL CCeDBDatabase::DeleteCurrRecordProps(int nNumProps /*= 0*/,
  495.                                            CCeDBProp *pPropArray /*= NULL*/)
  496. {
  497.     BOOL bRetVal;
  498.  
  499.     CCeDBRecord rec;    
  500.  
  501.     if(!ReadCurrRecord(&rec))  // inefficient
  502.         return FALSE;
  503.  
  504.     if(nNumProps == 0) // zero properties means delete all, so find out the properties. 
  505.     {                  // note: this is pretty inefficient
  506.  
  507.         nNumProps = rec.GetNumProps();
  508.         if(nNumProps == 0) // shouldn't occur!
  509.             return TRUE; // go ahead and say, yeah I'm okay
  510.  
  511.         TRY
  512.         {
  513.             pPropArray = new CCeDBProp[nNumProps];
  514.         }
  515.         CATCH(CException,e)
  516.         {
  517.             ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  518.             return FALSE;
  519.         }
  520.         END_CATCH;
  521.  
  522.         for(int n=0; n < nNumProps; n++)
  523.             pPropArray[n] = *rec.GetPropFromIndex(n);
  524.  
  525.         bRetVal = WriteRecordProps(&rec,DeleteProps,nNumProps,pPropArray);
  526.         delete[] pPropArray;
  527.     }
  528.     else
  529.     {
  530.         bRetVal = WriteRecordProps(&rec,DeleteProps,nNumProps,pPropArray);
  531.     }
  532.  
  533.     return bRetVal;
  534. }
  535.  
  536.  
  537.  
  538. //////////////////////////////////////////////////////////////////////
  539. // Queries 
  540. //////////////////////////////////////////////////////////////////////
  541.  
  542. // Note: AssertValid() is only needed in GetInfo() and SetInfo(), as
  543. // the other Get and Set methods call them.
  544.  
  545. CEDBASEINFO CCeDBDatabase::GetInfo(BOOL* pbOK) const
  546. {
  547.     AssertValid();
  548.  
  549.     CEOIDINFO CeObjectInfo;
  550.  
  551.     if(!CeOidGetInfo(m_CEOID,&CeObjectInfo))
  552.     {
  553.         *pbOK = FALSE;
  554.         memset(&CeObjectInfo.infDatabase,0,sizeof(CeObjectInfo.infDatabase));
  555.         return CeObjectInfo.infDatabase;
  556.     }
  557.     
  558.     ASSERT(CeObjectInfo.wObjType == OBJTYPE_DATABASE);
  559.  
  560.     *pbOK = TRUE;
  561.  
  562.     return CeObjectInfo.infDatabase;
  563. }
  564.  
  565. BOOL CCeDBDatabase::SetInfo(const CEDBASEINFO* pCeDBaseInfo)
  566. {
  567.     AssertValid();
  568.  
  569.     return CeSetDatabaseInfo(m_CEOID,(CEDBASEINFO*)pCeDBaseInfo);
  570. }
  571.  
  572.  
  573.  
  574. WORD CCeDBDatabase::GetNumRecords() const   
  575.     BOOL bOk;
  576.     return GetInfo(&bOk).wNumRecords;    
  577. }
  578.  
  579. // No SetNumRecords() counterpart
  580.  
  581. DWORD CCeDBDatabase::GetSize() const         
  582.     BOOL bOk;
  583.     return GetInfo(&bOk).dwSize;         
  584. }
  585.  
  586. // No SetSize() counterpart
  587.  
  588.  
  589. void CCeDBDatabase::GetName(LPWSTR szName) const         
  590.     BOOL bOK;
  591.     wcscpy(szName,GetInfo(&bOK).szDbaseName);
  592. }
  593.  
  594. BOOL CCeDBDatabase::SetName(LPCWSTR wszName)
  595. {
  596.     AssertValidDbaseName(wszName);
  597.  
  598.     CEDBASEINFO CeDBaseInfo;
  599.     memset(&CeDBaseInfo,0,sizeof(CeDBaseInfo));
  600.     wcsncpy(CeDBaseInfo.szDbaseName,wszName,CEDB_MAXDBASENAMELEN);
  601.     CeDBaseInfo.dwFlags = CEDB_VALIDNAME;
  602.  
  603.     return SetInfo(&CeDBaseInfo);
  604. }
  605.  
  606.  
  607. DWORD CCeDBDatabase::GetIdent() const
  608.     BOOL bOK;
  609.     return GetInfo(&bOK).dwDbaseType;
  610. }
  611.  
  612. BOOL CCeDBDatabase::SetIdent(DWORD dwIdent)
  613. {
  614.     CEDBASEINFO CeDBaseInfo;
  615.     memset(&CeDBaseInfo,0,sizeof(CeDBaseInfo));
  616.     CeDBaseInfo.dwDbaseType = dwIdent;
  617.     CeDBaseInfo.dwFlags = CEDB_VALIDTYPE;
  618.  
  619.     return SetInfo(&CeDBaseInfo);
  620. }
  621.  
  622.  
  623. FILETIME CCeDBDatabase::GetLastModified() const
  624.     BOOL bOK;
  625.     return GetInfo(&bOK).ftLastModified; 
  626. }
  627.  
  628. BOOL CCeDBDatabase::SetLastModified(FILETIME ftLastModified) 
  629. {
  630.     CEDBASEINFO CeDBaseInfo;
  631.     memset(&CeDBaseInfo,0,sizeof(CeDBaseInfo));
  632.     
  633.     CeDBaseInfo.ftLastModified = ftLastModified;
  634.     CeDBaseInfo.dwFlags = CEDB_VALIDMODTIME;
  635.  
  636.     return SetInfo(&CeDBaseInfo);
  637. }
  638.  
  639.  
  640.  
  641. // Note: pSortProps is assumed to be an array of at least CEDB_MAXSORTORDER elements!
  642. void CCeDBDatabase::GetSortProps(int *pnNumProps,CCeDBProp *pSortProps) const
  643. {
  644.     ASSERT(pnNumProps != NULL);
  645.     ASSERT(pSortProps != NULL);
  646.     
  647.     BOOL bOK;
  648.     CEDBASEINFO dbInfo = GetInfo(&bOK);
  649.     if(!bOK)
  650.     {
  651.         *pnNumProps = 0;
  652.         return;
  653.     }
  654.  
  655.     SORTORDERSPEC *pSpec;
  656.  
  657.     *pnNumProps = (int)dbInfo.wNumSortOrder;
  658.     ASSERT((*pnNumProps >= 0) && (*pnNumProps <= CEDB_MAXSORTORDER));
  659.  
  660.     for(int i=0; i < *pnNumProps; i++)
  661.     {
  662.         pSpec = &dbInfo.rgSortSpecs[i];
  663.         pSortProps[i] = CCeDBProp(CCeDBProp::CEVTtoType(GET_PROPID_CEVT(pSpec->propid)),
  664.                                    GET_PROPID_IDENT(pSpec->propid),
  665.                                    (WORD)pSpec->dwFlags);
  666.     }
  667.  
  668.  
  669. BOOL CCeDBDatabase::SetSortProps(int nNumProps,const CCeDBProp *pSortProps)
  670. {
  671.     ASSERT((nNumProps >= 0) && (nNumProps <= CEDB_MAXSORTORDER));
  672.     
  673.     CEDBASEINFO CeDBaseInfo;
  674.     int i;
  675.  
  676.     CeDBaseInfo.dwFlags       = CEDB_VALIDSORTSPEC;
  677.     CeDBaseInfo.wNumSortOrder = (WORD)nNumProps;
  678.  
  679.     if(nNumProps >= 0)
  680.         ASSERT(pSortProps != NULL);
  681.  
  682.     // The WinCE database doesn't allow multiple sort keys on a single property,
  683.     // so check for it
  684. #ifdef _DEBUG
  685.     for(i=0; i < nNumProps-1; i++)
  686.         for(int j=i+1; j < nNumProps; j++)
  687.             if(pSortProps[i].GetIdent() == pSortProps[j].GetIdent())
  688.                 ASSERT(FALSE); // A single property appeared more than once in the sort order!
  689. #endif
  690.  
  691.     for(i=0; i < nNumProps; i++)
  692.     {
  693.         CeDBaseInfo.rgSortSpecs[i].propid = pSortProps[i].GetPropid();
  694.         CeDBaseInfo.rgSortSpecs[i].dwFlags = (DWORD)pSortProps[i].m_wSortFlags;
  695.     }
  696.  
  697.     return SetInfo(&CeDBaseInfo);
  698. }
  699.  
  700. //////////////////////////////////////////////////////////////////////
  701.  
  702.  
  703. //////////////////////////////////////////////////////////////////////
  704. // Seeking operations
  705. //////////////////////////////////////////////////////////////////////
  706.  
  707.  
  708. // Note: the only seek operation that sets m_bEOF to TRUE is SeekNext(),
  709. // when it is unsuccessful.
  710. // m_bEOF is set to FALSE on all seek operations that are successful.
  711.  
  712. // O(dwIndex) if bFromEnd == FALSE, O(n) if bfromEnd == TRUE
  713. CEOID CCeDBDatabase::SeekToIndex(DWORD dwIndex,BOOL bFromEnd /*= FALSE*/) 
  714. {
  715.     AssertValid();
  716.  
  717.     DWORD dwNewIndex;
  718.     CEOID NewCeOID;
  719.     
  720.     if(bFromEnd)
  721.     {
  722.         NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_END,-(signed long)dwIndex,&dwNewIndex);
  723.     }
  724.     else
  725.     {
  726.         NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_BEGINNING,dwIndex,&dwNewIndex);
  727.         ASSERT(dwNewIndex == dwIndex);
  728.     }
  729.  
  730.     if(NewCeOID != 0)
  731.         m_bEOF = FALSE;
  732.  
  733.     return NewCeOID;
  734. }
  735.  
  736. // O(n)
  737. CEOID CCeDBDatabase::SeekToRecord(CEOID CeOID)
  738. {
  739.     AssertValid();
  740.  
  741.     DWORD dwNewIndex;
  742.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_CEOID,CeOID,&dwNewIndex);
  743.     if(NewCeOID != 0)
  744.         m_bEOF = FALSE;
  745.  
  746.     return NewCeOID; // may be zero if not found
  747. }
  748.  
  749.  
  750. // O(1)
  751. // This also maintains the EOF flag
  752. CEOID CCeDBDatabase::SeekNext()
  753. {
  754.     AssertValid();
  755.  
  756.     DWORD dwNewIndex;
  757.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_CURRENT,1,&dwNewIndex);
  758.  
  759.     m_bEOF = (NewCeOID == 0);
  760.  
  761.     return NewCeOID;
  762.  
  763. // O(n)
  764. CEOID CCeDBDatabase::SeekPrev()
  765. {
  766.     AssertValid();
  767.  
  768.     DWORD dwOldIndex,dwNewIndex;
  769.     CeSeekDatabase(m_hHandle,CEDB_SEEK_CURRENT,0,&dwOldIndex); 
  770.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_CURRENT,-1,&dwNewIndex);
  771.     if(NewCeOID != 0)
  772.         m_bEOF = FALSE;
  773.  
  774.     // Note: the behavior of CeSeekDatabase is that it doesn't go off the beginning or
  775.     // the end, but rather just stays there.  This wrapper fixes that.
  776.  
  777.     if(dwNewIndex == dwOldIndex)
  778.         return NULL;
  779.     else
  780.         return NewCeOID;
  781.  
  782.  
  783. // O(n)
  784. CEOID CCeDBDatabase::SeekFirstEqual(CCeDBProp& Prop)
  785. {
  786.     AssertValid();
  787.  
  788.     DWORD dwNewIndex;
  789.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_VALUEFIRSTEQUAL,(DWORD)&Prop.m_CePropVal,&dwNewIndex);
  790.     if(NewCeOID != 0)
  791.         m_bEOF = FALSE;
  792.     return NewCeOID;
  793. }
  794.  
  795. // O(1)
  796. CEOID CCeDBDatabase::SeekNextEqual(CCeDBProp& Prop)
  797. {
  798.     AssertValid();
  799.  
  800.     DWORD dwNewIndex;
  801.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_VALUENEXTEQUAL,(DWORD)&Prop.m_CePropVal,&dwNewIndex);
  802.     if(NewCeOID != 0)
  803.         m_bEOF = FALSE;
  804.     return NewCeOID;
  805. }
  806.  
  807. // O(n)
  808. CEOID CCeDBDatabase::SeekValueSmaller(CCeDBProp& Prop)
  809. {
  810.     AssertValid();
  811.  
  812.     DWORD dwNewIndex;
  813.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_VALUESMALLER,(DWORD)&Prop.m_CePropVal,&dwNewIndex);
  814.     if(NewCeOID != 0)
  815.         m_bEOF = FALSE;
  816.     return NewCeOID;
  817. }
  818.  
  819. // O(n)
  820. CEOID CCeDBDatabase::SeekValueGreater(CCeDBProp& Prop)
  821. {
  822.     AssertValid();
  823.  
  824.     DWORD dwNewIndex;
  825.     CEOID NewCeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_VALUEGREATER,(DWORD)&Prop.m_CePropVal,&dwNewIndex);
  826.     if(NewCeOID != 0)
  827.         m_bEOF = FALSE;
  828.     return NewCeOID;
  829. }
  830.  
  831. // O(1)
  832. DWORD CCeDBDatabase::GetCurrIndex() const
  833. {
  834.     AssertValid();
  835.  
  836.     DWORD dwCurrIndex;
  837.     CEOID CeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_CURRENT,0,&dwCurrIndex);
  838.  
  839.     if(CeOID == 0)
  840.         return (DWORD)-1;
  841.     else
  842.         return dwCurrIndex;
  843. }
  844.  
  845. // O(1)
  846. CEOID CCeDBDatabase::GetCurrRecord() const
  847. {
  848.     AssertValid();
  849.  
  850.     DWORD dwCurrIndex;
  851.     CEOID CeOID = CeSeekDatabase(m_hHandle,CEDB_SEEK_CURRENT,0,&dwCurrIndex);
  852.  
  853.     return CeOID;
  854. }
  855.  
  856.  
  857. //////////////////////////////////////////////////////////////////////
  858.  
  859.  
  860.  
  861.  
  862. //////////////////////////////////////////////////////////////////////
  863. // Diagnostics
  864. //////////////////////////////////////////////////////////////////////
  865.  
  866. void CCeDBDatabase::AssertValid() const
  867. {
  868. #ifdef _DEBUG
  869.     CObject::AssertValid();
  870. #endif
  871.     ASSERT(m_CEOID != NULL);
  872.     ASSERT(m_hHandle != INVALID_HANDLE_VALUE);
  873. }
  874.  
  875. void CCeDBDatabase::AssertValidDbaseName(LPCWSTR szName)
  876. {
  877.     int nLen = wcslen(szName);
  878.     ASSERT(nLen > 0);
  879.     ASSERT(nLen <= CEDB_MAXDBASENAMELEN-1);
  880. }
  881.  
  882. //////////////////////////////////////////////////////////////////////
  883.  
  884.  
  885.  
  886.  
  887.  
  888.  
  889.  
  890. //////////////////////////////////////////////////////////////////////
  891. // Constructors/destructor for CCeDBProp
  892. //////////////////////////////////////////////////////////////////////
  893.  
  894. // Default constructor places the value (long)0 
  895. // Note: in 32-bit Windows, long is the same as int
  896. CCeDBProp::CCeDBProp()
  897. {
  898.     m_bDeletePtr = FALSE; // assume that the user is allocating the memory for this
  899.                           // (set to TRUE if a CCeDBProp* gets added to a record and
  900.                           // it was allocated from within WCEDB.CPP)
  901.     InitProp(); // Note, all constructors need to call InitProp() first because
  902.             // each of the Set... helper functions call Delete(), which
  903.             // will free pointers.
  904.     SetLong(0);
  905. }
  906.  
  907.  
  908. // The following constructor creates valueless properties useful for
  909. // specifying sort keys.
  910. CCeDBProp::CCeDBProp(enum CCeDBProp::enType nType,WORD wIdent /*= 0*/,
  911.                        WORD wSortFlags /*= CCeDBProp::Sort_Ascending*/)
  912. {
  913.     m_bDeletePtr = FALSE; // see comment in CCeDBProp()
  914.     InitProp();
  915.     SetType(nType);
  916.     SetIdent(wIdent);
  917.     SetSortFlags(wSortFlags);
  918. };
  919.  
  920.  
  921. // The following constructor is used when reading a whole record from
  922. // the database with CeReadRecordProps(), which creates the CEPROPVAL's
  923. // with the wIdents for you.  If the CEPROPVAL doesn't have the identifier
  924. // in it, SetIdent() should be used to set it.
  925. CCeDBProp::CCeDBProp(CEPROPVAL CePropVal,enum CCeDBProp::enCopyMode nMode /*= Copy*/)
  926. {
  927.     m_bDeletePtr = FALSE;  // see comment in CCeDBProp()
  928.     InitProp();
  929.     if(CePropVal.propid == CEVT_LPWSTR)
  930.     {
  931.         SetString(CePropVal.val.lpwstr,nMode);
  932.         SetIdent(GET_PROPID_IDENT(CePropVal.propid));
  933.     }
  934.     else if(CePropVal.propid == CEVT_BLOB)
  935.     {
  936.         SetBlob(CePropVal.val.blob,nMode);
  937.         SetIdent(GET_PROPID_IDENT(CePropVal.propid));
  938.     }
  939.     else
  940.     {
  941.         m_CePropVal = CePropVal; // nMode doesn't apply
  942.     }
  943. }
  944.  
  945. CCeDBProp::CCeDBProp(short iVal,WORD wIdent /*= 0*/)
  946. {
  947.     m_bDeletePtr = FALSE;  // see comment in CCeDBProp()
  948.     InitProp();
  949.     SetShort(iVal);
  950.     SetIdent(wIdent);
  951. }
  952.  
  953. CCeDBProp::CCeDBProp(USHORT uiVal,WORD wIdent /*= 0*/)
  954. {
  955.     m_bDeletePtr = FALSE;  // see comment in CCeDBProp()
  956.     InitProp();
  957.     SetUShort(uiVal);
  958.     SetIdent(wIdent);
  959. }
  960.  
  961. CCeDBProp::CCeDBProp(long lVal,WORD wIdent /*= 0*/)
  962. {
  963.     m_bDeletePtr = FALSE; // see comment in CCeDBProp()
  964.     InitProp();
  965.     SetLong(lVal);
  966.     SetIdent(wIdent);
  967. }
  968.  
  969. CCeDBProp::CCeDBProp(ULONG ulVal,WORD wIdent /*= 0*/)
  970. {
  971.     m_bDeletePtr = FALSE;  // see comment in CCeDBProp()
  972.     InitProp();
  973.     SetULong(ulVal);
  974.     SetIdent(wIdent);
  975. }
  976.  
  977. CCeDBProp::CCeDBProp(FILETIME filetime,WORD wIdent /*= 0*/)
  978. {
  979.     m_bDeletePtr = FALSE;  // see comment in CCeDBProp()
  980.     InitProp();
  981.     SetFiletime(filetime);
  982.     SetIdent(wIdent);
  983. }
  984.  
  985. CCeDBProp::CCeDBProp(LPWSTR lpwstr,WORD wIdent /*= 0*/,enum CCeDBProp::enCopyMode nMode /*= CCeDBProp::Copy*/)
  986. {
  987.     m_bDeletePtr = FALSE;  // see comment in CCeDBProp()
  988.     ASSERT(lpwstr != NULL); // if you pass in 0, this constructor gets used.  
  989.     InitProp();
  990.     if(lpwstr != NULL)
  991.     {
  992.         SetString(lpwstr,nMode);
  993.         SetIdent(wIdent);
  994.  
  995.     }
  996. }
  997.  
  998. CCeDBProp::CCeDBProp(CEBLOB blob,WORD wIdent /*= 0*/,enum CCeDBProp::enCopyMode nMode /*= CCeDBProp::Copy*/)
  999. {
  1000.     m_bDeletePtr = FALSE;   // see comment in CCeDBProp()
  1001.     InitProp();
  1002.     SetBlob(blob,nMode);
  1003.     SetIdent(wIdent);
  1004. }
  1005.  
  1006.  
  1007. // copy constructor
  1008. CCeDBProp::CCeDBProp(CCeDBProp& prop)
  1009. {
  1010.     m_CePropVal = prop.m_CePropVal;
  1011.     m_bOwnsStringOrBlob = prop.m_bOwnsStringOrBlob; // transfer ownership to this, since prop
  1012.                                                     // is likely to be a temporary object
  1013.     m_wSortFlags = prop.m_wSortFlags;
  1014.     prop.m_bOwnsStringOrBlob = FALSE; // take away ownership from prop
  1015.     
  1016.     // m_bDeletePtr is not affected here
  1017. }
  1018.  
  1019. // assignment operator
  1020. CCeDBProp& CCeDBProp::operator=(const CCeDBProp& prop)
  1021. {
  1022.     FreeProp(); // free original object
  1023.     m_CePropVal = prop.m_CePropVal;
  1024.     m_wSortFlags = prop.m_wSortFlags;
  1025.     m_bOwnsStringOrBlob = FALSE; // leave ownership in prop 
  1026.  
  1027.     // m_bDeletePtr is not affected here
  1028.     return *this;
  1029. }
  1030.  
  1031. CCeDBProp::~CCeDBProp()
  1032. {
  1033.     FreeProp();
  1034. }
  1035.  
  1036. //////////////////////////////////////////////////////////////////////
  1037.  
  1038.  
  1039.  
  1040. //////////////////////////////////////////////////////////////////////
  1041. // Get/Set operations on CCeDBProp
  1042. //////////////////////////////////////////////////////////////////////
  1043.  
  1044.  
  1045. void CCeDBProp::SetIdent(WORD wIdent)
  1046. {
  1047.     SET_PROPID_IDENT(m_CePropVal.propid,wIdent);
  1048. }
  1049.  
  1050. WORD CCeDBProp::GetIdent() const
  1051. {
  1052.     return GET_PROPID_IDENT(m_CePropVal.propid);
  1053. }
  1054.  
  1055.  
  1056. /*private:*/ void CCeDBProp::SetCEVT(WORD wType)
  1057. {
  1058.     SET_PROPID_CEVT(m_CePropVal.propid,wType);
  1059. }
  1060.  
  1061. /*private:*/ WORD CCeDBProp::GetCEVT() const
  1062. {
  1063.     return GET_PROPID_CEVT(m_CePropVal.propid);
  1064. }
  1065.  
  1066.  
  1067. void CCeDBProp::SetType(CCeDBProp::enType nType)
  1068. {
  1069.     SET_PROPID_CEVT(m_CePropVal.propid,TypeToCEVT(nType));
  1070. }
  1071.  
  1072.  
  1073. CCeDBProp::enType CCeDBProp::GetType() const
  1074. {
  1075.     return CEVTtoType(GET_PROPID_CEVT(m_CePropVal.propid));
  1076. }
  1077.  
  1078.  
  1079. /*private: static */ CCeDBProp::enType CCeDBProp::CEVTtoType(WORD wType)
  1080. {
  1081.     if(wType == CEVT_I2)
  1082.         return CCeDBProp::Type_Short;
  1083.     else if(wType == CEVT_UI2)
  1084.         return CCeDBProp::Type_UShort;
  1085.     else if(wType == CEVT_I4)
  1086.         return CCeDBProp::Type_Long;
  1087.     else if(wType == CEVT_UI4)
  1088.         return CCeDBProp::Type_ULong;
  1089.     else if(wType == CEVT_FILETIME)
  1090.         return CCeDBProp::Type_Filetime;
  1091.     else if(wType == CEVT_LPWSTR)
  1092.         return CCeDBProp::Type_String;
  1093.     else if(wType == CEVT_BLOB)
  1094.         return CCeDBProp::Type_Blob;
  1095.     else 
  1096.         ASSERT(FALSE);
  1097.  
  1098.     // so compiler doesn't complain about control path not returning a value:
  1099.     return CCeDBProp::enType(0); 
  1100. }
  1101.  
  1102. /*private: static*/ WORD CCeDBProp::TypeToCEVT(CCeDBProp::enType nType)
  1103. {
  1104.     ASSERT((nType >= Type_Short) && (nType <= Type_Blob));
  1105.  
  1106.     static WORD wTypeMap[] = 
  1107.     {
  1108.         CEVT_I2,CEVT_UI2,CEVT_I4,CEVT_UI4,
  1109.         CEVT_FILETIME,CEVT_LPWSTR,CEVT_BLOB
  1110.     };
  1111.  
  1112.     return wTypeMap[nType];
  1113. }
  1114.  
  1115.  
  1116.  
  1117.  
  1118. /*private:*/ CEPROPID CCeDBProp::GetPropid() const 
  1119. {
  1120.     return m_CePropVal.propid;
  1121. }
  1122.  
  1123. // Note: there's no SetPropid().  We use SetType() and SetIdent() instead.
  1124.  
  1125.  
  1126. void CCeDBProp::SetSortFlags(WORD wSortFlags)
  1127. {
  1128.     ASSERT(0 == (wSortFlags & ~( Sort_Ascending  |
  1129.                                  Sort_Descending |
  1130.                                  Sort_CaseInsensitive |
  1131.                                  Sort_UnknownFirst |
  1132.                                  Sort_GenericOrder ) ) );
  1133.     m_wSortFlags = wSortFlags;
  1134. }
  1135.  
  1136. WORD CCeDBProp::GetSortFlags() const
  1137. {
  1138.     return m_wSortFlags;
  1139. }
  1140.  
  1141. void CCeDBProp::SetShort(short iVal)
  1142. {
  1143.     FreeProp(); // calls InitProp()
  1144.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_I2);
  1145.     m_CePropVal.val.iVal = iVal;
  1146. }
  1147.  
  1148. short CCeDBProp::GetShort() const
  1149. {
  1150.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_I2);
  1151.     return m_CePropVal.val.iVal;
  1152. }
  1153.  
  1154.  
  1155. void CCeDBProp::SetUShort(USHORT uiVal)
  1156. {
  1157.     FreeProp();  // calls InitProp()
  1158.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_UI2);
  1159.     m_CePropVal.val.uiVal = uiVal;
  1160. }
  1161.  
  1162. USHORT CCeDBProp::GetUShort() const
  1163. {
  1164.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_UI2);
  1165.     return m_CePropVal.val.uiVal;
  1166. }
  1167.  
  1168. void CCeDBProp::SetLong(long lVal)
  1169. {
  1170.     FreeProp();  // calls InitProp()
  1171.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_I4);
  1172.     m_CePropVal.val.lVal = lVal;
  1173. }
  1174.  
  1175. long CCeDBProp::GetLong() const
  1176. {
  1177.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_I4);
  1178.     return m_CePropVal.val.lVal;
  1179. }
  1180.  
  1181. void CCeDBProp::SetULong(ULONG ulVal)
  1182. {
  1183.     FreeProp();  // calls InitProp()
  1184.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_UI4);
  1185.     m_CePropVal.val.ulVal = ulVal;
  1186. }
  1187.  
  1188. ULONG CCeDBProp::GetULong() const
  1189. {
  1190.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_UI4);
  1191.     return m_CePropVal.val.ulVal;
  1192. }
  1193.  
  1194. void CCeDBProp::SetFiletime(FILETIME filetime)
  1195. {
  1196.     FreeProp();  // calls InitProp()
  1197.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_FILETIME);
  1198.     m_CePropVal.val.filetime = filetime;
  1199. }
  1200.  
  1201. FILETIME CCeDBProp::GetFiletime() const
  1202. {
  1203.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_FILETIME);
  1204.     return m_CePropVal.val.filetime;
  1205. }
  1206.  
  1207. void CCeDBProp::SetString(LPWSTR lpwstr,UINT nMode /*= CCeDBProp::Copy*/)
  1208. {
  1209.     FreeProp();  // calls InitProp()
  1210.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_LPWSTR);
  1211.  
  1212.     int nLen = wcslen(lpwstr)+sizeof(WCHAR);
  1213.     // Note: the length is not enforced by this wrapper method, but WinCE does have
  1214.     // a maximum set on its database records.
  1215.  
  1216.     switch(nMode)
  1217.     {
  1218.         case Copy:
  1219.             m_CePropVal.val.lpwstr = new WCHAR[nLen]; // throwable  
  1220.             wcscpy(m_CePropVal.val.lpwstr,lpwstr);
  1221.             m_bOwnsStringOrBlob = TRUE;
  1222.         break;
  1223.  
  1224.         case NoCopy:
  1225.             m_CePropVal.val.lpwstr = lpwstr;
  1226.             m_bOwnsStringOrBlob = FALSE;
  1227.         break;
  1228.  
  1229.         default:
  1230.             ASSERT(FALSE);
  1231.         break;
  1232.     }
  1233. }
  1234.  
  1235. LPWSTR CCeDBProp::GetString() const
  1236. {
  1237.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_LPWSTR);
  1238.     return m_CePropVal.val.lpwstr;
  1239. }
  1240.  
  1241. void CCeDBProp::SetBlob(CEBLOB blob,UINT nMode /*= CCeDBProp::Copy*/)
  1242. {
  1243.     FreeProp();  // calls InitProp()
  1244.  
  1245.     SET_PROPID_CEVT(m_CePropVal.propid,CEVT_BLOB);
  1246.     m_CePropVal.val.blob.dwCount = blob.dwCount;
  1247.     // Note: the length is not enforced by this wrapper method, but WinCE does have
  1248.     // a maximum set on its database records.
  1249.  
  1250.     switch(nMode)
  1251.     {
  1252.         case Copy:
  1253.             m_CePropVal.val.blob.lpb = new BYTE[blob.dwCount]; // throwable
  1254.             memcpy(m_CePropVal.val.blob.lpb,blob.lpb,blob.dwCount);
  1255.             m_bOwnsStringOrBlob = TRUE;
  1256.         break;
  1257.  
  1258.         case NoCopy:
  1259.             m_CePropVal.val.blob.lpb = blob.lpb;
  1260.             m_bOwnsStringOrBlob = FALSE;
  1261.         break;
  1262.     }
  1263. }
  1264.  
  1265. CEBLOB CCeDBProp::GetBlob() const
  1266. {
  1267.     ASSERT(GET_PROPID_CEVT(m_CePropVal.propid) == CEVT_BLOB);
  1268.     return m_CePropVal.val.blob;
  1269. }
  1270.  
  1271. //////////////////////////////////////////////////////////////////////
  1272.  
  1273.  
  1274.  
  1275. //////////////////////////////////////////////////////////////////////
  1276. // Other operations on CCeDBProp
  1277. //////////////////////////////////////////////////////////////////////
  1278.  
  1279. // Note: don't call InitProp() if there is currently data being pointed to by this class.
  1280. // InitProp() is private member function.
  1281. /*private:*/ void CCeDBProp::InitProp() 
  1282. {
  1283.     memset(&m_CePropVal,0,sizeof(CEPROPVAL));
  1284.     m_bOwnsStringOrBlob = FALSE;
  1285.     m_wSortFlags = 0;
  1286. }
  1287.  
  1288. void CCeDBProp::FreeProp()
  1289. {
  1290.     if((m_CePropVal.propid == CEVT_LPWSTR) && m_bOwnsStringOrBlob)
  1291.         delete[] m_CePropVal.val.lpwstr;
  1292.     else if((m_CePropVal.propid == CEVT_BLOB) && m_bOwnsStringOrBlob)
  1293.         delete[] m_CePropVal.val.blob.lpb;
  1294.  
  1295.     WORD wSaveIdent = GET_PROPID_IDENT(m_CePropVal.propid);
  1296.     InitProp();
  1297.     SET_PROPID_IDENT(m_CePropVal.propid,wSaveIdent);
  1298. }
  1299.  
  1300. //////////////////////////////////////////////////////////////////////
  1301.  
  1302.  
  1303.  
  1304.  
  1305. //////////////////////////////////////////////////////////////////////
  1306. // Implementation of CCeRecord
  1307. //////////////////////////////////////////////////////////////////////
  1308.  
  1309. CCeDBRecord::CCeDBRecord()
  1310. {
  1311.     m_pPropArray.SetSize(0);
  1312.     m_pbBuffer = NULL;
  1313. }
  1314.  
  1315. CCeDBRecord::~CCeDBRecord()
  1316. {
  1317.     FreeRecord(); 
  1318. }
  1319.  
  1320. // copy constructor
  1321. CCeDBRecord::CCeDBRecord(CCeDBRecord& rec)
  1322. {
  1323.     m_pPropArray.RemoveAll();
  1324.     m_pPropArray.Copy(rec.m_pPropArray);
  1325.     m_pbBuffer = NULL;  // no ownership of memory (let the original object keep it)
  1326. }
  1327.  
  1328. // assignment operator
  1329. CCeDBRecord& CCeDBRecord::operator=(const CCeDBRecord& rec)
  1330. {
  1331.     FreeRecord(); // free original object
  1332.     m_pPropArray.RemoveAll();
  1333.     m_pPropArray.Copy(rec.m_pPropArray);
  1334.     m_pbBuffer = NULL; // no ownership of memory (let the original object keep it)
  1335.     return *this;
  1336. }
  1337.  
  1338.  
  1339. int CCeDBRecord::GetNumProps() const
  1340. {
  1341.     return m_pPropArray.GetSize();
  1342. }
  1343.  
  1344. BOOL CCeDBRecord::AddProp(CCeDBProp *pProp)
  1345. {
  1346.     TRY
  1347.     {
  1348.         m_pPropArray.Add(pProp);
  1349.         pProp->m_bOwnsStringOrBlob = FALSE; // only want one ownership instance
  1350.     }
  1351.     CATCH(CMemoryException,e)
  1352.     {
  1353.         return FALSE;
  1354.     }
  1355.     END_CATCH
  1356.  
  1357.     return TRUE;
  1358. }
  1359.  
  1360. BOOL CCeDBRecord::AddProps(CCeDBProp* pPropArray,int nNumProps)
  1361. {
  1362.     for(int n=0; n < nNumProps; n++)
  1363.     {
  1364.         TRY
  1365.         {
  1366.             int nIndex = m_pPropArray.Add(pPropArray+n);
  1367.         }
  1368.         CATCH(CException,e)
  1369.         {
  1370.             return FALSE;
  1371.         }
  1372.         END_CATCH;
  1373.             
  1374.         pPropArray[n].m_bOwnsStringOrBlob = FALSE; // only want one ownership instance
  1375.     }
  1376.     return TRUE;
  1377. }
  1378.  
  1379. void CCeDBRecord::DeleteAllProps()
  1380. {
  1381.     FreeRecord();
  1382. }
  1383.  
  1384. void CCeDBRecord::DeleteProp(WORD wPropIdent)
  1385. {
  1386.     int nLength = m_pPropArray.GetSize();
  1387.  
  1388.     for(int n=0; n < nLength; n++)
  1389.     {
  1390.         if(GET_PROPID_IDENT(((CCeDBProp*)m_pPropArray[n])->m_CePropVal.propid) == wPropIdent)
  1391.         {
  1392.             if(((CCeDBProp*)m_pPropArray[n])->m_bDeletePtr)
  1393.                 free(m_pPropArray[n]);
  1394.             while(n < nLength-1)
  1395.             {
  1396.                 m_pPropArray[n] = m_pPropArray[n+1];
  1397.                 n++;
  1398.             }
  1399.             m_pPropArray.SetSize(--nLength);
  1400.             break;
  1401.         }
  1402.     }
  1403.  
  1404.     if(nLength == 0) // delete m_pbBuffer now (if there is one)
  1405.     {
  1406.         LocalFree(m_pbBuffer);
  1407.         m_pbBuffer = NULL;
  1408.     }
  1409. }
  1410.  
  1411. CCeDBProp* CCeDBRecord::GetPropFromIdent(WORD wPropIdent) const // query by wIdent?
  1412. {
  1413.     for(int n=0; n < m_pPropArray.GetSize(); n++)
  1414.     {
  1415.         if(GET_PROPID_IDENT(((CCeDBProp*)m_pPropArray[n])->m_CePropVal.propid) == wPropIdent)
  1416.             return *(((CCeDBProp **)m_pPropArray.GetData())+n);
  1417.     }
  1418.  
  1419.     return NULL;
  1420. }
  1421.  
  1422.  
  1423. CCeDBProp* CCeDBRecord::GetPropFromIndex(int n) const 
  1424. {
  1425.     ASSERT((n >= 0) && (n < m_pPropArray.GetSize()));
  1426.  
  1427.     return *(((CCeDBProp **)m_pPropArray.GetData())+n);
  1428. }
  1429.  
  1430.  
  1431. void CCeDBRecord::FreeRecord()
  1432. {
  1433.     int nLength = m_pPropArray.GetSize();
  1434.     for(int n=0; n < nLength; n++)
  1435.     {
  1436.         if(((CCeDBProp*)m_pPropArray[n])->m_bDeletePtr)
  1437.             free(m_pPropArray[n]);
  1438.     }
  1439.  
  1440.     m_pPropArray.SetSize(0); 
  1441.  
  1442.     if(m_pbBuffer != NULL)
  1443.     {
  1444.         LocalFree(m_pbBuffer);
  1445.         m_pbBuffer = NULL;
  1446.     }
  1447. }
  1448.  
  1449. //////////////////////////////////////////////////////////////////////
  1450.  
  1451. IMPLEMENT_DYNAMIC(CCeDBDatabase,CObject);
  1452. IMPLEMENT_DYNAMIC(CCeDBProp,CObject);
  1453.  
  1454.