HB++ Power Tip: Preferences

 

I was curious about how preferences were handled with HB++.  This article pulls together information from the Help files, the web site and my current undertanding.

 

Color key:  Main text in black, Help files in green, comments in red.

 

To understand preferences, it is necessary to start with the Application Class.  Note the pattern of inheritance, up to the Object Class.  Each Class has its own Members.  Note the Members Preferences and Preference Strings. 

Application Class

  + Object
      + Database
          + GenericDB
              + ResourceDB
                  + Application

 

Description

The Application class implements the behaviors necessary for interfacing Palm OS® and your application. This class is not instantiable or clonable. Its functions are only available by derivation.

All applications written in HB++ must declare a single unique class deriving from the Application class. This is the main class of your project, which. the system automatically creates an instance, accessible via the global App variable. If your project does not contain a class deriving from Application, or it contains more than one, a warning is generated and your program may not work properly.

You can see in the Autograph sample an implementation of the Application class called clsApplication which manages different launch modes.

 

Members

Members

Description

 

Alarm

Date and time of the next alarm.

AlarmTriggered

Activation of an alarm.

CustomLaunch

Custom application launch.

DisplayAlarm

Activation of an alarm.

ExgAskUser

Data reception request.

ExgReceive

Data reception.

FindItem

Global search.

GotoItem

Display a record.

NormalLaunch

Normal application launch.  ß This looks familiar from the Autograph sample.

Notify

Notification.

PanelCalled

Launch of a preference panel.

Preferences

Access application preferences.  ß

PreferenceStrings

Access application preferences as a string.  ß

Quit

Closes the application.

RegisterExtension

Registers the application for the reception of data.

RegisterNotify

Registers a notification request.

ReturnFromPanel

Launch after closing a configuration panel.

SubCall

Indicates if the application is already running.

SyncNotify

Startup after modifying application databases.

SystemReset

Startup after system is reinitialized.

Title

Application Title.

UnregisterExtensions

Unregisters the application for reception of data.

UnregisterNotify

Unregister a notification request.

Version

Application version.

 

Inherited from ResourceDB

Description

 

FindResource

Finds a resource in a database.

Resource

Accesses a resource in a database.

 

Inherited from GenericDB

Description

 

DeleteRecord

Deletes a record from a database.

Open

Opens a database from a DatabaseInfo object.

OpenByName

Opens a database from its name.

Record

Accesses a record in a database.

RecordCount

Number of records in a database

 

Inherited from Database

Description

 

CategoryName

Set or return a category name

Close

Closes a database.

DmOpenRef

Internal database reference.

Info

Returns a DatabaseInfo object.

 

Inherited from Object

Description

 

Recipient

Destination of events sent by the object.

Serialize

Serialization of an object into a stream.

 

 

Ok, that was interesting.  But what is a Preference?  Actually, most palm programmers know the answer to this well.  Let’s take a look at the Preference Member first.  It uses StreamMemory, which can be confusing, but it has a nice description of the Palm Preference sysem.  Just below that , we will look at the PreferenceString Member, which uses the more familiar String.

 

Preferences Property

Access application preferences.

Syntax

Public Property Get Preferences(ByVal iId As Integer) As StreamMemory
Public Property Set Preferences(ByVal
iId As Integer, ByRef objStream As StreamMemory)

Parameter

Description

 

iId

Index of preference block to set or retrieve.

objStream

A StreamMemory object containing preferences.   We will come back to this later…

 

Remarks

The Palm OS® plateform associates configuration information with each application on the handheld device. Each application thus has access to 32767 distinct memory blocks, which are saved and then restored at each synchronization. The contents of these memory blocks are not interpreted by the system. You should store all the necessary information for your program to function correctly here.

The iId parameter specifies the index of the memory block you which to access. Its value should be between 0 and 32766 inclusive. When reading, this property returns a StreamMemory object initialized with the contents of the memory block stored by the system. When writing, the objStream parameter specifies a StreamMemory object whose contents will be copied and stored by the system.

Typically, you use this property to save and restore the state of your application when launching it. The following example shows how to save and restore the state of two global variables iOption1 and sOption2 in the block 0 of the application preferences:

Public iOption1 as Integer
Public sOption2 as String
 
Public Sub SavePrefs()
  Dim s as New StreamMemory
 
  Write s, iOption1, sOption2
  Set App.Preferences(0) = s
End Sub
 
Public Sub LoadPrefs()
  Dim s as StreamMemory
 
  Set s = App.Preferences(0)
  Read s, iOption1, sOption2
End Sub

 

 

