Building Microsoft Windows CE Database Applications with the ADOCE Control

Timothy Trimble, President
Extended Technology Systems

May 18, 1999

Summary: This article covers an introduction to the use of Microsoft ActiveX® Data Objects for Windows® CE (ADOCE) with the Windows CE Toolkit for Visual Basic® 6.0 (VBCE), the approach to designing handheld applications compared with desktop development, connectivity to and from Windows CE database applications, and real-world application of this technology. Source code examples will be included to help you understand the use of VBCE and ADOCE. This article assumes that you have some familiarity with Windows CE, desktop Visual Basic, VBCE, and the use of databases from desktop Visual Basic. (21 printed pages)

Click to copy the BenchMark sample files.

Why ADOCE for Visual Basic?

The chief benefit of coupling handheld technology with Visual Basic, the most widely used corporate programming language, is the resulting ability of developers to use the same approach to designing and using databases for both the desktop world and the emerging handheld industry. The first version of Windows CE and VBCE had limitations that made data access possible only through the use of direct file I/O or by the use of third-party and quick-to-market database controls.

However, with the latest release of the Windows CE Toolkit for Visual Basic 6.0, corporate developers who were once concerned about those limitations can now dive head-first into designing and developing corporate database applications. With the addition of specialized ActiveX controls, specifically the ADOCE control, database development under VBCE now provides the Rapid Application Development (RAD) environment desired in today’s corporate environment.

Introduction to the ADOCE Control

The ADOCE control is Microsoft’s ActiveX Data Object for Windows CE, an ADO 1.0-based lean and trim version of the data access capabilities found in desktop Visual Basic. By using of SQL and native object methods, ADOCE provides database management functionality for Microsoft Access structured databases. Pocket Access is not required on the CE device in order to use ADOCE.

If you are using a Windows CE Handheld PC, Professional Edition (Version 2.11 or greater), then chances are that you already have the ADOCE control installed on your Windows CE device.

It is also recommended that you have the latest version of Windows CE Services installed. If you are not sure that ADOCE is installed, simply check the \windows directory on your CE device and look for the ADOCE.DLL file. If this file is not there, you will need to install the control.

Note   If you already have ADOCE installed on your Windows CE Pro device, do not install the ADOCE Control from your desktop. This will cause VBCE errors and your application will not run. If you have installed ADOCE without realizing that you already had ADOCE on your device, uninstall ADOCE from the device, and then reregister the built-in ADOCE. (Run REGSVR.EXE \windows\adoce.dll.)

Comparison with ADO Desktop

Using the ADOCE control under VBCE is just as easy as using ADO under desktop Visual Basic. The following example shows how easy it is to use ADOCE:

    Dim rsMain, sSQL, sSNum                           ‘declare necessary variables
    Set rsMain = CreateObject(“adoce.recordset”)  ‘declare pointer to adoce object
    SSQL = “SELECT * FROM NAMES WHERE LNAME = ‘SMITH’;”       ‘build sql statement
    rsMain.open sSQL                                 ‘issue sql statement to adoce
    rsMain.movefirst
    sSNUM = rsMain.fields(“SSNUM”)                 ‘get ss number from names table
    rsMain.close                                                  ‘close the table

As you can see, using ADOCE with VBCE does not require you to write your Visual Basic syntax any differently than if you were writing for desktop Visual Basic. However, there are some limitations in the features that are supported by ADOCE versus standard desktop ADO. The following table shows a list of SQL statements that are supported by ADOCE:

SQL Statement
Create Table
Drop Table
Create Index
Drop Index
Alter Table
Select (Select * From)
Select Order By
Select Restricted (NOT, =, <>, and so on.)
Select Projection (SELECT fieldname, fieldname, and so on.)
Select Join
Delete
Insert

The most noticeable missing SQL statement from this list is the UPDATE statement. However, record updates can still take place through the ADOCE Update method.

This next table is a list of methods and properties that are supported by ADOCE:

