> developer support home

SEPTEMBER 1993 VOLUME 5 NUMBER 9


INDEX


MAD'S COLUMN

If I look closely at my plate of developer food, I've got questions. I've still got the same four basic food groups: tools, addressing, optimizing and portability across platforms. I've got technological and philosophical issues about how much of each food group constitutes a "good" diet. I'd hate to find out that my two extra helpings of optimizers actually added poundage to my code.

Maybe I should check into a "code control clinic" to determine which group has the best trained staff and to make sure that my multi-vendor solutions are nutritionally balanced.

Is there a staff doctor or nutritionist available 24 x 7 for support therapy? And what about cholesterol? Am I unknowingly clogging my bus lines and making my CPU-heart beat erratically? Where do I exercise?

But that is this week. Next week, I'll probably be multimedia-ing my existing source using both digital audio and full-motion video into some sort of PLD (Programmable Logic Dance), so that I can play back a meeting in my hotel room or office in full 3-D sensaround detail.

I'm planning on being hungry! I may not even care which food group I pick from as long as it tastes good. I just hope my metabolism can handle whatever load I give it. This could lead to a whole new world of meaning for "Slim, Trim, Coding Machine."

Happy_Programming!

Mad Poarch
Director
Developer Support/Service


ARTICLES :

New Lock Mechanism for NetWare Btrieve v6.10b

Btrieve is Novell's complete key-indexed record management system designed for high-performance data handling and improved programming productivity. Btrieve allows your application to retrieve, insert, update, or delete records either by key value or by sequential or random access methods.

NetWare Btrieve is the server-based implementation of Novell's tried-and-tested record manager. It is implemented as an NLM for NetWare 3.x and 4.x. This article discusses a new design feature of NetWare Btrieve v6.10b, specifically: concurrency inside concurrent transactions and lock sharing with multiple cursors.

Novell has added two significant enhancements to NetWare Btrieve (NLM) v6.10b:

  • Record-level locking within concurrent transactions
  • Lock sharing with multiple cursors.
In the earlier releases of NetWare Btrieve, record locking inside a concurrent transaction was converted to page-level locking. In the new release a true record-level lock is used. Also, with previous releases, multiple cursors in the same file within the same application could block one another.

In NetWare Btrieve v6.10b, the same record can be locked by different cursors on behalf of the same client within a single application. In this article, multiple cursors in an application refers to cursors belonging to a single client within that application. (A "single-client" application is one that uses the BTRV function call and all Btrieve requests are only executed on behalf of that client. A "multiple- client" application is an application that uses the BTRVID function call and Btrieve calls are executed on behalf of the individual client whose ID is specified in the BTRVID function call.)

For simplicity, this article refers to new and old implementations to distinguish between different revisions. The "old implementation" refers to NetWare Btrieve v6.0, v6.0a-d, v6.10 and v6.10a; and the "new implementation" refers to NetWare Btrieve v6.10b and above.

Characteristics Common to All Versions

In all versions of NetWare Btrieve, any Insert, Update, or Delete operation within a concurrent transaction locks the data pages and any index pages modified for the duration of that concurrent transaction. So, if a record is updated within a concurrent transaction, the second user is unable to update or delete other records that either reside on that data page or use the same index page.

In addition, "simple reads," or reads operations without any lock bias, within a concurrent transaction will not lock the corresponding data and index pages.

Finally, record locks are owned (controlled) by the cursor, or positioning within a file. If a file is opened multiple times by a single client within an application using different position blocks, each position block contains independent positioning information within that file. Individual position blocks are referred to as cursors. If a NetWare Btrieve client has multiple cursors for a particular file, specific record locks obtained by one cursor cannot be released by another cursor.

New Characteristics: Record Locking inside Concurrent Transactions

The first difference between the old and new implementations is record locking within concurrent transactions. In the old implementation, the locking inside a transaction took place at the page level. The new implementation provides more concurrency by allowing true record-level locking. An explicit record lock (set by adding a bias to the Get and Step operations or Begin Transaction) does not lock the corresponding data page; it only locks that particular record. To demonstrate this, examine the examples at left. In each of the examples, Record 1 and Record 2 reside on the same data page.

In Figure 1, User B receives status 84 (Record In Use) on the Read operation using old revisions because User A's Read+Lock has locked the data page. In the new implementation, since the page is not locked by User A, User B successfully reads Record 2; both users are able to read and lock their respective records. Later, after User A updates record 1, the page is implicitly locked with either implementation. User B must wait until User A aborts or ends that transaction before continuing with the update.

FIGURE 1: Explicit record lock within concurrent transaction

 USER A                        | USER B
==============================|=============================
Begin Concurrent Transaction  |
------------------------------|-----------------------------
                              | Begin Concurrent Transaction
------------------------------|-----------------------------
Read+Lock Record 1            |
(page locked with old         |
implementation,               |
not locked w/ new)            |
------------------------------|-----------------------------
                              | Read+Lock Record 2
                              | (status with old imple-
                              | mentation status 0 w/new)
------------------------------|-----------------------------
Update Record 1               |
(page locked implicitly       |
w/ either implementation)     |
------------------------------|-----------------------------
                              | Update Record 2
                              | (USER B w/ either
                              | implementation)
==============================|=============================

END of FIGURE 1
Successful locking of a record (inside or outside of a transaction) guarantees that no other client (not to be confused with "no other cursor") may update or delete that record. In other words, when a user performs an update or delete operation on a record which he has previously locked, he will eventually succeed unless a deadlock situation is detected. A deadlock occurs if two clients are waiting for each other to release a resource which is locked by the other. If a user obtains a lock on a record and the corresponding data page or index page is locked implicitly by another client in a concurrent transaction, waiting for the data page to be released will produce a deadlock situation. Then, Btrieve will return status 78 (Deadlock Detected).

In the example in Figure 1, User B waits until User A aborts or ends the transaction. However, in the example in Figure 2, Btrieve detects a deadlock; User B is waiting for User A to release Record 1 while User A is waiting for the data page to be released in order to execute the update.

FIGURE 2: Record locking in deadlock situation

 USER A                  | USER B                   | STATUS
========================|==========================|========
Begin Concurrent Trans. |                          |   0
------------------------|--------------------------|--------
Read+Lock Record 1      |                          |   0
------------------------|--------------------------|--------
                        | Begin Concurrent Trans.  |   0
------------------------|--------------------------|--------
                        | Read+Lock Record 2       |   0
------------------------|--------------------------|--------
                        | Update Record 2          |   0
------------------------|--------------------------|--------
                        | Read+Wait Lock Record 1  | USER B
                        |                          | waits
------------------------|--------------------------|--------
Update Record 1         |                          |  78
========================|==========================|========

END of FIGURE 2

Lock Sharing with Multiple Cursors

In the new implementation, if a client of an application opens the same file multiple times, the locks issued by different cursors within the same application do not block each other. In the previous implementation, cursors were treated as completely independent clients. Thus, if a record was locked by one cursor, the second cursor of the same client would not be able to obtain a lock on the same record. As mentioned previously, cursors in the new implementation do not block each other from locking the same record, but they are still independent in the sense that they cannot explicitly unlock (using the Unlock operation) the records that were locked by the other cursors. In Figure 3, with the new implementation, Cursor 1 and Cursor 2 can lock the same record, but the update by Cursor 1 fails with status 80 (Conflict Error).

FIGURE 3: Lock-sharing with multiple cursors (Case 1)

 USER A/             | USER A/             | STATUS  | STATUS
CURSOR 1            | CURSOR 2            | (New)   | (Old)
====================|=====================|=========|========
Read+Lock Record 1  |                     |    0    |   0
--------------------|---------------------|---------|--------
                    | Read+Lock Record 1  |    0    |  84
--------------------|---------------------|---------|--------
                    | Update Record 1     |    0    |  N/A
--------------------|---------------------|---------|--------
Update Record 1     |                     |   80    |   0
====================|=====================|=========|========

END of FIGURE 3
This status is returned because Cursor 2 has already updated the record and Cursor 1 must re-read the record before updating it. In the old implementation, the application will never reach this point and will receive status 84 on the read by the second cursor.

Thus, in the new implementation, after Cursor 1 has read a record with a lock, Cursor 2 can update or delete the record regardless of whether Cursor 2 has locked the record (see Figure 4). Cursor 1 will not receive an status 80 until it tries to delete or update that record. In the old implementation, Cursor 2 would receive a status 84 on a read if a lock bias is used or a status 84 on an Update operation if regular read without any lock bias is used.

FIGURE 4: Lock sharing with multiple cursors (Case 2)

 USER A/             | USER A/             | STATUS  | STATUS
CURSOR 1            | CURSOR 2            | (New)   | (Old)
====================|=====================|=========|========
Read+Lock Record 1  |                     |    0    |   0
--------------------|---------------------|---------|--------
                    | Read Record 1       |    0    |   0