PreferenceStrings Property

Access application preferences as a string.

Syntax

Public Property Get PreferenceStrings(ByVal iId As Integer) As String
Public Property Let PreferenceStrings(ByVal
iId As Integer, ByRef sString As String)

Parameter

Description

 

iId

Index of preference block to set or retrieve.

sString

String to store in preferences.  This may look more familiar. 

 

Remarks

This property allows access to application preferences directly using a string, instead of using a StreamMemory object. Refer to the Preferences property for more information on managing preferences.

The following example shows how to save and restore the state of two global variables iOption1 and sOption2 in the blocks 1 and 2 of the application preferences:

Public iOption1 as Integer
Public sOption2 as String
 
Public Sub SavePrefs()
  App.PreferenceStrings(1) = CStr(iOption1)  convert to string before saving.
  App.PreferenceStrings(2) = sOption2  can save directly
End Sub
 
Public Sub LoadPrefs()
  iOption1 = CInt(App.Preferences(1))  and then back to an integer
  sOption2 = App.Preferences(2)  and back directly.
End Sub
 

If there are many variables whose state you want to save, or they are not of type String, it is more efficient to write them in a StreamMemory and use the Preferences property. The Autograph sample implements a class, easily reused in your own applications, to manage preferences in a simple way.  Actually, this is in the CountDown sample.  Let’s take a look at that now. 

 

The CountDown Sample

 

The CountDown Sample adds a Class called clsPrefs, which extends Object, which is the root of the Class heirarchy.  Part of the script for this Class is noted below:

 

'---------------------------- Store configuration --------------

Public Sub SavePrefs()

            dim s as new StreamMemory

 

            ' Serialize this object in a StreamMemory,

            ' and store it in the application preferences

 

            Write s, Me

            Set App.Preferences(0)=s

End Sub

 

'---------------------------- Load configuration ---------------

Public Sub LoadPrefs()

            dim s as StreamMemory

 

            ' Retrieve the application preferences, and try

            ' to serialize it in this object

 

            On Error Goto NoPref

            Set s=App.Preferences(0)

            Read s, Me

            Exit Sub

 

  ' An error occured. Initialize with default values.

 

NoPref:

            bRing=True

            iRingCount=8

            eSortOption=hbSortText

            szNextAlarmName=""

End Sub

 

Then in frmMain, we see the following:

 

Public Prefs as new clsPrefs ' Configuration

 

And then code in that app such as the following:

 

Private Sub Application_NormalLaunch()

            Prefs.LoadPrefs

 

And

 

On Error Goto 0

Prefs.bRing=bRing

Prefs.iRingCount=iCount

Prefs.eSortOption=eSort

Prefs.SavePrefs

' Close this form and exit.

Unload Me

Exit Sub

 

Here is a comment from the User Forum about this application:

 

See the clsPrefs class. This class had some members and methods. The members are the prefs.

 

We define 2 methods: LoadPrefs and SavePrefs, that directly deal with the App.preferences -ie the storage. The Object_Serialize method define how this object behave when it must deal with a stream -ie when a Read or a Write method is called with an instance of this class as parameter. (see the Read and Write calls in the LoadPrefs and SavePrefs functions)

 

It's powerful because the serialization principe can be used in several ways. If I define a StreamSocket object then Write the Prefs class to this object, the same Object_Serialize event is raised, and my prefs are then sent over the internet for example.

 

If I define a StreamFile object then Write the Prefs class to this object, the same Object_Serialize event is raised, and my prefs are then stored on a SD card...

 

OK, I was wondering about the Object_Serialize method.  Here it is…

 

Private Sub Object_Serialize(ByVal stream As Stream, ByVal eDirection As HbStream, ByVal lSize As Long)

            If eDirection=hbStreamRead Then

              ' Read member variables from the stream

                        Read stream, bRing, iRingCount, eSortOption,szNextAlarmName

            Else

                        ' Write member variables to the stream

                        Write stream, bRing, iRingCount, eSortOption,szNextAlarmName

            End If

End Sub

 

Here are some other tidbits from the Users Forum:

To delete a Preference, just set the specified preference to Nothing.

HB++ relies on the PrefGetAppPreferences/PrefSetAppPreferences APIs to implement the App.PreferenceStrings property, always passing True for the parameter specifying whether the preference should be saved or not during HotSync. If you do need preference not being saved, you'll have to declare the native function.

 

If you find any errors in this article or if you have suggestions for improvement, please drop me a note.

 

 

Jon Blackman

jab@easystreet.com

 

Updated July 5, 2004