ADO Method
Addnew
CancelUpdate
Clone
Close
Delete
GetRows
Move
MoveFirst
MoveLast
MoveNext
MovePrevious
Open
Update
Supports
ADO Properties
AbsolutePage
AbsolutePosition
ActiveConnection
BOF,EOF
Bookmark
CacheSize
Count
CursorType
EditMode
LockType
PageCount
PageSize
RecordCount
Source
ActualSize
Attributes
DefinedSize
Name
Type
UnderlyingValue
Value

While this list may seem limited in comparison to desktop ADO, keep in mind that it actually provides a lot of database power for such a small device and operating system. Many developers who are making a transition to Windows CE development must make a mental note that they are not developing for a desktop computer.

Handheld Design Methodology

This Is Not a Desktop Computer!

This is one of the hardest issues to face when making the transition from desktop to Windows CE development. Due to the size, memory, and resource constraints of these small computer devices, Windows CE is a lean OS that provides the minimum of necessary functions and resources. While a desktop developer may have 64 megabytes (MB) of RAM and a 2-gigabyte (GB) hard drive to utilize, the Windows CE developer has only memory for both program execution and storage. Memory is as low as 2 MB on some devices.

While the topic of Windows CE design methodology could be discussed in an entire book, in the scope of this white paper we’ll simply touch on the aspects related to database design.

Database Design

The first consideration to keep in mind, when designing database applications for Windows CE, is the size of the data. Some of the following considerations may seem simplistic, but these are things that we sometimes take for granted when doing desktop development. Some questions that you can ask during the design stage are:

Other Considerations

To insure that VBCE has as small a footprint as possible, many constants that we are used to automatically having under desktop Visual Basic are not automatically included in VBCE. Such is the case with the constants for the parameters used by the ADOCE Open method. However, the constants for the parameters of the MsgBox statement do not need to be declared. The example application available for download at the beginning of this article, DataBench, will demonstrate the use of these constants.

ADOCE Features and Functionality

An Application Example—DataBench

The DataBench application was written to demonstrate how to use the ADOCE control with VBCE. Both SQL and native methods are used. DataBench is also a good program for testing the speed of database usage on the Windows CE device you are using.

DataBench can be downloaded by clicking on the link at the beginning of this article.

Figure 1. The DataBench application

Variables and constants

VBCE utilizes all variables as variants. Even though this is the case, it is always a good practice to use a variable naming convention that aids in identifying how the variable is being used. We’ve also declared the constants that are used by the ADOCE Open method.

    Option Explicit
    Dim rsMain                                                  ‘our recordset var
    Dim lp, lp2                                                 ‘generic loop vars
    Dim dtAppStart, dtAppEnd, dtAppTotal                  ‘application time values
    Dim dtCreateStart, dtCreateEnd, dtCreateTotal        ‘create table time values
    Dim dtInsertStart, dtInsertEnd, dtInsertTotal   ‘insert into table time values
    Dim dtUpdateStart, dtUpdateEnd, dtUpdateTotal        ‘update table time values
    Dim dtSortStart, dtSortEnd, dtSortTotal                ‘sort table time values
    Dim dtSearchStart, dtSearchEnd, dtSearchTotal        ‘search table time values
    Dim dtHrs, dtMins, dtSecs                                  ‘time segments vars
    Dim sAppTitle                                        ‘application title string
    Dim sSQL                               ‘sql string to pass to the adoce object
    Dim iIterations, iCurrentIteration               ‘for tracking test iterations
    Dim iTestRecs, iCurrentTestRec            ‘for tracking number of test records
    Dim iVal                                                 ‘random integer value
    Dim sVal                                                  ‘random string value
    Dim bETrap                                ‘true if error trapping is turned on
    Dim iFindVal                                  ‘value to conduct search against
    Dim bGridView                               ‘true if data grid is being viewed
    Dim sMBText                                                   ‘text for msgbox

    Const adOpenForwardOnly = 0                                   ‘adoce constants
    Const adOpenKeyset = 1     ‘desktop vb includes these constants, vbce does not
    Const adLockReadOnly = 1                      ‘so we need to declare them here
    Const adLockOptimistic = 3
    Const adCmdText = 1
    Const adCmdTable = 2
    Const adCmdStoredProc = 4
    Const adCmdUnknown = 8