--------------------|---------------------|---------|--------
                    | Update Record 1     |    0    |  84
--------------------|---------------------|---------|--------
Update Record 1     |                     |   80    |   0
====================|=====================|=========|========

END of FIGURE 4
With multiple cursors inside a concurrent transaction, locks obtained on a cursor before the application starts a concurrent transaction are automatically released when the cursor becomes an active participant of that transaction. A cursor becomes an active participant of a concurrent transaction if a lock is requested or if an insert, delete, or update operation is executed with that cursor. This situation is shown in Figure 5.

FIGURE 5: Multiple cursors within a concurrent transaction

 USER A/          |USER A/           |USER B           | STATUS
CURSOR 1         | CURSOR 2         |                 |
=================|==================|=================|=======
Read+Lock Rec.1  |                  |                 |   0
-----------------|------------------|-----------------|-------
                 | Read+Lock Rec.1  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |  84
-----------------|------------------|-----------------|-------
Begin Concurrent |                  |                 |   0
Transaction.     |                  |                 |
-----------------|------------------|-----------------|-------
Read+Lock Rec.1  |                  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |  84
-----------------|------------------|-----------------|-------
End Transaction  |                  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |  84
-----------------|------------------|-----------------|-------
                 | Update Record 1  |                 |   0
-----------------|------------------|-----------------|-------
                 |                  | Read+Lock Rec.1 |   0
=================|==================|=================|=======

END of FIGURE 5
Notice that all locks in Figure 5 are single, no-wait locks. The transaction does not have any affect on the inactive cursors. In other words, locks obtained before the transaction are still maintained after ending or aborting the transaction for inactive cursors.

This article has discussed two major issues with the new Btrieve locking mechanism. First, more concurrency is achieved by allowing record-level locking inside concurrent transactions. Second, the ability to share locks between multiple cursors held by one client on the same file in an application has been added.

NetWare Btrieve v6.10b is now available on NetWire at no charge to U.S. and international customers. The following files are located in Library 7 and have been compressed using PKZIP:

  • BTR61.EXE (707K) - software files
  • BTR61M.EXE (128K) - ASCII manual
At 9600 baud, downloading the files takes about 30 minutes. If you wish to receive the product on diskette, call 1-800- UPDATE1 (domestic customers) or 317-364-7276 (international customers) and order the product for US$49.95 plus shipping and handling. You may also place orders by fax by calling 317-364-0787.

The NetWare Btrieve v6.1x Developer's Kit Supplement is available to registered members of the Novell Professional Developers' Program.

What's in the Box? Novell's NLM Certification Kit

The NLM Certification kit was developed by Novell Labs to ensure that NLM-based products meet Novell's criteria for "well-behaved" NetWare applications. This kit contains all the tools and information needed to perform the same tests Novell Labs applies to third-party products submitted for certification.

The NLM Certification Kit now contains a new test tool, NControl, that was developed by the Novell Provo System Test Group. This kit is included as a component of the NLM SDK. This article presents a brief overview of the functionality of this testing kit.

Automation Tools

The NLM Certification Kit includes several utilities and tools to automate the testing procedure.
NControl
NControl is an automated testing tool designed to test DOS, Windows, OS/2, and NLM applications developed for use with NetWare. It is an excellent tool for testing applications with user interfaces. It replaces the MASTER.NLM that was previously included with the NLM Testing Kit. NControl has all the functionality of MASTER.NLM, with additional features, so you can use the same test suites that were used with MASTER.NLM. NControl is also shipped with the Yes, NetWare Tested and Approved Software Test Kit from Novell Labs.

NControl offers a record mode that captures keyboard or mouse input and automatically creates a test program (written in C language). It also has a playback mode that executes the test program and logs the results. The test programs created by NControl can be compiled and used as generated, or can be customized to support more specific testing. A set of APIs are included to assist you in customizing your test programs.

An NControl record session creates C source code to play back a set of keystrokes and mouse operations, and to check the playback results against reference results. The compiled code is the test playback program.

The test programs generated with NControl create a master process that controls and verifies the execution of a slave workstation. Under DOS, the slave and master processes must run on separate machines. In the graphical environment, the master process controls the workstation using messages and APIs and can control the workstation on which it is running. During playback, discrepancies are written to an error log and the status of the playback is written to a general log file.

The text-based applications check playback results by taking a snapshot of the screen during the record session and comparing the playback screen results to the snapshot. In the graphical environment, the state and attributes of the window are included in the source code, and the window state and attributes must match during playback. Bitmaps in the graphical environment may also be used to check the playback.

NetWare Job Server
Job Server (JSERVER.NLM) is a script driven tool designed to automate software testing environments so that NetWare users, groups, and trustee rights can be duplicated easily on different servers. Job Server can also control the sequence of loading automated test NLMs (i.e., NControl script NLMs), including the number of times a sequence is repeated. Job Server runs as an NLM and uses NetWare's QMS (Queue Management System). Once loaded, Job Server attaches to a server as a job server account and services assigned job queues.
The DO_REC Utility
DO_REC is a simple DOS utility for recording keystrokes used when executing DOS applications. The keystrokes recorded by DO_REC are placed in a key file and may be played back using DO_PLAY. Up to 512 keystrokes may be recorded in each DO_REC session.

DO_REC can only record keystrokes of a single application. It cannot perform any logical branching based on the state of the application being executed or screen contents. An example of using DO_REC would be:

DO_REC syscon syskeys
where syscon is the program whose keystroke sequences will be stored in the file syskeys.
The DO_PLAY Utility
DO_PLAY is a DOS utility which replays the keystrokes recorded by DO_REC. An example of using DO_REC would be:
DO_PLAY syscon syskeys
The keystrokes are fed to the application at the rate of about three per second (one keystroke every five clock ticks).

Verification Utilities

The purpose of verification utilities is to provide you with the statistics of behavior testing. The utilities do not perform any test but rather provide information about behavior testing being performed.
Procedure Coverage Logger (PCL)
The Procedure Coverage Logger (PCL), is used to verify that the exercising procedure of a product provides adequate coverage of the functions declared in the source code.

If PCL reports that your exercising procedure executes less than 100% of the declared functions, you know that your exercising procedure is inadequate. On the other hand, if PCL reports that all of the functions have been executed, then you know that your exercising procedure is adequate.

Using the PCL utility in the NLM testing process, you are able to:

  • Dynamically monitor which public symbols have been called
  • Dynamically track how often selected sections are called
  • Dynamically monitor all NetWare resources used by your product
  • Generate ASCII text reports
  • Can simultaneously monitor several NLMs without affecting the performance of the NLMs being monitored
  • Automatically monitor NLMs auto-loaded or spawned by your NLM, provided the NLMs have the necessary debugging information (NetWare 4.x only).
The Procedure Coverage Logger consists of a single NLM, called PCL.NLM. Tutorials are also provided in the NLM Certification Kit to demonstrate the functionality of PCL.

Monitoring Utilities

The NLM Certification Kit provides utilities to monitor the behavior of your NLM.
The Sentry Utility
A key requirement of "well-behaved" NLMs is that they frequently relinquish the control of the CPU. The Sentry Utility (SENTRY.NLM) monitors the length of the time taken by all execution threads of the file server. Once Sentry has started to monitor a set of execution threads, it automatically monitors any new threads that are created, and retains the information of any thread that is destroyed.
The Protect Utility
The Protect Utility (PROTECT.NLM) monitors all memory accesses from NLMs loaded via PROTECT.NLM. If an NLM accesses any memory that the Protect Utility considers suspicious, it stops the execution of that NLM and reports the instance on the screen. PROTECT.NLM can be used to verify that an NLM meets the requirement forbidding illegal memory accesses. Right now, PROTECT.NLM only supports NetWare 3.11.
The Starver Utility
The Starver utility (STARVER.NLM) is used to monitor memory allocation requests made by NLMs, and to selectively refuse them. This allows you to monitor the behavior of your NLM in scarce memory conditions and determine how your product handles situations where it can not get the memory it needs for proper operations.
User Activity Simulators
The following utilities simulate the activity of several users on the workstations and relieve the necessity of actually placing human users on the network to simulate certain test conditions:
  • DO_BTRV (DO_BTRV.EXE)

    DO_BTRV simulates the Btrieve record management of several network database users. It creates a database with two different indices, fills it with over 1900 records, performs various sorts and queries, and then deletes it.

  • DO_PRINT (DO_PRINT.EXE)

    This utility simulates the file printing requests of as many as 40 individual users. It generates a specified number of ASCII text files, and sends them to the network's print services. The user instructions for DO_PRINT include directions for building a mock-printer; a device allowing you to fully exercise print services on a network without the need for a physical printer or paper.

  • DO_FILE (DO_FILE.EXE)

    DO_FILE simulates the network file activity of dozens of network users. It creates a file, copies 4Kb into it, closes it, locks it, unlocks it, and performs various other file oriented task on it several times a second.

