#ifndef __CeDb_h__
#define __CeDb_h__
#include "CeDebug.h"
#include "CeMisc.h"
#include "CeString.h"
#ifdef _WIN32_WCE
# include <windbase.h>
#else
# include <ole2.h>
# include <rapi.h>
#endif
class CeDbEnum;
class CeDb;
class CeDbRecord;
class CeDbProp;
///////////////////////////////////////////////////////////////////////////////
//
// Get/Manipulate the properties of a database data record
//
///////////////////////////////////////////////////////////////////////////////
//
// Property types
//
// CEVT_BLOB A CEBLOB structure.
// CEVT_FILETIME A FILETIME structure.
// CEVT_I2 A 16-bit signed integer.
// CEVT_I4 A 32-bit signed integer.
// CEVT_LPWSTR A null-terminated string.
// CEVT_UI2 A 16-bit unsigned integer.
// CEVT_UI4 A 32-bit unsigned integer.
//
// And beginning in 2.11
// CEVT_BOOL A boolean value.
// CEVT_R8 A double floating point value.
//
class CeDbRecord
{
protected:
friend class CeDb;
public:
CEOID m_oid; // the OID of the record
WORD m_wProps; // number of properties
DWORD m_cbProps; // the size of the allocated array
CEPROPVAL* m_pProps; // array of allocated field values
bool m_bLocalAlloc;
protected:
int FindProp(WORD wProp) const
{
for (int ii = 0; ii < (int) m_wProps; ii++)
{
if (HIWORD(m_pProps[ii].propid) == wProp)
return ii;
}
return -1;
}
CEPROPVAL* DupProps(CEPROPVAL* pPropsOrig, WORD wProps, DWORD cbNewProps);
public:
CeDbRecord()
{
m_oid = 0;
m_wProps = 0;
m_cbProps = 0;
m_pProps = NULL;
m_bLocalAlloc = false;
}
bool AddProp(WORD wProp, WORD wType);
bool RemProp(int nCol);
bool RemProp(WORD wId);
// Get/Set value by identifier
bool GetIdVal(WORD wProp, SHORT& iProp) const
{ return GetIndexVal(FindProp(wProp), iProp); }
bool GetIdVal(WORD wProp, USHORT& uiProp) const
{ return GetIndexVal(FindProp(wProp), uiProp); }
bool GetIdVal(WORD wProp, LONG& lProp) const
{ return GetIndexVal(FindProp(wProp), lProp); }
bool GetIdVal(WORD wProp, ULONG& ulProp) const
{ return GetIndexVal(FindProp(wProp), ulProp); }
bool GetIdVal(WORD wProp, FILETIME& ftProp) const
{ return GetIndexVal(FindProp(wProp), ftProp); }
bool GetIdVal(WORD wProp, CEBLOB& blobProp) const
{ return GetIndexVal(FindProp(wProp), blobProp); }
bool GetIdVal(WORD wProp, CeString& strProp) const
{ return GetIndexVal(FindProp(wProp), strProp); }
#ifdef CEVT_BOOL
bool GetIdVal(WORD wProp, bool& bProp) const
{ return GetIndexVal(FindProp(wProp), bProp); }
#endif
#ifdef CEVT_R8
bool GetIdVal(WORD wProp, double& dblProp) const
{ return GetIndexVal(FindProp(wProp), dblProp); }
#endif
bool SetIdVal(WORD wProp, SHORT sProp)
{ return SetIndexVal(FindProp(wProp), sProp); }
bool SetIdVal(WORD wProp, USHORT sProp)
{ return SetIndexVal(FindProp(wProp), sProp); }
bool SetIdVal(WORD wProp, LONG nProp)
{ return SetIndexVal(FindProp(wProp), nProp); }
bool SetIdVal(WORD wProp, ULONG dwProp)
{ return SetIndexVal(FindProp(wProp), dwProp); }
bool SetIdVal(WORD wProp, FILETIME ftProp)
{ return SetIndexVal(FindProp(wProp), ftProp); }
bool SetIdVal(WORD wProp, CEBLOB blobProp)
{ return SetIndexVal(FindProp(wProp), blobProp); }
bool SetIdVal(WORD wProp, LPCWSTR lpszProp)
{ return SetIndexVal(FindProp(wProp), lpszProp); }
#ifdef CEVT_BOOL
bool SetIdVal(WORD wProp, bool bProp)
{ return SetIndexVal(FindProp(wProp), bProp); }
#endif
#ifdef CEVT_R8
bool SetIdVal(WORD wProp, double dblProp)
{ return SetIndexVal(FindProp(wProp), dblProp); }
#endif
// Get/Set value by index
bool GetIndexVal(int nProp, SHORT& iProp) const;
bool GetIndexVal(int nProp, USHORT& uiProp) const;
bool GetIndexVal(int nProp, LONG& lProp) const;
bool GetIndexVal(int nProp, ULONG& ulProp) const;
bool GetIndexVal(int nProp, FILETIME& ftProp) const;
bool GetIndexVal(int nProp, CEBLOB& blobProp) const;
bool GetIndexVal(int nProp, CeString& strProp) const; // valid for all types, limited to 256 bytes for Blobs
#ifdef CEVT_BOOL
bool GetIndexVal(int nProp, bool& bProp) const;
#endif
#ifdef CEVT_R8
bool GetIndexVal(int nProp, double& dblProp) const;
#endif
bool SetIndexVal(int nProp, SHORT iProp);
bool SetIndexVal(int nProp, USHORT uiProp);
bool SetIndexVal(int nProp, LONG lProp);
bool SetIndexVal(int nProp, ULONG ulProp);
bool SetIndexVal(int nProp, FILETIME ftProp);
bool SetIndexVal(int nProp, CEBLOB blobProp);
bool SetIndexVal(int nProp, LPCWSTR lpszProp);
#ifdef CEVT_BOOL
bool SetIndexVal(int nProp, bool bProp);
#endif
#ifdef CEVT_R8
bool SetIndexVal(int nProp, double dblProp);
#endif
virtual ~CeDbRecord()
{
if (NULL != m_pProps)
delete[] (BYTE*) m_pProps;
}
protected:
// record objects cannot be copied or assigned
CeDbRecord(const CeDbRecord& arSrc);
void operator=(const CeDbRecord& arSrc);
};
///////////////////////////////////////////////////////////////////////////////
//
// Create/Open/Delete/Modify a specific database
//
///////////////////////////////////////////////////////////////////////////////
class CeDb
{
private:
HANDLE m_hDb;
CEOID m_oid;
WCHAR m_szName[256];
public:
// Construction
CeDb()
{ m_oid = 0; m_hDb = (HANDLE) INVALID_HANDLE_VALUE; *m_szName = 0; }
bool Create(LPCWSTR lpszName, DWORD dwDbaseType = 0, WORD wNumSortOrder = 0, SORTORDERSPEC * rgSortSpecs = NULL)
{
m_oid = ::CeCreateDatabase((LPWSTR)lpszName, dwDbaseType, wNumSortOrder, rgSortSpecs);
wcscpy(m_szName, lpszName);
return (m_oid) ? true: false;
}
/*
bool Open(CEPROPID idKey = 0, DWORD dwFlags = 0, HWND hwndNotify = NULL)
{
ASSERT(0 == m_oid);
ASSERT(0 == *m_szName);
ASSERT((HANDLE)INVALID_HANDLE_VALUE == m_hDb);
// open from non-zero OID, assert handle null
m_oid = 0;
m_hDb = ::CeOpenDatabase (&m_oid, m_szName, idKey, dwFlags, hwndNotify);
return (HANDLE)INVALID_HANDLE_VALUE != m_hDb;
}
*/
bool Open(CEOID oid = 0, CEPROPID idKey = 0, DWORD dwFlags = 0, HWND hwndNotify = NULL)
{
ASSERT((HANDLE)INVALID_HANDLE_VALUE == m_hDb);
if (0 == oid)
{
ASSERT(0 != m_oid);
}
else
{
ASSERT(0 == *m_szName);
//ASSERT(0 == m_oid);
m_oid = oid;
}
// open from OID passed, assert handle null
m_hDb = ::CeOpenDatabase (&m_oid, m_szName, idKey, dwFlags, hwndNotify);
return ((HANDLE)INVALID_HANDLE_VALUE != m_hDb);
}
bool Open(LPCWSTR lpszName, CEPROPID idKey = 0, DWORD dwFlags = 0, HWND hwndNotify = NULL)
{
ASSERT(0 == m_oid);
ASSERT(0 == *m_szName);
ASSERT((HANDLE)INVALID_HANDLE_VALUE == m_hDb);
// open from name, assert handle null
wcscpy(m_szName, lpszName);
m_hDb = ::CeOpenDatabase (&m_oid, m_szName, idKey, dwFlags, hwndNotify);
return ((HANDLE)INVALID_HANDLE_VALUE != m_hDb);
}
// Attributes
bool IsOpen() const
{ return ((HANDLE)INVALID_HANDLE_VALUE != m_hDb); }
// reads up all the current records properties
bool ReadRec(CeDbRecord& rec);
bool AddRec(CeDbRecord& rec)
{
ASSERT(rec.m_wProps > 0);
ASSERT(NULL != rec.m_pProps);
rec.m_oid = ::CeWriteRecordProps(
m_hDb,
0,
rec.m_wProps,
rec.m_pProps);
return (0 != rec.m_oid);
}
bool UpdateRec(CeDbRecord& rec)
{
ASSERT(0 != rec.m_oid);
ASSERT(rec.m_wProps > 0);
ASSERT(NULL != rec.m_pProps);
CEOID oid = ::CeWriteRecordProps(
m_hDb,
rec.m_oid,
rec.m_wProps,
rec.m_pProps);
return (oid == rec.m_oid);
}
// Operations
// Raw seek
CEOID Seek(DWORD dwSeekType, DWORD dwValue, DWORD* pdwIndex=NULL)
{
DWORD dwIndex;
CEOID ceoid = ::CeSeekDatabase(m_hDb, dwSeekType, dwValue, &dwIndex);
if (pdwIndex) *pdwIndex = dwIndex;
return ceoid;
}
CEOID SeekRec(CEPROPVAL *pPV)
{ return Seek(CEDB_SEEK_VALUEFIRSTEQUAL, (DWORD) pPV); }
CEOID SeekEnd(int nOff = 0)
{ return Seek(CEDB_SEEK_END, nOff); }
CEOID SeekBegin(int nOff = 0)
{ return Seek(CEDB_SEEK_BEGINNING, nOff); }
CEOID SeekCurrent(int nOff)
{ return Seek(CEDB_SEEK_CURRENT, nOff); }
CEOID SeekNext()
{ return SeekCurrent(1); }
CEOID SeekPrev()
{ return SeekCurrent(-1); }
CEOID SeekTo(CEOID oid)
{ return Seek(CEDB_SEEK_CEOID, oid); }
CEOID SeekFirst()
{ return SeekBegin(); }
CEOID SeekLast()
{ return SeekEnd(); }
// Other operations
BOOL SetInfo(CEDBASEINFO* pNewInfo)
{ return ::CeSetDatabaseInfo(m_oid, pNewInfo); }
BOOL SetLastModified(FILETIME ft)
{
CEDBASEINFO info;
info.dwFlags = CEDB_VALIDMODTIME;
info.ftLastModified = ft;
return SetInfo(&info);
}
BOOL SetName(LPCWSTR lpszName)
{
CEDBASEINFO info;
info.dwFlags = CEDB_VALIDNAME;
wcsncpy(info.szDbaseName, lpszName, CEDB_MAXDBASENAMELEN);
return SetInfo(&info);
}
BOOL SetDbaseType(DWORD dwType)
{
CEDBASEINFO info;
info.dwFlags = CEDB_VALIDTYPE;
info.dwDbaseType = dwType;
return SetInfo(&info);
}
//BOOL SetSort(SORTORDERSPEC pSortSpec)
// {
// CEDBASEINFO info;
// info.dwFlags = CEDB_VALIDSORTSPEC;
// return SetInfo(&info);
// }
// Destruction
BOOL Delete()
{ return ::CeDeleteDatabase(m_oid); }
BOOL DeleteRecord(CEOID oid)
{ return ::CeDeleteRecord(m_hDb, oid); }
void Close()
{
if (INVALID_HANDLE_VALUE != m_hDb)
{
::CloseHandle(m_hDb);
m_hDb = INVALID_HANDLE_VALUE;
}
}
~CeDb()
{ Close(); }
protected:
// database objects cannot be copied or assigned
CeDb(const CeDb& Src);
void operator=(const CeDb& Src);
};
///////////////////////////////////////////////////////////////////////////////
//
// Enumerate through the system databases
//
///////////////////////////////////////////////////////////////////////////////
class CeDbEnum
{
private:
HANDLE m_hEnum;
CEOID m_oid;
// ???
bool m_bHaveInfo;
CEOIDINFO m_oidinfo;
public:
bool First(DWORD dwType = 0)
{
m_bHaveInfo = false;
m_hEnum = ::CeFindFirstDatabase(dwType);
m_oid = 0;
return (INVALID_HANDLE_VALUE != m_hEnum);
}
bool Next(bool bGetInfo = true)
{
CHW_ASSERT(NULL != m_hEnum);
m_bHaveInfo = false;
m_oid = ::CeFindNextDatabase(m_hEnum);
if (ERROR_NO_MORE_ITEMS == GetLastError())
return false;
if (bGetInfo)
GetInfo();
return true;
}
CEOID GetOid() const { return m_oid; }
bool GetInfo()
{
if (! m_bHaveInfo)
{
if (! ::CeOidGetInfo(m_oid, &m_oidinfo))
return false;
m_bHaveInfo = true;
}
return true;
}
bool GetInfo(CEDBASEINFO& dbInfo)
{
if (GetInfo())
{
memcpy(&dbInfo, &m_oidinfo.infDatabase, sizeof m_oidinfo.infDatabase);
return true;
}
return false;
}
// only valid if GetInfo() called or true passed to Next()
LPCWSTR GetName() const
{ return m_oidinfo.infDatabase.szDbaseName; }
DWORD GetFlags() const
{ return m_oidinfo.infDatabase.dwFlags; }
DWORD GetType() const
{ return m_oidinfo.infDatabase.dwDbaseType; }
WORD GetNumRecords() const
{ return m_oidinfo.infDatabase.wNumRecords; }
WORD GetNumSorts() const
{ return m_oidinfo.infDatabase.wNumSortOrder; }
DWORD GetSize() const
{ return m_oidinfo.infDatabase.dwSize; }
FILETIME GetModified() const
{ return m_oidinfo.infDatabase.ftLastModified; }
// SORTORDERSPEC rgSortSpecs[CEDB_MAXSORTORDER];
CeDbEnum()
{ m_hEnum = NULL; m_oid = NULL; }
~CeDbEnum()
{ if (NULL != m_hEnum) ::CloseHandle(m_hEnum); }
protected:
// database objects cannot be copied or assigned
CeDbEnum(const CeDbEnum& Src);
void operator=(const CeDbEnum& Src);
};
#endif // __CeDb_h__