Declaring the recordset

In the Form_Load() routine, we set the recordset variable.

    bETrap = True                            ‘set to “true” for trapping errors
    If bETrap = True Then On Error Resume Next
    Set rsMain = CreateObject(“adoce.recordset”)   ‘create rs pointer to object
    If Err Then
        MsgBox “Problem with ADOCE. “ & Hex(Err) & “ - “ & _
               Err.Description, vbCritical, sAppTitle
        Err.Clear
        App.End
    End If
    On Error GoTo 0

You’ll notice that we’re using some error checking for trapping any database errors that might occur. The bETrap variable is used as a Boolean flag to indicate if error trapping should occur or not. This is convenient during development because having the error checking off will help to reveal variable naming errors, undeclared variables, and so on. Also, unlike desktop Visual Basic, an App.End statement is required for exiting from the VBCE application.

Creating the DataBench table

In the CreateTable() routine, we first build our SQL statement with the table name and the fields to be placed in the table.

For this table, our table name is BENCHTBL and our fields are:

IKEY INT

NUMFIELD INT

TEXTFIELD VARCHAR(20)

DATEFIELD DATETIME

Valid field types are:

INT—4-byte signed integer.

FLOAT—double-precision floating point.

BIT—logical or Boolean.

VARCHAR(n)—null-terminated Unicode character string of length n, maximum of 255 characters.

DATETIME—date and/or time value.

TEXT—variable length string up to 32,000 characters.

VARBINARY(n)—binary value of length n, maximum of 255.

LONG VARBINARY—binary value of length less than 65,469 bytes.

SMALLINT—2-byte signed integer

UINT—unsigned 4-byte integer (for backward compatibility only).

USMALLINT—unsigned 2-byte integer (for backward compatibility only).

The SQL statement could be written as:

    create table benchtbl (ikey int, numfield int, textfield varchar(20),        
    datefield datetime);  

However this is difficult to read compared to:

   
    Create table benchtbl (
       Ikey int,
       Numfield int,
       Textfield varchar(20),
       Datefield datetime);

Once the SQL statement is built, it can be passed to the ADOCE object with the Open method. Example:

    msMain.open sSQL

The following subroutine combines the building of the SQL statement, passing it to the ADOCE object, trapping any errors that might occur, and updating the timestamp statistics.

    Private Sub CreateTable()                                   ‘create test table
        lblStatus.Caption = “Creating table...”
        sSQL = “create table benchtbl(“                   ‘build the sql statement
        sSQL = sSQL & “ikey int, “
        sSQL = sSQL & “numfield int, “
        sSQL = sSQL & “textfield varchar(20), “
        sSQL = sSQL & “datefield datetime);”
        dtCreateStart = calcseconds                                 ‘get timestamp
        If bETrap = True Then On Error Resume Next
        rsMain.open sSQL                                  ‘issue the sql statement
        If Err Then
            MsgBox “Create SQL error. “ & Hex(Err) & “ - “ & _
                Err.Description, vbCritical, sAppTitle
            Err.Clear
            App.End
        End If
        On Error GoTo 0
        dtCreateEnd = calcseconds
        dtCreateTotal = dtCreateEnd - dtCreateStart
        lblCreateTime.Caption = dtCreateTotal
    End Sub

When using DDL (Data Definition Language) statements for manipulating the table structure, the recordset does not remain open after the Open method is executed. Reads or writes to the table cannot take place until the recordset is reopened.

Adding data