Miscellaneous Utilities

Five more utility NLMs bring additional functionality to the NLM Certification Kit.
The MemMap NLM
The MemMap NLM (MEMMAP.NLM) displays the addresses of the code and the data area of each NLM loaded on the file server. This utility, in conjunction with PROTECT.NLM, is useful in determining whether memory access reported by Protect as suspicious is really illegal or not. For example, Protect might report a memory access as illegal, but by looking at that address you discover that the address belongs to the data area of another NLM in the same product.
The Sets NLM
The Sets NLM (SETS.NLM) gives a menu driven interface for altering the system parameters for the NetWare Operating System. The same functionality can also be achieved with the system console command, "Set." This NLM is useful for performing behavior testing of NLMs. (SETS.NLM supports NetWare 3.x only. SERVMEM.NLM is included for 4.x NLMs)
The Mod NLM
This NLM (MOD.NLM) generates a report on all the modules loaded on the file server. This report contains the same information that is displayed by the system console command "modules."
The ReadBind NLM
The ReadBind NLM provides a menu-driven method of examining the contents of the file server's bindery. This utility is useful in verifying the bindery objects used and created by an application.
The Spawn Trap NLM
Spawn Trap (SPWNTRAP.NLM) is a work-around utility for testing NLMs that spawn other NLMS (in NetWare 3.1x). Normally, calls to spawnlp or spawnvp cause other NLMs to be loaded programatically. However, this feature prevents some NLM testing tools (PCL in NetWare 3.1x environment) from monitoring behavior of the spawned NLMs. When Spawn Trap is loaded before a test session, it intercepts attempts by one NLM to spawn another, and allows the user to manually load the spawned NLM. Then, you can load the spawned NLMs through one of the testing utilities. In the NetWare 4.x environment, SPWNTRAP.NLM is not needed since, in that environment, PCL can detect the behavior of spawned NLMs that have the needed debugging information.

The NLM Certification Kit is a valuable collection of utilities and tools to test your NLM, even if you do not plan to certify it. If you do plan to have your NLM certified by Novell, contact Novell Labs at 1-800-453-1267 x5544 or 1-801- 429-5544. When your product passes Novell's testing process, it will be authorized to display the "YES! NetWare Tested & Approved NLM" certification mark.


DEVELOPER NEWS:

NOVDEV: New Developer Area on CompuServe

Novell is pleased to announce the unveiling of the new Novell developer area on CompuServe. This area, called NOVDEV, will provide common services for all Novell developers creating applications with Novell development tools.

This area provides an exclusive developer interface for support, patches, periodicals and product information, as well as information on all of the programs and services provided for members of the Novell Professional Developers' Program.

Why Make a New Area?

Many times in the past, Novell developers have found it necessary to search through several forums in several different areas in order to find information or resolve a development problem. At times, this process could be frustrating.

Over time, the complexity increased as Novell's product line increased and additional services were introduced. For example, Developer Support was provided though several sections on NOVC as well as sections of the Developer Relations forum, while patches were posted to the NOVFILES forum.

After analyzing this situation, the forums were reorganized to make life easier for the Novell customer by providing a central point for developer services, support and information. Whether you would like to join the a Novell Developer Program, ask a technical support question, find out about a new SDK, or look up a technical article from a past issue of Novell Professional Developer Bullets, all of this information is here at your fingertips.

New NOVDEV Area Layout

Once you type "GO NOVDEV" at the CompuServe "!" prompt, you will see a main menu corresponding to the map in Figure 6. The menu contains several options that are available from the NOVDEV main menu. The general layout of the new NOVDEV area is shown in Figure 6.

FIGURE 6: Layout of new NOVDEV area

                            NOVDEV
                              |
    |----------|----------|---|-------|-----------|---------|
    |          |          |           |           |         |
    |      NDEVREL        |     Files/Patches     |      NetWire
NDEVSUPP              NDEVINFO                  Novell
    |                     |                       |
    |                     |                       |
General Business      General Business       Bullets
Btrieve               Btrieve                White Papers
NetWare SQL           NetWare SQL            Other tech. pubs
NetWare Client SDK    NetWare Client SDK
NetWare Server SDK    NetWare Server SDK
Macintosh SDKs        Macintosh SDKs
Communication SDKs    Communication SDKs
To be assigned        To be assigned
Personal NW SDK       Personal NW SDK
AppWare Found. SDK    AppWare Found. SDK
LAN WorkPlace SDK     LAN WorkPlace SDK
Telephony SDK         Telephony SDK
Visual AppBuilder     Visual AppBuilder

END of FIGURE 6

NDEVSUPP: The Developer Support Forum

NDEVSUPP, the new Developer Support forum, is where Novell developers post technical questions or answers and voice concerns about Novell development products. NDEVSUPP is divided into sections for each of the Novell development tools. As Novell continues to expand its product line, additional sections will be added.

NDEVINFO: The Developer Support Forum

NDEVINFO is a forum dedicated to pre-sales information on the Novell development tools. Like the Developer Support forum, NDEVINFO is divided into sections for each of the tools.

NDEVREL: The Developer Relations Forum

Many developers will recognize the name "NOVDEV" from past experience and may wonder what has happened to the original NOVDEV. The forum that was formerly named NOVDEV has been renamed NDEVREL. The existing sections of this forum will be changed to accommodate the new Developer Support (NDEVSUPP) and Product Information (NDEVINFO) forums.

Note: Because the new, all-encompassing developer forum reuses the name NOVDEV, be aware that all script files written to target the old Developer Relations forum will now access the new main developer forum.

Other Services & Information

NOVDEV also has sections for publications of interest to application developers like Novell Professional Developer Bullets, Novell white papers and other technical publications. In addition, NOVDEV includes a section for example code and patches.

Novell is committed to providing quality support, services and programs for developers. The new NOVDEV area will enhance and streamline the services and support provided to the Novell developer community.

The Basics of Using Visual AppBuilder

AppWare's Visual AppBuilder raises the level of application development beyond coding altogether, enabling programmers and non-programmers alike to create professional software with unprecedented speed and ease.

This article provides an overview of Visual AppBuilder and explains the basics of building applications with this valuable 5GL tool.

Overview of Visual AppBuilder

Visual AppBuilder provides a 5GL-level development environment that is tightly integrated with the AppWare environment. Visual AppBuilder allows applications to be constructed by selecting, manipulating, and connecting on- screen icons.

These icons represent the building blocks of the application and are known as objects and functions in Visual AppBuilder. Objects and their associated functions make up the ALMs (AppWare Loadable Modules) in the AppWare development environment.

The range of applications Visual AppBuilder users can create is limited only by the range of ALMs available. By purchasing the ALM SDK, developers can use 3GL development tools to produce a variety of ALMs that can plug directly into Visual AppBuilder. Likewise, Novell is also committed to developing additional ALMs to be used in Visual AppBuilder. Because ALMs hide the inherent complexity of their code behind on-screen icons, Visual AppBuilder is ideal for corporate and vertical business application developers.

Currently, Visual AppBuilder provides a comprehensive library of robust, high-level objects and functions that facilitate application development, without significant sacrifices in either performance or functionality.

Using these objects is an order of magnitude less complicated than developing them -something that cannot be said of objects in more conventional object-oriented programming environments. In other words, you don't need to know anything about how it works at the code level to use a Visual AppBuilder object.

Visual AppBuilder ALM Libraries

The Visual AppBuilder ALM Library for Microsoft Windows currently consists of approximately 40 high-level objects and hundreds of high-level functions divided among several object sets.

The first of these is the Visual AppBuilder Essentials, a core set of objects and functions supporting various aspects of the Microsoft Windows graphical user interface (GUI), such as menus, lists, buttons, and windows, as well as traditional programming features such as loops, subroutines, and arrays -all structured to be usable by non-programmers. The Visual AppBuilder Essentials ALM set is included with Visual AppBuilder.

Other object sets address specialized areas of application development. The Visual AppBuilder Database ALM set consists of five objects for building robust, multiuser, relational databases. The Database ALM set supports unlimited indexing, unlimited relations, virtually unlimited record size, and unlimited data types, enabling users to store most other objects. ASCII file import/export, multi-column tabular display/printing, and international sorting are also supported.

Future ALM sets in development include:

  • Visual AppBuilder Multimedia - a multi-media set for dynamic, frame-based color animation, CD audio, digitized sound, and movies.
  • Visual AppBuilder Communications - a three-object set for modem and serial connection, file transfer, and terminal emulation.
