VOICE Home Page: http://www.os2voice.org |
September 2004
Newsletter Index
|
By James J. Weinkam, D.Sc. © September 2004 |
Profile and registry are two more-or-less synonymous terms for the data structure that stores configuration information. The system, and programs running on it, can manipulate a profile dynamically. A profile must persist when the system is shut down. OS/2 prefers the term profile while Windows favors the term registry.
OS/2 has two standard profiles, the System Profile and the User Profile, in which the system stores configuration information, particularly information related to the Presentation Manager and the Workplace Shell.
OS/2 profiles are organized as sets of Key/Value pairs grouped by Application. The Application names and Keys are nul-terminated strings; the Values may be arbitrary binary data and in many instances are nul-terminated strings. In particular, the System Profile contains the Application PM_Objects which has one key, ClassTable, whose value is a table where the classes that implement the behavior of the Workplace Shell are registered along with their corresponding DLLs.
Since the profile content must persist when the system is not running, it is stored in a file. OS/2 stores profiles in files which have an .ini extension and are organized according to a standard binary format described below.
The OS/2 INI files where OS/2 saves the System and User Profiles when the system is shut down. The names and locations of the two standard INI files are specified in the environment variables SYSTEM_INI and USER_INI which are set in CONFIG.SYS. Normally these are set to b:\os2\os2sys.ini and b:\os2\os2.ini, respectively, where b: is the boot drive.
Besides the system itself various applications distributed with OS/2, such as EPM and PMSEEK and also some third party software like PMView and Mozilla, store configuration information in the standard profiles.
Instead of using the standard profiles, some components of the system and third party software use their own profiles having the same format and the .ini extension for their configuration information. For example, the OS/2 dialer, DOIP, stores its configuration in b:\mptn\etc\tcpos2.ini. Similarly, WARPIN stores its configuration and database of installed software in datbas_d.ini in the same directory as warpin.exe; it only stores the path to this directory in the User Profile under the Application WarpIN and Key Path.
To ensure the maximum possible confusion, some applications such as Papyrus, store configuration information in binary files which have the .ini extension but do not have the standard OS/2 format. Also some parts of OS/2 itself use text files with the .ini extension, such as dive.ini and mmpm2.ini.
The following format information was derived by examining and experimenting with copies of several actual ini files in the OS/2 system and several other ini files constructed for the purpose. There are a number of apparently unused fields. It is possible that some of these fields are used for purposes which did not come up in the various ini files that I examined. All offsets are in bytes from the beginning of the file. All offsets and lengths are unsigned integers.
File descriptor section (beginning at offset 0):
32 bit integer Signature? FFFFFFFF
32 bit integer Offset of first app 00000014
32 bit integer File size ssssssss
32 bit integer Unused? 00000000
32 bit integer Unused? 00000000
Application descriptor:
32 bit integer Next app aaaaaaaa
32 bit integer First pair pppppppp
32 bit integer Unused? 00000000
16 bit integer Name length mmmm
16 bit integer Name length mmmm
32 bit integer Offset of name nnnnnnnn
mmmm bytes App name Name followed by nul
Pair descriptor:
32 bit integer Next pair pppppppp
32 bit integer Unused? 00000000
16 bit integer Key length llll
16 bit integer Key length llll
32 bit integer Offset of key kkkkkkkk
16 bit integer Value length uuuu
16 bit integer Value length uuuu
32 bit integer Offset of value vvvvvvvv
llll bytes Key Key followed by nul
uuuu bytes Value Value
There is considerable redundancy in the design. In all the examples I have examined, the first application descriptor immediately follows the file descriptor, and each application name immediately follows the corresponding application descriptor. Each application's list of key/value pairs immediately follows the application name (last line of the application descriptor), and each pair's key and value immediately follows the pair's descriptor. Thus the offset fields are not really needed. Also the lengths of the name, key, and value fields are recorded twice for no apparent reason.
Values may be terminated with a nul. The name and key fields must have a terminating nul. In almost all cases the length includes the terminating nul. A special situation arises when an application name or value with length greater than 65535 bytes is stored. In this case, the entire name or value is copied into the file, but the mmmm or uuuu fields are set to the rightmost 16 bits of the actual length. Depending on what changes are subsequently made, the unretrievable bytes may eventually be eliminated. An attempt to enter a key longer than 65535 hangs the system.
The value 00000000 is used to terminate the application list and each application's pair list.
The value field is always deemed to be uuuu bytes in length even if more bytes were stored. On the other hand, if a hex editor is used to introduce a nul prior to the mmmm-th byte of a name field or the llll-th byte of a key field, that nul-terminates the name or key, the length fields are adjusted accordingly and the extra bytes eliminated the next time the file is written.
The API calls (described below) do not enforce any other restrictions on the content of the name and key fields although the use of ascii values between 1 and 31 inclusive or greater than 127 in these fields may present challenges in some situations, particularly when exporting and importing.
No information about the "type" of the value field is stored. The API calls allow values to be stored as strings or binary values and retrieved as string, binary, or 32 bit integer.
Many OS/2 users run 16 bit Windows applications in Winos2 or 32 bit applications using Odin or Open32. Accordingly, OS/2 includes b:\os2\mdos\winos2\reg.dat, a Windows 3.1 registry file, and b:\os2\system\system.dat and b:\os2\system\user.dat, Windows 95/98 registry files.
The format of all the different Windows registries is readily available at http://www.wotsit.org/ so I will not present the details here.
However it is worthwhile to mention a few qualitative differences in the OS/2 and Windows approaches to managing the registry.
The most obvious difference is that the Windows registry is a forest which can have a list of Key/Value pairs at any node whereas each OS/2 profile is a list of lists of Key/Value pairs.
Another difference is that each value stored in the Windows registry has a type recorded with it (string, binary, or doubleword) whereas the values stored in the OS/2 profiles are essentially untyped.
The format of the Windows registry changes every couple of versions; the structure of the OS/2 profiles has remained the same since it was introduced. The latest Windows version, used in Windows NT and 2000, is not supported in OS/2 which means that recent Windows programs that rely on the additional data types added to the registry in Windows NT and 2000 are likely to present difficulties when they are run under Odin.
The file structures used to store the various versions of the Windows registry are considerably more complex than that used to store the OS/2 profiles. In particular, all of the Windows formats use several types of blocks within the file separating the linkage information that specifies the structure from the names and values. When information is deleted from an OS/2 profile it disappears entirely from the corresponding INI file. When information is deleted from the Windows registry it is unlinked from the data structure but remains in the corresponding file until the space is reused.
A problem that both OS/2 profiles and the Windows registry suffer is that both system software and application programs sometimes abandon entries that are no longer needed rather than delete them. Over time these useless entries accumulate, increasing the disk space and memory space needed as well as the processing time required to interrogate or modify the profiles.
Utilities such as checkini and cleanini analyze the ini files and delete these useless entries for OS/2. A similar utility is available in Windows.
OS/2 profiles, whether standard or application specific, can be interrogated and updated by programs using the following API calls. They are described in detail in the Presentation Manager Programming Guide and Reference found in the Toolkit documentation. A brief overview of these API calls follows. A detailed discussion is beyond the scope of this article.
PrfCloseProfile
PrfOpenProfile
The profile to be interrogated or updated is identified by a handle which is obtained by opening the profile. PMSHELL always has the System and User profiles open, but if a user program wishes to interrogate of modify these profiles, it must open them itself. After processing of a profile is completed, the handle should be closed. While a profile is open, its contents are held in an internal data structure. If an API call changes a value or adds a new one, the change is visible immediately to any interrogating API call even though the corresponding INI file may not have changed. Approximately once every 5 minutes the system writes the current state of any open profile that has been changed to its corresponding INI file.
PrfQueryProfile
PrfResetProfile
Certain applications, such as logon or logoff programs, may need to change which INI files are being used as the System and User profiles. PrfQueryProfile obtains the names of the System and User profiles that are currently active. PrfResetProfile switches to new profiles and notifies all open applications of the change. Applications respond by interrogating the new profiles and altering their configuration accordingly.
PrfWriteProfileData
PrfWriteProfileString
Values can be written to an application and key within a profile either as arbitrary binary data or as a nul-terminated (asciiz) string. If both the application and key already exist, the new value replaces the old. Data of any length may be written but there is no mechanism for retrieving more than 65535 bytes. In fact, if the total number of bytes written (including the terminating nul in the case of PrfWriteProfileString) is N, all N bytes are stored in the INI file, but the stored length that governs the number of bytes that can be retrieved is mod(N, 65536).
By using appropriate combinations of null application, key, and value pointers together with a zero value length, the PrfWriteProfileData function can also delete keys from an application, to delete an entire application, or even to empty the entire profile.
PrfQueryProfileSize
Since retrieved values can be up to 65535 bytes long, it is useful to know the buffer space needed before requesting a value.
PrfQueryProfileData
PrfQueryProfileString
These functions retrieve the value for a specific application and key, obtain a list of all keys for an application (by providing a nul key), or obtain a list of all applications (by providing a nul application). When retrieving a value, PrfQueryProfileString transfers uuuu bytes to the buffer, where uuuu is the length of the value recorded in the profile even if some of them are nul. If the buffer size, l, is less than or equal to uuuu, PrfQueryProfileString transfers l-1 bytes, followed by a nul. Despite its name PrfQueryProfileString does not guarantee that its returned value is a nul-terminated string.
PrfQueryProfileInt
If the value for a specific application and key is a nul-terminated string that contains an integer in character form, the value can be retrieved as a 32 bit integer. If the value is not of this form, the returned value is 0.
Users can also manipulate profiles in REXX using the SysIni utility function. This function can be used to perform any operation the API calls can do by appropriate specification of parameters. A complete description is given in the online REXX documentation.
Actually, my first experience in manipulating INI files was using REXX to transfer APL keyboard customizations from one system to another. IBM's APL2 has an extremely versatile keyboard customization scheme; however, setting up a complete layout is a tedious and time consuming process.
Ted Edwards and I had developed a keyboard layout for APL2 for DOS back in the early 90's that had the following useful characteristics:
In the DOS implementation of APL2, the keyboard layout information is directly accessible to a running APL program, so moving customizations from one system to another is not a problem. However in the OS/2 implementation the specifications for all the available system and user defined keyboard layouts are stored in the User Profile and APL2 provides no direct access to the Profile API functions.
In 1998, I had upgraded my APL2 from DOS to OS/2 several months earlier than Ted. When he decided to upgrade, the problem was to transfer the customizations that I had painstakingly worked out for my system to his without having to reenter them by hand. The following REXX program, mergeapp.cmd, was originally written to solve that problem and has evolved a bit since then.
/* JJW 19990927 -- mergeapp.cmd */ /* Merge or copy one or ALL: applications from one ini file to another */ /* (c) 1999, James J. Weinkam, All rights reserved. */ call RxFuncAdd 'SysIni','RexxUtil','SysIni' parse arg APP', 'FROM', 'TO', 'COPY TO = strip(TO); COPY = ',' || strip(COPY); if APP='ALL:' then do if 'ERROR' = SysIni(FROM, 'ALL:', 'app.') then do say 'Error reading ini file' FROM exit end end else do app.0=1 app.1=APP end do j=1 to app.0 if 'ERROR' = SysIni(FROM, app.j, 'ALL:', 'ky.') then say app.j 'not found in' FROM else do if pos(COPY, ",,COPY,copy,Copy") > 1 then call SysIni TO, app.j, 'DELETE:' do i=1 to ky.0 call SysIni TO, app.j, ky.i, SysIni(FROM, app.j, ky.i) end end end exit
The following command script, saveapl.cmd, extracted the relevant customization information from the ini files on my system:
call mergeapp APL2 KEYBOARD, %1:\os2\os2.ini, %2
call mergeapp APL2 SESSION MANAGER, %1:\os2\os2.ini, %2
call mergeapp APL2 OBJECT, %1:\os2\os2.ini, %2
This was accomplished using the command
saveapl d a:\saveapl.ini
Installing the customizations on another system is even easier using the command
mergeapp ALL:, a:\saveapl.ini, d:\os2\os2.ini, copy
REGEDIT2 is a PM program included with OS/2 which views and edits any OS/2 ini file. This includes not only the SYSTEM and USER ini files, normally b:\os2\os2sys.ini and b:\os2\os2.ini where b: is the boot drive, but also any other file following the same format that is used by a component of the system or an application. The standard OS/2 ini files are identified as HINI_SYSTEM_PROFILE and HINI_USER_PROFILE; other opened ini files are identified by their names.
REGEDIT2 can also view or edit the 32 bit Windows registry files that are included in OS/2 to allow windows applications to run. These files are b:\os2\system\system.dat and b:\os2\system\user.dat. Unlike the OS/2 files which have just two levels, application and key/value, the Windows-style registry files are tree structured to arbitrary depth. The Windows registry files are identified as HKEY_LOCAL_MACHINE, and HKEY_USERS. REGEDIT2 is unable to open arbitrary .dat files having the windows structure. In addition, REGEDIT2 displays the identifiers HKEY_CLASSES_ROOT, an alias for HKEY_LOCAL_MACHINE\SOFTWARE\Classes, and HKEY_CURRENT_USER, an alias for HKEY_USERS\.default.
The REGEDIT2 window is divided into two panes which can be arranged either horizontally or vertically using the Split option in the View menu. Upon starting REGEDIT2, the standard ini files are displayed in one pane of the window. The Open option of the Files menu can make other ini files available. Clicking on any available ini file causes each application in the file to be displayed as a folder. Clicking on a folder causes the key/value pairs in that application to be displayed in the other pane.
REGEDIT2 classifies each value in an OS/2 profile as string, dword (32 bit integer), or binary. If the last byte of a value is nul and all other bytes are between ascii 32 and ascii 127 inclusive, the value is considered a string. Failing that, if the value is 4 bytes long, it is considered a dword. Otherwise, the value is deemed to be binary.
The fact that it is REGEDIT2 and not the API that is making this type determination can be demonstrated by a series of experiments using REGEDIT2 itself and a hex editor.
To avoid the risk of corrupting your real ini files, start by opening a test ini file. Pick any application and open it. Add a new string calling it anything you like and give it the value "ABC". It is displayed as a string value. Now modify the value by deleting the C and inserting the character ascii 01 using the alt key and the numeric keypad. Now close the application and reopen it. Your new "string" is now classified as dword. Modify this value changing the 01 to 43. Close and reopen the application. Your value is a string again! Modify the string again, this time inserting the alt-01 between the A and the B. Close and reopen the application again. Now the value is classified as binary and the terminating nul is displayed as part of the value.
Outside of REGEDIT2 use a hex editor to change a character in a string value to a non zero value outside the range 32 to 127 inclusive. Run REGEDIT2 and open the ini file. Open the relevant application and you see that the string has become either dword or binary depending on whether or not the length of the value is four.
These experiments show that the "type" as displayed by REGEDIT2 is not a property of the key but is assigned by REGEDIT2 by analyzing the value itself. Moreover, REGEDIT2 uses a narrower definition of string than the API does. Nevertheless it permits you to insert into a "string" characters which it does not consider valid string characters, thereby essentially "converting" the value to binary or dword. REGEDIT2 does not detect this "type change" until you close and reopen the application.
REGEDIT2 is also supposed to have the ability to export and import an entire ini file or any selected application from an ini file. Unfortunately, this capability only works in simple special cases. In fact it could not be made to work in general without a major redesign. Fortunately, these simple cases cover many, possibly even most, of the situations that arise in practice.
REGEDIT4 [file] [file\application1] key1=value1 ... keyn=valuen ...where,
Here is an example of an exported file:
REGEDIT4 ["E:\PLI\TESTINI.INI"] ["E:\PLI\TESTINI.INI"\App One] String1="ABC" String2="12564" Binary=hex:32,33,34,35,36,37,38 Dword=dword:675bcd15 Long String="A long enough string value to require more than two lines in the"\ "exported format; to achieve this we need to run on and on for a while to a"\ "ccumulate enough characters." Long Binary=hex:01,02,03,04,05,06,07,08,09,0a,0b,0c,0d,0e,0f,10,11,12,13,14,15,\ 16,17,18,19,1a,1b,1c,1d,1e,1f,20,21,22,23,24,25,26,27,28,29,2a,2b,2c,2d,2e,2f,\ 30,31,32,33,34,35,36,37,38,39,3a,3b,3c,3d,3e,3f,40,41,42,43,44,45,46,47,48,49,\ 4a,4b,4c,4d,4e,4f,50
Using the API function PrfQueryProfileInt to read the values of String1, String2, Binary, and Dword yields 0, 12564, 0, and 0, respectively.
REGEDIT2 can also export and import to the Windows registry. Here file must be one of HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, or HKEY_USERS and the [file\application] lines are replaced by lines of the form
[file\folder1] [file\folder1\folder2] [file\folder1\folder2\...\foldern]
Folders with key/value pairs are immediately followed by a list of these. The special key "@" specifies a default value. Exporting works correctly subject to the limitations of the format.
For early versions of REGEDIT2, importing works correctly only if there is only one application, there are no problem characters in the keys or strings, and there are no binary or string values spread over more than one line. Problem characters in keys include =, ", CR and LF and perhaps others. In strings the major offender is the " character. If the =" combination appears in the key of a string pair, it is mistaken for the = which separates the key from the value and the " that delimits the value. Similarly, " characters cause problems within string values because no escape mechanism is used. If a binary or string value is spread over n+1 lines, instead of simply deleting the n \ characters, REGEDIT2 replaces them with random bytes and deletes the last n bytes. Thus the length is correct but the data is corrupted.
The version of REGEDIT2 that comes with the latest convenience pack (MCP2), or convenience pack fixpack (XR_C004), imports string and binary values spread over more than one line correctly, but still cannot to deal with problem characters in keys. It also imports more than one application from the same file. I do not know exactly when the fix first appeared.
REGEDIT2 appears to use the API functions correctly to update a profile, but frequently gets confused in keeping its display up to date following a series of changes. The solution to this problem is either to go to the View menu and click on Refresh (this can also be done by pressing Ctrl-R) or to exit the program and restart it.
In summary, REGEDIT2 can be used to browse the OS/2 ini files and windows registry files and also to make simple modifications. The import and export facilities only work correctly in restricted simple cases and carry the risk of file corruption. Backing up portions of the registry is best accomplished by using the REXX SysIni function.
Feature Index
editor@os2voice.org
< Previous Page | Newsletter Index | Next Page >
VOICE Home Page: http://www.os2voice.org