Adding data to the table is just as easy as creating the table. There are several ways to do this. This example shows how to use the Addnew method:

    rsMain.open “mytable”, ““, adOpenKeyset, adLockOptimistic 
    rsMain.Addnew 
    rsMain.fields(“firstfield”) = “ActiveX Data Objects” 
    rsMain.fields(“secondfield”) = 1.8 
    rsMain.Update 
    rsMain.Close 

First the table is opened, then the Addnew method, which opens the table for new records, is called. The Fields collection then defines the fieldname to receive the inserted data. The Update method then stores the data in the table.

Prior to doing an Update, if you decide that you do not want to store any of the changes just made, you can use the CancelUpdate method. As:

    rsMain.CancelUpdate

Addnew can also be utilized with parameters for immediately adding data to the table. This use of Addnew does not require the use of the Update method. Either a single value can be inserted, or an array with all the values can be passed. When passing array values, the number of elements in both arrays need to be the same.

    rsMain.Addnew “Lastname”, “Smith”

    rsMain.Addnew sFieldArray(), sValueArray()

   

In the DataBench application, we’ll use SQL for adding data to the table. The process is basically the same one that we used when creating the table. First, we create the SQL statement, then we pass it to ADOCE. In DataBench, we are creating random test data, so we loop through the number of required test records for populating the table. When records are inserted with SQL, the recordset is not left open. Thus, the recordset does not need to be closed when record inserting is finished.

    Private Sub InsertRecs()                     ‘generate and insert test records
        Randomize Second(Now)
        lblStatus.Caption = “Inserting “ & cboNumRecs.Text & “ records...”
        dtInsertStart = calcseconds
        If bETrap = True Then On Error Resume Next
        For iCurrentTestRec = 1 To iTestRecs
            sSQL = “INSERT INTO BENCHTBL VALUES(“
            sSQL = sSQL & “‘“ & iCurrentTestRec & “‘, “
            sSQL = sSQL & “‘“ & Int((Rnd * 32000) + 1) & “‘, “
            sSQL = sSQL & “‘“ & Chr(Int((Rnd * 26) + 65)) & “‘, “
            sSQL = sSQL & “‘“ & FormatDateTime(Now) & “‘); “
            rsMain.open sSQL
            If Err Then
                MsgBox “Insert SQL error. “ & Hex(Err) & “ - “ & _
                    Err.Description, vbCritical, sAppTitle
                Err.Clear
                App.End
            End If
        Next
        On Error GoTo 0
        dtInsertEnd = calcseconds
        dtInsertTotal = dtInsertEnd - dtInsertStart
        lblInsertTime.Caption = dtInsertTotal
    End Sub

Updating data

To update data through the ADOCE object, we use the Fields collection and the Update method. As with the Addnew method, the Update method can be used with a Fields collection or with parameters.

With Fields collection:

rsMain.Fields(“LastName”) = “Smith”
rsMain.Fields(“FirstName”) = “Joe”
rsMain.Update

With parameters:

   RsMain.Update “LastName”, “Smith”

Or an array:

   RsMain.Update sFieldArray(), sValueArray()

SQL Update is not currently available in this version of the ADOCE control, so for the DataBench application we’ll use the native method. Because this is a benchmark program, we need to update each of the records in the table. We begin by selecting all of the records with a SQL select statement:

   SSQL = “SELECT * FROM BENCHTBL”

Then, while looping through the table, we update one of the fields. You’ll also notice that, once we’re halfway through the table, we get the value from the NUMFIELD and store it in the iFindVal variable. We’ll use this variable later on for doing a search through the table.