Other ALM sets under development include sets for Dynamic Data Exchange, OLE, serial communications, NetWare services, client-server databases, and imaging.

To create your own object sets (ALMs) for use in the Visual AppBuilder environment, you can use the ALM SDK and lower- level tools such as Borland C++, Microsoft C++, and Turbo Pascal for Windows.

Visual AppBuilder Objects

A Visual AppBuilder object is a self-contained, reusable program building block containing both the data and the code your computer needs to manage that data. You use a Text object, for example, to store and display textual data. Graphics are displayed in Picture objects, lists in List objects, and so on. Most Visual AppBuilder objects represent application features that you'll recognize immediately.

For example, the Window object enables your application to display and operate windows. In this and most other cases, there's a one-to-one correspondence between a typical application feature (like a window) and a Visual AppBuilder object (such as a Windows object). Thus, a Database object would handle all the low-level database operations for indexing, record searching, retrieval, etc. The Table object would do the same for multicolumn tables.

You don't need to be a programmer to know how to use a Visual AppBuilder object. Nor do you need to know a lot about the inner workings of DOS, Windows or Macintosh. In fact, the code that makes a Visual AppBuilder object work is invisible. You'll never see a line of it. To use an object, all you need to know is how to use the application feature that the object represents.

Building An Application Using Visual AppBuilder

To start Visual AppBuilder, you simply double-click on the Visual AppBuilder icon in Windows. Once you are in Visual AppBuilder, the first step in building your applications is to create a project. This project will contain your application "code."

Although much easier to create and understand, a project is like the source code file a programmer creates in C or Pascal. After you have finished constructing your project, you compile it and create an icon for it. By double-clicking on that icon, you launch your application.

Although all this sounds pretty simple, you also need to know that a project is made up of one or more reusable sub- projects or subjects, each devoted to a different aspect of your application. Some subjects are so basic in nature that you'll reuse them over and over.

For instance, your application may create a basic menu bar subject containing File and Edit menus. You will need a subject like this in just about every application. Other subjects may be very specific in nature--the sort of thing you may never need to reuse.

General or specific, subjects let you compartmentalize your program and isolate segments that are reusable from those that are not. Every project must contain at least one subject.

The Object & Function Palette

After you have created the project and one subject, you can begin building your application using the Visual AppBuilder Object & Function Palette. This palette displays alphabetical lists of objects and functions for use in Visual AppBuilder.

The Pallette has three scrollable compartments:

  • Objects are displayed in the left compartment of the Object & Function Palette. Examples of objects that are provided with Visual AppBuilder include List, Menu, Menu Bar, Loop, Keyboard, Cursor, File, Database, etc.
  • Functions are displayed to the right of the objects in the center compartment of the Palette. The functions displayed in the center compartment depend on which function category is selected.
  • Function categories are listed in the right compartment of the Object & Function Palette. These categories generally relate to an object type.
When you want to use an object of a particular type in your application, you drag its icon from the Object & Function Palette into the object list. Visual AppBuilder then creates a copy or instance of that object type in your project. The objects you use in a subject reside in the object groups that you can freely locate within the subject window. Once an object has been copied into the object list, it can be named and edited. Note that every subject has one object list.

Associating Objects and Functions

Before objects can be useful, the computer must know what you want your application to do with them. For example, you may want to open or close a window, enter or delete a record in a database, etc. Each object file therefore comes with a set of functions that you use to control exactly how the object is to operate in your application.

The Window object, to take an example, includes the functions Open Window and Close Window. You use these functions to open and close windows in your application. If your window contains editable text fields, then you might have occasion to use Text functions such as Append Return, Concatenate, Find-Replace, and so on. There are also File Operations and General functions not associated with any specific object.

Unlike objects, functions contain no information and interact with objects. A Visual AppBuilder function performs a single high-level operation. High-level means that the Visual AppBuilder user is shielded from the complicated, operating system-level programming that actually makes the function work.

To select a function, you simply highlight that function and then drag it from the Palette onto the subject's worksheet.

Creating Signal Flows and Function Chains

You indicate that an object calls a function by dragging a line between the object and a function. This line is called a signal flow. Each object has its own set of signals, which reflect occurrences or events that affect the object.

For example, the Text object notes when you change or edit its content, tab into or out of it, type too many characters, or press the Enter key. Signals are issued for each of these occurrences.

Functions, like objects, issue signals that you can use to call other functions. By clicking on a particular function and dragging a line to another function, you create a function chain. Function chains are initially triggered by the object to which they are connected. In addition, functions, like objects, may issue more than one signal.

Through the use of different signals, one function may call several different function chains that extend from the function like branches of a tree. Each of these branches represents a path along which your function may proceed.

Defining an Object as an Input or Output Parameter

Functions by definition operate on objects. The object (or objects) that a function does something to are its parameters. Parameters come in two varieties: inputs and outputs.

To define an object as an input parameter, you simply click the label above the function and drag a line from the label to the object in the object list. When you activate one of the labels above the function icon, you are specifying that the object specified in that label can be passed as an input parameter to that function.

Parameter Type Checking

One of the unique features of Visual AppBuilder is its built in parameter type checking. In Visual AppBuilder, input and output parameters expect or produce certain types of information, in the form of objects. Parameter type checking ensures that you connect only appropriate types of objects to function inputs and outputs.

To prevent you from mistakenly connecting the wrong kind of object parameter to a function input, Visual AppBuilder uses type checking. Type checking works by not allowing you to draw a line between a function label and an improper object type or between incompatible function outputs and inputs.

Type checking, then, limits the sort of parameters you can pass to and from a function. In some cases, type checking may limit the choice of object types to one. However, many function inputs and outputs do accept more than one type of object connection.

For example, certain functions have inputs and outputs that will accept any type of object. For these functions, there is effectively no type checking, and the input and output parameter types are therefore said to be "global" in nature.

Sharing and Aliasing Objects Between Subjects

In Visual AppBuilder, you use lines (signal flows) to link functions to objects and to other functions. This methodology works fine within a subject, but it can't be used between subjects, since each is its own separate window and lines can't be drawn across window boundaries. Fortunately, there is a way around this dilemma.

When a function or object in Subject A needs to reference an object in Subject B, you create a surrogate or alias for the object in Subject B and put it into Subject A. Objects and functions in Subject A work with the alias just as they would with the original, which still resides in Subject B. Object aliases are, therefore, the links that hold various subjects together.

An object alias is not a copy of the original object, but a representative of it that you can use as if it were the original. The difference between a copy and an alias is easily illustrated in an example. Suppose that you're working on a project that contains two subjects: one devoted to a menu bar and its constituents, and another concerned with windows. While the responsibilities of the two subjects are generally distinct, there could possibly be some interaction between them.

Now, suppose that at runtime when you choose a menu item, you want to open a dialog window. To program this, you would drag an Open Window function into your work area and attach (draw a line) between the Open Window function and the menu item in the menu bar subject. Next, you would specify the window to open as the input parameter to the Open Window function. Since that window is in the Windows subject, you would create an alias of it in the menu bar subject and pass the alias to the Open Window function.

If, on the other hand, you were to copy the dialog Window object, paste the copy into the menu bar subject, and pass this to the Open Window function, then the menu item would open an exact duplicate of the dialog, but not the dialog you want.

Both functions and objects face this dilemma when communicating with objects in another subject. An object can "see" only those objects resident in its subject. If, for example, your Menu Bar object is in one subject and its Menu objects are in others, the Menu objects will not appear in the Menu Bar's editing dialog. So, you will not be able to add the Menu objects to the Menu Bar.

If, on the other hand, you create aliases of your Menus in the Menu Bar's subject, then the Menu Bar will "see" and display them in the editing dialog. You can then add them to the Menu Bar just like ordinary Menu objects.

Most of your objects will not need to be aliased. Those that do may be aliased more than once, perhaps in multiple subjects. So, it is useful to have a quick way to get to them when you need to make an alias. To make quick access possible, you first identify the object you want to alias and share it. Once shared, an object can be aliased in any subject within your project. Shared objects are distinguished from other objects by their boldface titles.

Debugging and Compiling

After designing your application in Visual AppBuilder, the final step is to debug and compile the application you have designed.

Debugging is the process of running your application with an interpreter (the interpreter is intrinsic to Visual AppBuilder) to see if there are any bugs in the application. The interpreter lets you run through the application one step at a time. The advantage of using an interpreter is that you can find exactly where in the application an error occurs. Knowing this, you can then address the problem and try again.

When you run in the interpreter, Visual AppBuilder actually creates and launches a temporary application. When you exit the interpreter, the temporary application file is automatically deleted.

An additional feature in Visual AppBuilder aids in the debugging process even before running in the interpreter. This feature is the ability to check selected projects, subjects, and objects for errors. You can use this feature by inserting stops (pauses) along suspected problem function chains in your application before running the interpreter. As the interpreter runs through your application, it pauses at each stop and waits for you to select "Continue" from the Project menu.

