The profile API and its encapsulation in a group of C++ classes

From EDM2
Jump to: navigation, search

Written by Gordon Zeglinski

Introduction

Profile Files (aka INI files) are used in most OS/2 applications. In this issue, we will look at the profile API and then encapsulate it within a group of C++ classes.

The Profile API

In this section, we will look at the functions in the profile API that will be used to create the C++ classes.

Opening the File

Before we can read or write to our own profile files, we must open the profile file. The PrfOpenProfile() function returns a handle to the opened profile file, and takes an anchor block handle and file name as arguments. The function prototype follows:

HINI PrfOpenProfile(HAB hab,PSZ ProfileName)

Closing the File

Of course, we should close any INI file we open. The handle returned by PrfOpenProfile() is this function's only argument.

BOOL PrfCloseProfile(HINI hini)

Profile File Structure

Now that we can open and close profile files, we need to write and read from them. Before we can proceed, however, we will look at how profile files are organized. Data is stored by an application name and key name. Both the application and key names are strings. One can conceptually think of the file structure as follows:

oops1.gif

Keys within a given application must be unique, but they do not have to be unique within the profile file. Application strings must be unique within the profile file.

Writing Data

Data can be written to the profile file using either of the following functions:

BOOL PrfWriteProfileData(HINI hini,
                         PSZ pszApp,
                         PSZ pszKey,
                         PVOID pData,
                         ULONG cchDataLen);
BOOL PrfWriteProfileString(HINI hini,
                           PSZ pszApp,
                           PSZ pszKey,
                           PSZ pszData);

The pData parameter in PrfWriteProfileData() is the address of the data to be written while cchDataLen is the length of the data. This function can be used to write binary data to the profile file, while the PrfWriteProfileString() function writes a NULL terminated string only.

Reading Data

The profile file API provides three functions which can be used to read in data from the application/key pair. Two of these functions are just the inverse of the two read functions, while the third function converts a number stored as a string into an integer. Finally, there is a function which returns the length of the data stored under an application/key pair. The prototypes for these functions follow:

BOOL PrfQueryProfileData(HINI hini,
                         PSZ pszApp,
                         PSZ pszKey,
                         PVOID pBuffer,
                         PULONG pulBufferMax);
ULONG PrfQueryProfileString(HINI hini,
                            PSZ pszApp,
                            PSZ pszKey,
                            PSZ pszDefault,
                            PVOID pBuffer,
                            ULONG cchBufferMax);
LONG PrfQueryProfileInt(HINI hini,
                        PSZ pszApp,
                        PSZ pszKey,
                        LONG lDefault);
BOOL PrfQueryProfileSize(HINI hini,
                         PSZ pszApp,
                         PSZ pszKey,
                         PULONG pDataLen);

The functions PrfQueryProfileSize() and PrfQueryProfileData() can be used to enumerate the application and key values (see the PM Reference for details). The functions PrfQueryProfileString() and PrfQueryProfileInt() allow the programmer to specify default values. This is very handy when the application is executed for the first time and its profile information may not be present.

Encapsulating The Profile API

As with all first attempts at encapsulation, we will wrap the profile API loosely with a C++ class. To do this, we will have member functions for reading and writing data, and data members to store the profile file's name and handle. Following is the class definition for the base ProfileFile class:

class ProfileFile {
   APIRET Error;
   HINI hini;
   HAB hab;
   PSZ FileName;
   char Close;

public:
   ProfileFile(PSZ name,HAB hb);
   ProfileFile(HINI H);
   ~ProfileFile();

   APIRET GetError() { return Error; }
   HINI GetHandle() { return hini; }

   void WriteString(PSZ App,PSZ Key,PSZ String);
   void WriteData(PSZ App,PSZ Key,void * Buff,ULONG BLen);
   ULONG GetDataSize(PSZ App,PSZ Key);
   void GetData(PSZ App,PSZ Key,void * Buff,ULONG & BufMax);
   ULONG GetString(PSZ App,PSZ Key,PSZ Buff,ULONG BufMax,PSZ DefArg=NULL);
   LONG GetInt(PSZ App,PSZ Key,LONG DefArg=0);
   void WriteInt(PSZ App,PSZ Key,LONG Num);
   PRFPROFILE Querry();
};

You will notice that each of the API functions we looked at has a corresponding member function. In addition, we added a function to write an integer that can be read later by the GetInt member function.

The system and user INI files, have predefined handles. We will subclass ProfileFile to allow us to use the same encapsulation method on the system and user INI files. Following are the definitions of these two classes:

class UserProfile:public ProfileFile {
public:
   UserProfile():ProfileFile(HINI_USERPROFILE) { }
};

class SystemProfile:public ProfileFile{
public:
   SystemProfile():ProfileFile(HINI_SYSTEMPROFILE) { }
};

The use of these classes is pretty straight forward. The following sample code will show some of the basics.

void main() { 
   ProfileFile AppINI("APP.INI");   // open an application ini file (app.ini) 
   UserProfile UserINI;             // open the user ini file (os2.ini)
   char SomeString[30];

   AppINI.GetString("Application","Key",SomeString,29,"Default String");
   UserINI.WriteString("Application","Key",SomeString);
}

The above program opens the file "APP.INI", then attempts to read a string from this file. If the application/key pair is not present, SomeString will contain the value "Default String" on return from GetString. SomeString is then written to the user INI file under the application/key pair "Application"/"Key".

The files INIFLOBJ.H and INIFLOBJ.CPP contain the source code necessary to compile the profile classes.

Summary

In this issue, we have examined the profile file API and encapsulated it. You should now be able to use profile files in your application.