Private Sub UpdateRecs()                 ‘perform an update on each test record
    ‘The SQL Update statement is not currently supported by ADOCE.  So, we’ll
    ‘use the object update method for updating these records.
    
    lblStatus.Caption = “Updating “ & cboNumRecs.Text & “ records...”
    dtUpdateStart = calcseconds
    If bETrap = True Then On Error Resume Next
    sSQL = “SELECT * FROM BENCHTBL”                  ‘use sql to open the table
    rsMain.open sSQL, ““, adOpenKeyset, adLockOptimistic, adCmdText
    rsMain.movefirst
    For iCurrentTestRec = 1 To iTestRecs
        rsMain.Update “NUMFIELD”, Int((Rnd * 32000) + 1)        ‘perform update
        If iCurrentTestRec = Int(iTestRecs / 2) Then   ‘get a sample for search
            iFindVal = rsMain.fields(“NUMFIELD”)
        End If
        rsMain.movenext
        If Err Then
            MsgBox “Update error. “ & Hex(Err) & “ - “ & _
                Err.Description, vbCritical, sAppTitle
            Err.Clear
            App.End
        End If
    Next
    On Error GoTo 0
    rsMain.Close
    dtUpdateEnd = calcseconds
    dtUpdateTotal = dtUpdateEnd - dtUpdateStart
    lblUpdateTime.Caption = dtUpdateTotal
End Sub

Notice that in this subroutine we had to use the Close method. This is due to the fact that we opened the table for updating.

Removing data

There are two processes that can be used for deleting records from a table. The first process is uses the Delete method. A Delete is performed upon the current record in the table and the deleted record will remain current until you move to a different record. Also, the table must be opened as updateable prior to performing the delete. Here’s an example:

    rsMain.open “SELECT * FROM MYTABLE”, ““, adOpenKeyset, adLockOptimistic
    rsMain.movelast
    rsMain.delete
    rsMain.close

For deleting single records this works fine. However, if you need to delete a group of records that match specific criteria, then the best approach would be to utilize a SQL statement, such as:

    sSQL = “DELETE FROM MYTABLE WHERE BALANCE < ‘0’”
    rsMain.open sSQL

The Delete method supports the use of the AffectRecords parameter for maintaining compatibility with ADO desktop. However, the only value supported is 1.

Sorting the table

Sorting a table is a very simple process with SQL. In its simplest form, a table can be sorted, while being opened, this way:

   rsMain.open “SELECT * FROM MYTABLE ORDER BY LASTNAME”, ““, 1, 3

If an index has been created on the Order By field name, the parameters of the index will be utilized for the sort. Otherwise, a sort will be done in memory and an ordered result set will be opened. The default order for this type of sort is Ascending. This can be specified by adding the DESC or ASC parameter to the SQL statement. Example:

   rsMain.open “SELECT * FROM MYTABLE ORDER BY LASTNAME DESC”, ““, 1, 3

Or:

   rsMain.open “SELECT * FROM MYTABLE ORDER BY LASTNAME ASC”, ““, 1, 3

Here is our code for doing the sort in DataBench:

    Private Sub SortRecs()                                         ‘sort the table
        lblStatus.Caption = “Sorting table...”
        sSQL = “SELECT * FROM BENCHTBL “                  ‘build the sql statement
        sSQL = sSQL & “ORDER BY NUMFIELD; “
        dtSortStart = calcseconds
        If bETrap = True Then On Error Resume Next
        rsMain.open sSQL                                  ‘issue the sql statement
        If Err Then
            MsgBox “Sort SQL error. “ & Hex(Err) & “ - “ & _
                Err.Description, vbCritical, sAppTitle
            Err.Clear
            App.End
        End If
        On Error GoTo 0
        rsMain.Close
        dtSortEnd = calcseconds
        dtSortTotal = dtSortEnd - dtSortStart
        lblSortTime.Caption = dtSortTotal
    End Sub

Searching the table

In SQL, searching for a specific record or group of records can be done through the use of Where clauses that are appended to the SQL statement. These can be simple or very complex depending on the need. Here’s a simple Where clause:

   sSQL = “SELECT * FROM MYTABLE WHERE LASTNAME = ‘SMITH’” 
rsMain.open sSQL, ““, adOpenKeyset, adLockOptimistic