If an error occurs between stops, then you know that the problematic functions are to be found after the first stop and before the second. By inserting additional stops, you can narrow down the problem even further. Although you can't edit an object, you may make other changes to your project while it pauses. These changes will not be reflected until you exit the interpreter and run the application again.

Stops are for you to use as needed. You probably won't want to install them the first time you debug your application, but they are a valuable aid in debugging applications that don't run correctly.

When you are finished designing and debugging a project, you can compile it into a double-clickable application. All of your subjects, objects, functions, and function chains are merged into one program.

To compile a project, you simply choose Create Application from the Visual AppBuilder Project Menu and specify a file name for your application. To create an icon for your application, you choose Edit Icon from the Visual AppBuilder Project menu and use an icon editor to draw the icon.

The icon editor displays a "fat-bits" icon editing box. The view is enlarged to make your editing easier. Each square or bit in the fat-bits editor represents a single pixel in the icon. To draw the icon, you first select from a series of colors. An Import button also lets you import an icon (.ICO) file.

Distributing Your Application

When distributing your application, you will need to copy the application file (*.EXE) file itself and the DLL file for each type of object used inside the application. You will deposit the DLL files in a directory that is in a common search path so that your built application can easily find them as it runs. You may, in fact, install the DLL files on a network server, so that several users can simultaneously run off of one set of object code files.

Porting Your Application to and From the Macintosh

For developers who want to port their Windows application developed using Visual AppBuilder for Windows to the Macintosh environment, a new technology is provided that allows you to do just that. This new technology is known as Universal Program Structure File (UPSF). UPSF allows projects created in Visual AppBuilder for Windows to be ported to operate on Macintosh computers.

In order for a project to be ported, the objects and functions it uses must be available on both platforms. Currently, the Essentials and Database object sets are available on both platforms. Windows versions of object sets currently available only for Macintosh are in development.

UPSF is a file specification similar in concept to an Adobe Postscript file. Many different printers and typesetters understand postscript files. Likewise, the Macintosh and Windows versions of Visual AppBuilder speak a common language in UPSF.

In the future, Novell will be announcing new versions of Visual AppBuilder for several additional platforms, making your existing and new Visual AppBuilder applications portable to those platforms.

For More Information

For more information on Visual AppBuilder, call 1-800-NETWARE. Visual AppBuilder is scheduled to be available to Novell developers in October 1993 through the Novell Professional Developers' Program.

TECHNICAL INSIGHTS:

Problem With Domain (NLM SDK v3.0)

The version of DOMAIN.NLM included with NetWare 4.01 can trigger a server crash in the following situation: if you attempt to enter the debugger using the keyboard sequence (ALT, ALT, SHIFT, ESC), and domain is running, and control of the CPU belongs to an NLM running in the protected domain when you enter the debugger, the server will crash. This situation does not present a problem for end users, but could definitely affect Novell developers debugging NLMs.

This situation has been addressed by Novell Engineering. A new version of DOMAIN.NLM has been posted on Novell's NOVDEV CompuServe forum (Library 6, DOMAIN.ZIP, 8/9/93).

stat() Fails on 254th Attempt (NetWare Client SDK v1.00c)

The stat() function in the versions of CLIB associated with NetWare 4.00 and 4.01 fails on the 254th attempt against a remote file server. The function returns a completion code of -1 and errno is set to 11, indicating that it is out of directory handles.

This failure will be prevented in a future CLIB release. Until then, use the access() function if stat() is being used to check for the existence of a file. Otherwise, use opendir() and readir() to return file information.

Creating 32-bit OS/2 Applications (NetWare Client SDK v1.0d)

Creating 32-bit OS/2 applications with the NetWare Client SDK and either IBM's CSET/2 compiler or the Borland OS/2 Compiler requires that you thunk the header files to perform the appropriate pointer conversion for the APIs. The #include file, NWCALDEF.H, documents this procedure. The format of the declarations in the header files unfortunately is not consistent, so you must modify 70+ files, rather than NWCALDEF.H alone.

