March 8, 2021
Hot Topics:

Manipulating Data Records in Win CE

  • By Nancy Nicolaisen
  • Send Email »
  • More Articles »

Iterating Records

Iterative reading of CE database records is a pretty slick situation, as you probably guessed, based on the fact there is a special database open mode for doing it. This technique is demonstrated in the BirthdayListDlgProc(), which is invoked when the user clicks the BirthdayReminder Dialog's Show All button.

The work of creating the list of birthday reminder records is all done in response to the WM_INITDIALOG message. Let's examine the database access-related parts of the BirthdayListDlgProc().

   //get a handle to the list control
   hwndList = GetDlgItem(hDlg,IDC_BIRTHDAY_LIST);

   //open the database in AUTOINCREMENT mode, no sort
   //order active
   globalHDB = CeOpenDatabase (&globalCEOID, NULL, 0,
                               CEDB_AUTOINCREMENT , NULL);

First, we open the database using its CEOID and setting the CEDB_AUTOINCREMENT flag. This flag causes the current record location to be incremented with each read operation.

   //seek to the beginning of the database
   oid = CeSeekDatabase (globalHDB, CEDB_SEEK_BEGINNING, 0, &dwIndex);

Next, we seek to the beginning of the database to establish a current record.

   // Read all properties for the record. Have the system
   // allocate the buffer containing the data.
   oid = CeReadRecordProps (globalHDB, CEDB_ALLOWREALLOC,
                            &wProps, NULL,
                            &(LPBYTE )pRecord, &dwRecSize);

Now, we call CeReadRecordProps() The parameters, in the order shown, are:

  • The handle to the database.
  • A flag that allows the function to allocate a correctly sized record buffer in our behalf.
  • The address of the null initialized variable wProps. On return, wProps will contain a count of the record's properties.
  • A pointer to an array of CEPROPIDs for which to retireve values. In this case, it is set to NULL, meaning all properties should be returned.
  • The address of a pointer to the buffer (a pointer to a pointer) containing the retrieved record, set to NULL to indicate that the system must allocate the record buffer.
  • The address of a variable that will contain the size in bytes of the returned buffer on a successful return.

This all sounds fairly complicated, and it could turn out that way in certain circumstances. However, most of the time, the best and easiest way to make this call is just as you see it above. Let the system allocate the record buffer, and retrieve all the properties at one time, because this is much more efficient than any other scheme.

   while( oid != 0 )

      lpRecord = (PCEPROPVAL)pRecord;
      //get the Name string
      memset( szBirthday, 0x0, sizeof(szBirthday));

We cast the pointer to the buffer returned by CeReadRecordProps() to a PCEPROPVAL so that you may use it to access the individual CEPROPVAL structures. Now, we are ready to create the listbox strings:

//get the date
FileTimeToSystemTime( &lpRecord[1].val.filetime,

//what gift did we have in mind?
memset(szWhat, 0x0, sizeof(szWhat));
if(lpRecord[2].val.iVal == IDC_CANDY )
   { wcscpy( szWhat, TEXT("Candy"));};

if(lpRecord[2].val.iVal == IDC_FLOWERS )
   { wcscpy( szWhat, TEXT("Flowers"));};

if(lpRecord[2].val.iVal == IDC_ANT_FARM )
   { wcscpy( szWhat, TEXT("Ant Farm"));};

//format the string
wsprintf((TCHAR*)&szBirthday, TEXT("%s %i/%i/%i %s"),
            stBirthDate.wDay ,
            stBirthDate.wMonth ,
//insert the string
SendMessage(hwndList, LB_INSERTSTRING, -1, 
              (long)&szBirthday );

To make listbox strings out of the returned property values, we convert the birth date stored as a file as a FILETIME back to a SYSTEMTIME, select a gift item based on the stored integer value, and use the CEVALUNION member val.lpwstr to pass the name string to wsprintf(). Presto, formatted birthday reminder record data in a Unicode string.

A Few Final Words on CE Databases

We've touched on a great many things you can do with the CE database API, a toolset that is both flexible and powerful. However, there are some inherent limitations of which to be aware. The first is that a database may contain only one kind of record. The second, which is actually a corollary to the first, is that you can't explicitly create one-to-many or many-to-many relationships. In a strict sense, it's also true that the Windows CE database is really an object store, not a true database. It shares no relationship with standard relational database tools such as SQL and the like. Personally, I don't see any of these facts as particularly troubling or intrusive, for the reason that the CEBLOB type allows you to store sophisticated, application specific data structures inside a record.

Looking Ahead

One of the very great strengths of the integrated nature of the CE database API is that it allows you to find other databases that exist on a device, query their structures, and dynamically incorporate their data. In upcoming examples, we'll build on the skills you've learned up to this point. You'll see how to connect to a Windows CE database from the desktop, using the remote database API. You'll learn how to remotely enumerate databases, find out what kind of information they contain, and manipulate those databases in your applications. We'll also look at power conservation strategies for programming CE.

About the Author

Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, and entry time data validation.

In addition to writing for Developer.com, she has written several books, including Making Win 32 Applications Mobile.

# # #

Page 2 of 2

This article was originally published on May 5, 2004

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date