Here’s a more complex example:

   sSQL = “SELECT FIRSTNAME, LASTNAME, BALANCE, ACTIVE FROM MYTABLE “
   sSQL = sSQL & “WHERE LASTNAME = ‘SMITH’ “
   sSQL = sSQL & “AND BALANCE > ‘100’ “
   sSQL = sSQL & “AND BALANCE < ‘10000’ “
   sSQL = sSQL & “AND ACTIVE IS NOT NULL “
   rsMain.open sSQL, ““, adOpenKeyset, adLockOptimistic

Here is our search routine for the DataBench application. Remember that iFindVal variable we set earlier?

    Private Sub FindRec()                  ‘conduct a search for the sampled value
        lblStatus.Caption = “Searching table...”
        sSQL = “SELECT * FROM BENCHTBL “                  ‘build the sql statement
        sSQL = sSQL & “WHERE NUMFIELD = ‘“ & iFindVal & “‘; “
        dtSearchStart = calcseconds
        If bETrap = True Then On Error Resume Next
        rsMain.open sSQL                                  ‘issue the sql statement
        If Err Then
            MsgBox “Search SQL error. “ & Hex(Err) & “ - “ & _
                Err.Description, vbCritical, sAppTitle
            Err.Clear
            App.End
        End If
        On Error GoTo 0
        rsMain.Close
        dtSearchEnd = calcseconds
        dtSearchTotal = dtSearchEnd - dtSearchStart
        lblSearchTime.Caption = dtSearchTotal
    End Sub

Indexes

For increased performance of the database, indexes can be created and utilized. An index can be created for one field in the table and only one index can be open at a time. The following example shows how to create and use an index:

   sSQL = “CREATE INDEX LNAMENDX ON MYTABLE (LASTNAME)”
   rsMain.open sSQL
   sSQL = “SELECT * FROM MYTABLE ORDER BY LASTNAME”
   rsMain.open sSQL  

The sort order defaults to Ascending but can be set to descending by using DESC.

   sSQL = “CREATE INDEX LNAMENDX ON MYTABLE (LASTNAME DESC)”

Database Connectivity

Manual Importing and Exporting

Tables that have been created on the Windows CE device can be moved to Microsoft Access desktop through the use of the Import and Export Database functions in the Mobile Devices window of Windows CE Services. These can be found under the Tools menu.

To demonstrate this process, we’ll copy the BENCHTBL table from the Windows CE device to your PC:

  1. On the Windows CE Device, run DataBench.

  2. From the View menu select Data Viewer. This will create the table that we want to export. Do not exit from the Data Viewer during the export since this would delete the table.

  3. From Windows CE Services on your PC, select the Tools menu.

  4. Select Export Database Tables.

  5. Use the Browse button to select where you want the table stored.

  6. Select the benchtbl file and then click the OK button.

You’ll now be able to open up the table in Access on your PC.

Automatic Synchronizing with the Desktop

Windows CE Services can also be configured for automatic synchronization of the tables when the Windows CE device is connected. This can be done through the Tools menu of Windows CE Services on the PC. To activate, follow these steps:

  1. From Windows CE Services on your PC, select the Tools menu.

  2. Select ActiveSynch Options.

  3. Highlight Table in the Synchronization Services window, then click the Options button.

  4. Click the Add button.

  5. Select the Access .mdb file on your PC that you want to synchronize with.

  6. Now set the path, tables, and fields that you want to synchronize on the Windows CE device.

  7. Click the OK button.

The database will now be synchronized whenever you establish a connection between the Windows CE device and PC.

Note   In order for this type of synchronizing to work, your tables need to have a primary key field with a data type of AutoNumber. While this is easy to do with Access on the desktop PC, it is a little more difficult on the Windows CE device. The Windows CE-based table must have an index called PrimaryKey that is based on a single, unique-value field. To get this to work with the DataBench program, we would need to add the following line after the table is created:

    sSQL = “CREATE INDEX PrimaryKey ON BENCHTBL (iKey)”
    rsMain.open sSQL

Programmed Data Transfers with the Desktop