The thunked headers for the NetWare Client SDK are posted on NetWire in NOVDEV forum (Library 6, THUNK.ZIP). You must activate the thunking in a manner similar to the thunked files in the C Interface for OS/2 (i.e., using the #define IS32BIT and #define BCPP -or CSET2). Additional information appeared in the February 1993 issue of Bullets.

NetWare SQL Index Optimization Changes (NetWare SQL v3.0)

NetWare SQL v3.0 performs index optimization somewhat differently than previous versions. When using a restriction such as:
 
WHERE fld1 = 
  AND fld2 = 
NetWare SQL first looks for a segmented index where the first two segments are "fld1" and "fld2" (in any order). If such an index does not exist, it will check for an index where the first segment is either "fld1" or "fld2."

Suppose there is an index on "fld1," and a separate index on "fld2." Previous versions of NetWare SQL would choose to optimize on the index with "fld1" as its first segment, since this is the first restriction in the query. However, NetWare SQL v3.0 optimizes on whichever index is defined first in the table. So, if "fld2" is the fourth index defined in the table, and "fld1" is the fifth index, NetWare SQL optimizes the query using the index on "fld2."

In some cases, it may be more desirable for NetWare SQL to choose one index over the other, depending on the number of duplicate values that exist in each of the indexes. One option is to rebuild the table so that the preferred index is declared first. However, this option does not give users control in their SQL statements to determine the optimization. This can be done by rewriting the restriction so that the preferred indexed field uses an equal restriction. For example, the restriction above could be rewritten as:

 
WHERE fld1 = 
  AND fld2 <= 
  AND fld2 >= 
NetWare SQL attempts to optimize equal restrictions first, and if no appropriate indexes exist, then it attempts to optimize other types of restrictions. So, this example would result in NetWare SQL optimizing on an index on "fld1" instead of "fld2."

A second option is to add an ORDER BY clause to the statement specifying the indexed field to be used. NetWare SQL always attempts to optimize the ORDER BY clause before optimizing restrictions.

Status 0xF2 on SPXInitialize() in Standard Mode (NetWare Client SDK v1.0d)

A call to SPXInitialize() in Windows running in standard mode will return a completion code of 0xF2 (no DOS memory) when more than 60 ECBs are specified as the maximum number of ECBs on the function call.

TBMI2.COM must be loaded before Windows 3.1 only if running in standard mode and IPX/SPX communication applications will be run. However, TBMI2 defaults to allocating 60 data ECBs. The NetWare C Interface for Windows documentation states that, if TBMI2 is configured for less than the number of needed ECBs, a status 0xFE will be returned. Actually, when the NetWare Client SDK makes a request for an ECB, it cannot distinguish between an "out of DOS memory" state and an "out of configured ECBs" state. Because of this, an 0xF2 (no DOS memory) will be returned in both cases.

To configure TBMI2 for more than 60 data ECBs, create a configuration file containing the following line:

  
DATA ECB COUNT = n
where n equals the number of ECBs for TBMI2 to allocate.

If you name the configuration file TBMI2.CFG, TBMI2 will be loaded before Windows as follows for the configuration option to take effect:

 
TBMI2 /C=TBMI2.CFG
With this configuration, SPXInitialize() can be called with more than 60 ECBs. However, if this data ECB value is set too high and exceeds the lower DOS memory limit for that machine, an 0xF2 status will also be returned; the machine actually has no DOS memory available.

The NetWare C Interface for Windows v1.3 documentation (p. 1- 12 through 1-14) provides more information on the "DATA ECB COUNT" configuration option, as well as other configuration options for TBMI2. These configuration options are not documented in the NetWare Client SDK v1.0d documentation.

Service Query Responses for Windows and DOS (NetWare Client SDK v1.0d) (NetWare C Interface for Windows v1.3) (NetWare C Interface for DOS v1.2)

General Service Queries (GSQs) from Windows or DOS targets return Nearest Service Responses. This fact is unimportant unless you filter the packets coming back. MacIPX does filter these packets, and does not see the Service Responses to GSQs. Furthermore, the Service Response replies to a broadcast address, thus causing one response to come back to the querying machine multiple times depending on routing.

The situation results from a problem with the AdvertiseService() function included with the NetWare C Interface for Windows and NetWare C Interface for DOS. In the function, RespondToLocalQuery(), it does not test so see if the query is "general" or "nearest." The response packet is initialized to respond back with a packet type of 4 (nearest) for all responses. Also, the response ECB immediate address field is initialized to -1 (all 0xFF values) and never set to the address from which the query originated.

To resolve this situation, you must modify the source file, advertis.c (included with the NetWare C Interface Kits). Using the NetWare C Interface for Windows, for example, you could replace the RespondToLocalQuery() function with the code in Figure 13.

FIGURE 7: Replacement for RespondToLocalQuery()

 void far pascal RespondToLocalQuery2()
{
  int transTime;

  if (!((instStructPtr + availSlot)->listenECB.completionCode))
  {
    if((instStructPtr + availSlot)->querySAP.serverType ==
                                    thisServerType)
    {
      while((instStructPtr + availSlot)->responseSAP.theECB.inUseFlag)
      {
        IPXRelinquishControl();
        IPXYield();
      }

      /* reply back to the address that the SAPquery came from */
      memmove((instStructPtr+availSlot)->responseSAP.packet.destination.
                                         network,
             (instStructPtr+availSlot)->querySAP.source.network,12);

      /* respond back directly, rather than broadcast(this way you won't
      ** get N=1 responses, where n=number routers) */
      IPXGetLocalTarget(TaskID,
        (BYTE FAR *)(instStructPtr+availSlot)->
                     responseSAP.packet.destination.network,
        (BYTE FAR *)(instStructPtr+availSlot)->
                     responseSAP.theECB.immediateAddress, &transTime);

      /* if the query is general, respond back general
      ** (default response is RESPOND_IS_PACKET #def'd to 4) */
      if ( (instStructPtr+availSlot)->querySAP.queryType == 0x0100 )
           (instStructPtr+availSlot)->responseSAP.packet.SAPPacketType =
           IntSwap(2);

      IPXSendPacket(TaskID, &(instStructPtr+availSlot)->
                    responseSAP.theECB);

    } // END - if this is our server
  } // END - if we got the ECB ok

  IPXListenForPacket( TaskID, (ECB far *)&(instStructPtr + availSlot)->
                              listenECB);
} // END = ResponseToLocalQuery2

END of FIGURE 7
Rather than using the IPXGetLocalTarget() in an ESR, you could also copy the immediate address field from the Query ECB into the Response ECB for a faster (though not guaranteed) response. The modified source files are available on NetWire (NOVLIB, section 9, SAPFIX.ZIP) and are also posted on AppleLink in the Third Parties area for MacIPX users.

Microsoft QuickBasic & Btrieve Status 76 (Btrieve for DOS v5.10a)

Btrieve applications compiled with Microsoft QuickBasic may return a BASIC run-time error 76 (Path Not Found) when run on peer-to-peer networks. The error occurs when executing the OPEN "NUL" statement in applications that use fielded variables rather than type structures.

To resolve this error, change each OPEN "NUL" statement to:

 
OPEN "\DEV\NUL".
By default, Microsoft QuickBasic appends path names to files opened with the OPEN statement. The \DEV\ added to the OPEN statement prevents Microsoft QuickBasic from assigning a file path to the device and enables the statement to succeed.

NetBIOS for OS2 & DOS Mutually Exclusive (NetWare OS/2 SDK v2.0)

The use of NetBIOS under OS/2 involves loading NETBIOS.SYS and NBDAEMON.EXE. These drivers take over the NetBIOS interrupt 0x5A. When using NetBIOS in a DOS VDM, the NETBIOS.EXE TSR is loaded, which then attempts to take over int 0x5A. The OS/2 Requester v2.0 Manual incorrectly describes the steps necessary to run NetBIOS from a VDM as follows:
  • Make sure the NetWare Requester in installed with Novell NetBIOS and Virtual DOS Session support.
  • Install the NETBIOS.EXE TSR.
This procedure causes the VDM to lock up, although the operating system still runs and other sessions are not affected.

DOS NetBIOS may be loaded only if the OS/2 NetBIOS statements in the workstation config.sys are "commented out." Doing so provides support for NetBIOS under one DOS VDM only. Multiple Global DOS NetBIOS sessions are possible through the use of the files LANVDD.SYS and LANPDD.SYS, which virtualize NetBIOS through NETBIOS.OS2. These files are available in either Extended Services or LAN Services.

DOS NetBIOS and OS/2 NetBIOS are available through the IBM multiple protocol stack extender for OS/2, which in turn is included as a part of IBM's NTS/2 product.

Btrieve Overwrites Key Buffer with Status 22 (NetWare Btrieve (NLM) v6.00)

Btrieve will overwrite the Key Buffer parameter on a Get Equal (5) operation if a status 22 (Data Buffer Length Too Short) is returned. NetWare Btrieve (NLM) v6.x and the Btrieve v5.x client versions overwrite the Key Buffer parameter with extraneous characters on a Get Equal (5) operation if a status 22 (Data Buffer Length Too Short) is returned from the call. This situation occurs only if the data buffer length specified is less than the offset and length of the key specified in the Key Number parameter.

This situation occurs because the return key value is extracted from the data buffer itself. An incomplete Data Buffer results in an incomplete (thus invalid) key value.

Status 22 is an informative status code indicating that there is more data in the record than Btrieve was able to return. When using variable-length records, many developers intentionally set the Data Buffer Length parameter to a number that is less than needed to return the entire record. Doing so can improve performance by preventing a variable- page read when only the fixed-length data is needed. This is an acceptable method of data retrieval. The Key Buffer overwrite problem described above only occurs if the Data Buffer Length parameter specified is shorter than the fixed- length portion of the record, and specifically the offset of the key specified in the Key Number parameter.

Registering Console Commands Requires Stable Console Process (Network C for NLMs v2.00)

The RegisterConsoleCommand() function may fail when used in an NLM that is autoloaded from AUTOEXEC.NCF. RegisterConsoleCommand() requires the console interpreter to be fully loaded and initialized before it can be used, but it does not check for such conditions.

If an NLM that makes this call must be autoloaded, it must provide a long enough delay for the console to become fully stable before the call is made. The exact length of this required delay depends on the specific hardware and system configuration.

Obtaining NetWare Print Queue IDs (NetWare Client SDK v1.0d)

]The documentation for the NetWare Client SDK incorrectly describes NWGetPrinterQueueID(): it is actually an NLM API. The underlying NCP denotes the API as being server-based. On a client workstation it will return a Queue ID of 0.

To obtain the Queue ID for a captured device on a workstation, call NWGetCaptureFlags(). This API returns a structure called NWCAPTURE_FLAGSRO that contains a queueID field containing the queue ID.

Closing TLI Endpoints & "Time-Outs" (NetWare Client SDK v1.0d)

When you attempt to connect to a non-listening node, the following scenario results in a "time-out," when a cancellation of the request was expected.
  • t_connect() (in non-blocking) is called against a non-listening node (or bad address).
  • t_close() waits until t_connect() completes its "time-out" process. Once t_connect() does "time-out," t_close() completes successfully.

Loading Brequest from Login Scripts (NetWare Btrieve (NLM) v6.00d)

When loading BREQUEST.EXE from a NetWare login script, the TSR fragments memory, so it appears to take 200K of space. This memory loss is attributed to the fact that the LOGIN program is still in memory when the TSR is loaded. It gets trapped between whatever was in memory prior to logging in (most likely the network shell) and the newly loaded TSR.

To avoid this situation, do not load TSRs from login scripts. If you need to load any TSRs at login time, use the "EXIT" statement in a login script to call a DOS batch file. Batch files can load the TSRs without this memory penalty.

Ensuring Btrieve Transaction Recovery (Btrieve for DOS v5.10a)

The documentation for Btrieve for DOS v5.10a states that, when using Btrieve in a networked environment, all users who start Btrieve with a "/T" option should specify the same physical location for the transaction control file. This rule ensures that, when a data file is shared by two workstations, both of the stations will be able to recover from a server failure during an End Transaction (20) operation, regardless of which station is recovered first.

This rule should be applied, but it is not foolproof. The full logical path of the data files used in a transaction are stored in the transaction control file. If the first station to start Btrieve after a server failure does not have the same logical mappings to the files as the station that was processing an End Transaction operation during server failure, Btrieve will not be able to access the files described in the transaction file and will report the error "Unable to access Btrieve file for transaction recovery."

To insure transaction recovery after a server failure, all stations should share the same transaction file (/T), and should also access the data files with the same logical mappings.

File Cache Buffer Size (Network C for NLMs v2.0(e))

If a file server is configured for 4096-byte cache buffers, the NetWare API AllocNonMovableCacheMemory() returns multiples of a block size larger than 4096 bytes.

Under NetWare 3.11 a 4096-byte cache buffer actually has 124 bytes of overhead associated with it. So, although 4096 bytes of each block is usable, each block is actually 4220 bytes long. When a block is moved from the file cache buffers to the non-movable memory pool and then allocated, only 16 bytes of memory are required for overhead for each allocation.

Therefore, if a single block of memory is allocated the usable storage will be:

 
4220 (block) - 16 (overhead) = 4204
If more than one block is allocated the total allocated and usable memory is equal to:
 
(number of blocks * 4220) - 16