The ADOCE SDK comes with an API that allows the calling of the two functions used by Windows CE Services for moving files between the Windows CE device and the PC. These two functions are contained in the adofilter.dll file and are called DesktopToDevice and DeviceToDesktop. The following example demonstrates how to move a table from the Windows CE device to the PC via this API. (This example can also be found at http://support.microsoft.com/support/kb/articles/Q196/0/34.ASP.)

Steps to use (through desktop Visual Basic 6.0):

  1. In the Visual Data Manager, open Biblio.MDB.

  2. In the SQL window, insert and execute the following SQL statement:
    SELECT Authors.* INTO Authors2 FROM Authors WHERE (Authors.AU_id < 50)
    
  3. In Visual Basic 6.0, create a new standard EXE project.

  4. Add two CommandButtons (Command1 and Command2).

  5. Set Command1.caption to “Device to PC”.

  6. Set Command2.caption to “PC to Device”.

  7. Add the following code to the form module:
    Private Declare Function DESKTOPTODEVICE _
        Lib “c:\program files\windows ce services\adofiltr.dll” _
        (ByVal desktoplocn As String, _
        ByVal tablelist As String, _
        ByVal sync As Boolean, _
        ByVal overwrite As Integer, _
        ByVal devicelocn As String) As Long
         
    Private Declare Function DEVICETODESKTOP _
        Lib “c:\program files\windows ce services\adofiltr.dll” _
        (ByVal desktoplocn As String, _
        ByVal tablelist As String, _
        ByVal sync As Boolean, _
        ByVal overwrite As Integer, _
        ByVal devicelocn As String) As Long
    
    
    
    
    Private Sub Command1_Click()
        Dim result As Long, sPath As String, sTableList As String
        sPath = “c:\Program Files\Microsoft Visual Studio\VB98\biblio2.mdb”
        sTableList = “Authors2..”
        ‘ Change mouse pointer to hourglass.
        Screen.MousePointer = vbHourglass
        ‘ import table from remote device.
        result = DEVICETODESKTOP(sPath, sTableList, False, False, ““)
        ‘ Return mouse pointer to normal.
        Screen.MousePointer = vbDefault
        If result = 0 Then
           MsgBox “Transfer Successful”
        Else
           MsgBox “An error occurred transferring the data: “ & result
        End If
    End Sub
    
    Private Sub Command2_Click()
        Dim result As Long, sPath As String, sTableList As String
        sPath = “c:\Program Files\Microsoft Visual Studio\VB98\biblio.mdb”
        sTableList = “Authors2..”
        ‘ Change mouse pointer to hourglass.
        Screen.MousePointer = vbHourglass
        ‘Export table to remote device.
         result = DESKTOPTODEVICE(sPath, sTableList, False, False, ““)
        ‘ Return mouse pointer to normal.
        Screen.MousePointer = vbDefault
        If result = 0 Then
            MsgBox “Transfer Successful”
        Else
            MsgBox “An error occurred transferring the data: “ & result
        End If
    End Sub
        

Be sure to click the PC to Device button first, then the Device to PC button to complete the test. You’ll notice that the biblio2.mdb file is created when the Device to PC button is clicked. If you try this test a second time, you’ll get errors because the tables already exist on the device and on the PC.

Extending the Corporate Information Database

With the power to programmatically control the flow of data between the PC and the Windows CE device, the possibilities are unlimited. When using the ADOCE API from the PC, you can substitute a DSN (ODBC) in place of the desktoplocn parameter of the API functions. This gives you the ability to move data to and from any ODBC-compliant database that the PC is connected to.

The Possibilities

With the power of the ADOCE control, the possibilities for database connectivity to Windows CE are unlimited. We can only expect that, with any future versions of ADOCE and VBCE, the power and flexibility of the ADOCE control will greatly increase. At least now, with this version, it is now possible to put the power of Windows CE into the corporate environment.

The Author

Timothy Trimble is the President of Extended Technology Systems, based in Carlsbad, California. Extended Technology Systems provides custom software development services for handheld computers. They can be found on the World Wide Web at www.exts.com/.