SAP Service Queries From OS/2 (NetWare OS/2 SDK v2.0)

Issuing a SAP (Service Advertise Protocol) Service Query from OS/2 will not return all of the responses to the application through IPXReceive().

If you use IPXSend() and IPXReceive() with the NW OS/2 Requester v2.01 or less to get a list of advertising services, a number of the responses (possibly up to 50) are dropped because the IPX/LSL interface is unable to handle large quantities of incoming packets at one time.

The most reliable solution in this situation is to use the NetWare Bindery to locate services. In peer-to-peer cases, or where dependency on a NetWare server is undesirable, there are two potential solutions:

  • To issue the GSQs inside a loop, building an internal exclusion list of respondents for each query, until a sufficient number of responses have come back. This solutions relies on the fact that the servers will not respond in the same order every time and is therefore not dependable.
  • Run a background process that monitors the advertisements on the SAP socket and records the services to a file or a shared memory area. This is similar to what DOSNP does to find Named Pipe servers for SQL.

Error in Attach_LU Call with CPI-C (NetWare LU6.2 Tools v1.4)

While loading CPI-C from NetWare 3270 LAN Workstation for Windows v1.2, an error in the Attach_LU call or a "CPI-C Application Subsystem Error" may occur if the LU Local Address is improperly configured. In this case, NetWare for SAA does not recognize the dependent LU address in the "LU_LOCAL_ADDRESS" field, or it does not recognize it as an LU 6.2 address.

To prevent the error, make the "LU_LOCAL_ADDRESS" field match the address of a dependent type of LU 6.2 address in the NetWare for SAA database. Also, call CSRESTART after the service profile is modified in CSCON to place the changes in effect. Error code "0x00000501" is also returned at 20th byte in the Attach_LU call in the protocol boundary trace.

IBM LAN Server Reports Sharing Violation with Btrieve (Btrieve for DOS v5.10a)

IBM LAN Server reports a "Sharing Violation" when an application issues a Close (1) operation on a Btrieve file if at least two stations have a data file open and have both modified the data file.

The error occurs when Btrieve for DOS performs its Close test to determine if it is the last instance accessing the data file. During the Close operation, Btrieve tries to open the preimage file in exclusive mode. If the Open operation succeeds, then Btrieve knows that this is the last handle to the data file and can erase the preimage file. Unlike DOS, LAN Server interprets this test as a critical error.

To prevent this "Sharing Violation" error from occurring, load Btrieve with a "/O." This load parameter tells Btrieve to override the critical error handler so that Btrieve handles critical errors instead of the operating system.

NWDSLogout() & SMS APIs (NLM SDK for NetWare 4.0 v1.0c)

The NWDSlogout() and NWSMTSReleaseTargetServer() interfere with each other in the NetWare 4.0 environment. If the SMS (Storage Management System) services are used in conjunction with the NetWare 4.0 CLIB APIs, they may interfere with each other.

In particular, NWDSlogout() and NWSMTSReleaseTargetServer() fail when used together. When used together, in either order, the second call always fails. In addition, the active connection for the second call remains allocated.

This situation has been resolved in NetWare 4.01.

Volume Info for Large Volumes (NetWare Client SDK v1.0d)

NWGetVolumeInfoWithHandle() and NWGetVolumeInfoWithNumber() return, among other things, available blocks and total blocks for a volume. They return them as type NWNUMBER, which is a 16-bit quantity. This type poses a problem when these calls are used on a large volume, since large volumes could conceivably have more than 65,535 blocks.

The call NWGetDirSpaceInfo() returns these values as NWNUM_BLOCKS, which is a 32-bit quantity. Use this call instead of the NWGetVolumeInfo..() calls mentioned above to ensure the information returned is correct for large volumes.

Btrieve Clients & SHARE.EXE (Btrieve for DOS v5.10a)

SHARE.EXE needs to be loaded on Btrieve for DOS and Btrieve for Windows client workstations under the following conditions:
  • If your application accesses the files that reside on your hard disk and applies any record locks, whether single or multiple.
  • If your application uses multiple cursors (multiple position blocks) to access the same file on the hard disk.
DOS, by default (and without the NetWare shell), provides no locks at all; that is, INT 21H, function 5CH, is a "NOP." To support locking on local disks, DOS provides SHARE.EXE. In order for Btrieve to be able to lock records on a local disk, SHARE.EXE must be loaded.

SHARE, by default, allows up to 20 concurrent locks. To increase locks, use the SHARE "L" command line parameter. The "F" parameter may have to be used to make SHARE allocate more work space if many files are locked, or if the files are in "deep" subdirectories, (for example, c:\path1\path2...\path6\FILE.EXT.

Invalid Window Handle in NetWare Applications (NetWare Client SDK v1.0x)

Applications using the NetWare C Interface for Windows v1.3 function IPXYield() will cause an invalid window to be reported if the debug version of Windows 3.1 is running. The message is reported because IPXYield() uses a null window handle. This condition does not affect the functionality of the call, but it does cause the debugger to report an error. This situation also occurs with the following NetWare C Interface for Windows functions that use IPXYield() internally:
  • BeginDiagnostics()
  • EndDiagnostics()
  • IPXCancelEvent()
  • PSAttachToPrintServer()
  • QueryServices()
  • ShutdownSAP()
  • StartSendingPacketsTimed()

GetDiskUtilization() usedBlocks Parameter (NetWare C Interface for DOS v1.2)

The usedBlocks value returned by GetDiskUtilization() is incorrect due to a problem with the NetWare C Interface for DOS source code. The wrong area of the NCP reply packet is being returned.

To resolve this situation, modify the line in DISKUTIL.C:

 
*usedBlocks = *(LONG *)
                   &receivePacket[4];

to read:

*usedBlocks = *(LONG *)

              &receivePacket[6];
and recompile the module. The correct number of used blocks is then returned and the usedBlocks parameter does not need to be swapped.

NIBBLES AND BITS

Fast Answers to Common Questions

NetWare 3.11

Q - Sometimes when an NLM is loaded, the amount of "Total Server Work Memory" that is displayed in MONITOR.NLM decreases by a multiple of 16 bytes. Are small amounts of memory being lost when NLMs are loaded?

A - No, this decrease is a result of the method MONITOR.NLM uses to calculate the amount of memory. No memory is actually being lost. The Non-Movable Cache, Movable Cache, and File Cache totals reflect the total allocated memory, including the overhead involved in managing these pools. The totals for Permanent and Alloc, however, only reflect memory that is usable by an application and do not take into account the overhead involved in managing the memory.

Therefore, any time an NLM needs more memory and the server is required to move memory from File Cache Buffers to the Permanent pool, a full buffer (overhead and all) is removed from the File Cache total and the amount of usable memory added to the Permanent total is 16 bytes smaller, since 16 bytes are required for overhead.

NetWare Client SDK

Tip When a Windows application calls the the Service Advertise Protocol (SAP) services, ShutDownSap(), after advertising, SAP Services will not be discontinued.

The "SAPping" process will continue until you actually exit from Windows.

Tip NWGetFileConnectionID() returns 0x89FD when it is used under NETx, but the call works fine under VLM. This call is not supported under NETx. To be able to use NWGetFileConnectionID(), the workstation must be running VLM.

NetWare C Interface for Windows

Q - How does VIPX handle ECBs (Event Control Blocks) internally?

A - When you call IPXListenForPacket(), VIPX adds the client ECB to a list of listen ECBs for the socket. When a GetECB request is issued from the LAN driver, VIPX checks its list of listen ECBs for that socket. If there is an ECB available, VIPX allocates a global ECB and then copies the local client ECB to the global ECB. The global ECB is then submitted to the LAN driver.

When a packet is received, the LAN driver fills the global ECB with the received packet. It then calls the ServiceEvents routine to service the Event Service Routine (ESR) corresponding to the ECB. This ESR is the service events callback used by VIPX. VIPX copies the contents of the global ECB into the local client ECB. VIPX then determines whether the currently running virtual machine (VM) is the owner of the local client ECB. If it is, the ESR is called immediately. Otherwise, VIPX schedules the owner VM to run. When the VM that owns the local client ECB is running, the ESR is called.

Btrieve

Tip When you perform an Insert (2) operation on a file containing an auto-increment key, if the value of the auto-increment key is set to zero, on return from the operation, Btrieve will update the data buffer to the new assigned auto-increment value for the record.

When you issue an Extended Insert (40) operation to insert multiple records with a single call to Btrieve, if the data file contains an auto-increment key, the multiple records in the data buffer will be updated with the auto-increment value, as well.

Tip If a data file is flagged "H" (hidden), NetWare Btrieve (NLM) cannot open the file. NetWare Btrieve (NLM) returns a status 12 (File Not Found), but Btrieve for DOS v5.10a is able to open data files that are hidden.

Currently, there is no solution for this inconsistency between the two Btrieve products.

Network C for NLMs

Tip If you are using WATCOM C/C++32 to create a C++ NLM, you must include the header files in the \NOVH directory first, and then include the header files in the \WATCOM\H directory. For example, if you had installed the tools in C:\WATCOM, you would set the environment variable as follows:
set INCLUDE=C:\WATCOM\NOVH;
C:\WATCOM\H
You still need to include the regular \H directory because all the C++ headers are located there (the header files are not duplicated in the \NOVH directory).

Novell FAX ON DEMAND Service

Q - How can I obtain the latest product information and press releases from Novell?

A - Novell customers who have access to a touch-tone telephone and a fax machine can now request faxes of customer success stories, current press releases or specific product information from Novell's new Fax on Demand (FOD) service by calling 1-800-NETWARE (1-800- 638-9273) or 1-801-429-5588.

Product information on the FOD system includes the latest specifications on each of Novell's products including: NetWare 4.01 and the NetWare Branch Office Solutions.

Developer information is still available through the Novell Developer Relations Automated Fax System (see "Current Patches for Novell Development Tools" for details).


DEVELOPER EDUCATION:

Available Novell Developer Education Courses

Novell Developer Education offers several courses for developers who use Novell's development & database tools, including NetWare SQL, Btrieve, Xtrieve PLUS, and the NetWare Client APIs.
904 - Btrieve: An Overview
905 - Programming with Btrieve
907 - Xtrieve PLUS
911 - NetWare Database Administrator
912 - Programming with NetWare SQL
930 - Developing NetWare Loadable Modules (NLMs)
940 - NetWare Programming: Basic Services
945 - NetWare Programming: Protocol Support
To obtain information on pricing, location, scheduling, & course content for classes held in the US, call 1-800-233- 3382, 1-801-429-5508 or 1-800-NETWARE. For information on classes outside of the US, contact your local Novell office.

CURRENT PATCHES FOR NOVELL DEVELOPMENT TOOLS

The latest NetWare drivers, example code for NetWare API development tools, OS/2 requester patches, and patches for Novell's database products are available on Novell's NetWire forum on CompuServe. New information is first stored in NOVLIB library 1, and moved to library 7 after a period of 30 days. If you do not have access to CompuServe, request these files from Novell's Developer Support Group at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588.

When calling, be ready to provide a shipping address, disk preference (5.25", 3.5", HD, or DD) and, if you prefer overnight delivery, your company's Federal Express account number. If you do not provide a Federal Express account number, the patch disk will be sent to you via regular mail.

Novell Professional Developers' Program members can obtain updated NetWare API SDK components from Novell's NOVDEV forum on CompuServe. For more information on Novell developer programs contact Novell at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588. Novell Developer Relations Automated Fax System A document describing available patches and other files and their location on CompuServe is available through Novell Developer Relations Automated Fax System (AFS). This system can provide you other useful information as well. To use the AFS, call 1-800-RED-WORD (1-800-733-9673) or 512- 794-1796 from a touch-tone phone. Then, choose the option for the Automated Fax System, select the documents you wish to receive, and supply your fax number (the fax number to which you want the document(s) sent). Document #7805 describes the patches. Document #1 lists all other documents available through the Automated Fax System. Up to five documents can be requested per call.


CONTACTING NOVELL

Developer Support

Developers in the U.S. and Canada may contact Novell Developer Support via telephone, fax, BBS or electronic mail via CompuServe, MHS or the Internet.

Voice

For both presales and postsales support, call Novell Developer Support between 8:00 a.m. and 5:00 p.m. Mountain Time at 1-801-429-5588. Many calls to Novell Developer Support are passed to a software support engineer immediately. Calls to Novell Developer Support generally will be acknowledged or answered within four hours.

Fax

If you prefer, you may contact Novell Developer Support via fax at 1-801-429-2990. Faxed questions are acknowledged or answered within 24 hours.

Developer BBS

If you do not have access to either CompuServe or the Internet, send test cases to our BBS. Set your communication software to N-8-1 and call 1-801-429-5836.

E-mail: CompuServe

Post your messages in the appropriate section addressed to Novell at 76701,171. These messages will receive a response within 24 hours.

E-mail: MHS

You may direct your questions and comments to Novell Developer Support via Novell's Message Handling Service E-mail facility. Address your messages to devsup@novell. These messages will receive a response within 24 hours.

E-mail: Internet (SMTP)

An alternative method of contacting Novell Developer Support is through the Internet E-mail system. Send your messages to devsup@novell.com. These messages will receive a response within 24 hours.

NetWire on CompuServe

Novell's NetWire forum is open to all registered CompuServe subscribers. Through the NDEVSUP forum, professional developers writing applications with Novell development tools can gain access to information specific to Novell development. Support, patches, periodicals and product information, as well as information on all of the programs and services provided for Novell developers are accessible through this forum. Post your messages in the appropriate section addressed to Novell at 76701,171. Technical questions will be acknowledged or answered by Novell Developer Support within 24 hours.

Novell Products and SDKs

Novell products on the "Currently Shipping Developer Products" list (see page 15 of this issue), including the Red Box Products, are available to Novell Professional Developer's Program members. Call 1-800-RED-WORD (1-800-733-9673) or 1-303-894-4135 to order these products or to receive additional information. To order other Red Box Products not listed, contact your local Novell office or Novell Authorized Reseller.

Novell Labs

For information on Novell Labs development tools, education classes and product certification, in the U.S. and Canada call 1-800-453-1267 ext. 5544 or 1-801-429-5544, or call your local Novell office (see back cover of this issue).

Novell Developer Relations

Novell Professional Developers or those wishing to become members may contact Novell Developer Relations via telephone, fax, or electronic mail via Compuserve, MHS or the Internet.

Voice

For general information or questions on Novell Developer Relations programs, in the U.S. or Canada call 1-800-RED-WORD (1-800-733-9673). All others call 1-801-429-5281.

Fax

If you prefer, you may contact Novell Developer Relations via fax at 1-801-429-7207.

NetWire on CompuServe

Novell's NetWire forum is open to all registered Compuserve subscribers. Through the NDEVREL forum, Novell Professional Developer's Program-related issues or general questions may be posted. Through the NDEVINFO forum, customers who do not have products may post pre-sales product information questions on all Novell SDKs.

E-mail: MHS or Internet (SMTP)

You may direct your questions and comments to Novell Developer Relations via Novell's Message Handling Service E-mail facility. Address your messages to devprog@novell.com. Use the same address when going through the Internet E-mail system.

ACKNOWLEDGMENTS

Publisher: Mad Poarch
Editor: Kirk R. Humphries
Design: Creative Services, Provo
Articles: Drake Backman, Neda Eslami, Holly Roff, Glenn Stephens, and Aslam Tejani

Contributors: Linda Anderson, Vitek Boruvka, Jack Gumaer, Clint McVey, Raj Perubhatla, Matt Pinsonneault, Bob Quinlan, Randy Reddy, Vicki L. Smith, Aslam Tejani, Howard Thamm, and Brenda Wallace

Special thanks to the Developer Support, Development, Developer Relations, Product Marketing, and Marketing Communications staff who contributed time and valuable input.

(c) 1993 Novell, Inc. All rights reserved.

Novell, the N design, NetWare, Btrieve, XQL, LAN WorkPlace, NetWare Name Services and LANalyzer are registered trademarks; NetWare Loadable Module, NLM, NetWare Global Messaging, Global MHS, NetWare MHS, NetWare System Calls for DOS, NetWare Runtime, NetWare SQL, NetWare Btrieve, NetWare C Interface for DOS, NetWare System Interface Technical Overview, NetWare RPC, NetWare RPC 386, NetWare LU6.2, Report Executive, NetWare Asynchronous Communication Services (NACS), NetWare Asynchronous Services Interface (NASI), NetWare Management System, NetWare 3270 LAN Workstation, Xtrieve PLUS, Novell Labs, IPX, and MacIPX are trademarks; and NetWire and Professional Developers' Program are service marks of Novell, Inc. IBM and OS/2 are registered trademarks, and NetBIOS and SAA are trademarks of International Business Machines Corporation. Microsoft is a registered trademark, and Windows and Microsoft QuickBasic are trademarks of Microsoft Corporation. AppleLink and Macintosh are registered trademarks of Apple Computer, Inc. CompuServe is a registered trademark of CompuServe Corporation. Sun Microsystems and NFS are registered trademarks and TI-RPC is a trademark of Sun Microsystems, Inc. UNIX is a trademark of UNIX Systems Laboratories, Inc. in the USA and other countries. UNIX Systems Laboratories is a wholly-owned subsidiary of Novell, Inc. WATCOM is a registered trademarks of WATCOM Systems, Inc.