> developer support home

FEBRUARY 1994 VOLUME 6 NUMBER 2


INDEX


ARTICLES:

The NLM Developer's Troubleshooting Checklist for NetWare 4.x

NetWare 4.x is being widely adopted by businesses interested in enterprise-wide networking solutions. In response, many developers have started writing a 4.x NetWare Loadable Modules (NLMs) or porting existing NetWare 3.x NLMs to the NetWare 4.x platform.

From conversations with these developers, Novell Developer Support has found that the majority of NLMs written for NetWare 3.x simply load and run under NetWare 4.x. However, in some cases, aspects of the NetWare 4.x environment require you to modify your NLMs. This article presents the most common of these special cases in a format designed for quick reference, and assumes the reader is familiar with the NetWare 3.x NLM environment.

New Memory Checking Features

The NetWare v3.12 and v4.01 debug versions of CLIB (CLIBDEB.NLM) include additional messages to help you locate un-freed resources. Many developers find these messages helpful. For documentation on this feature, look in the file, README.NOV, in the NLM SDK v3.0.

WATCOM Compiler v9.5 Patches

If you use WATCOM's v9.5 compiler and write in C++, be sure to obtain all patches and install them before you begin your development effort. To obtain the latest patches (levels A and B), contact WATCOM at 1-519-886-3700 (or on their BBS at (519) 884-2103).

Switches Required Under Domain

Currently under NetWare v4.01, the code segment of an NLM running in the OS_PROTECTED domain is flagged "execute only." If you use certain WATCOM switches, the compiler will attempt to read the code segment. Doing so causes the OS_PROTECTED domain to be quarantined. Always remember:
  • Use the "/ms" switch when compiling with WATCOM to run under Domain.
    Using "/ms" forces the code generator to include CS: overrides when accessing constants in the code segment. One side-effect that occurs when using "/ms" is that the code generated for a large, sparse case statement will put the contents of CS into ES in order to do a table scan to find the matching case label. If a hardware interrupt occurs during this time and code is executed that assumes ES == DS, a fault may occur.
    The only workaround at present (verified by WATCOM Engineering) is to use "/ot" ("optimize for time") which produces a large jump table for the sparse case statement (instead of a lookup table). This method seems to work, but may not be the optimal solution for all NLM developers.
  • Do not use the "/zc" option that places literal strings in the code segment.

Stack Sizes

Under NetWare 4.x, a CLIB thread requires a minimum stack size of 8KB. If you specify a smaller stack size, it will automatically be increased to 8KB. However, if you allocate the space yourself and pass that pointer as well as the size to BeginThread(), an error will return indicating the thread could not start because the stack size is too small. You have to increase this to 8,202 bytes (8KB plus overhead).

Exit Routines

NetWare 4.x has additional memory protection. Once memory is freed, it no longer belongs to your NLM, so accessing this resource after it has been freed can cause problems. Because the memory protection was less stringent under NetWare v3.1x, some functions worked in exit routines with NetWare 3.x that really should not have be allowed.

Exit routines include those registered with atexit() and atunload(). If you attempt to clean up or close resources that are at the thread group level, you need to do this clean up in a signal routine or within the thread before it ends. Activities requiring this procedure include closing files and destroying screens.

File Monitoring Hooks

The file monitoring hook is a new feature in NetWare 4.x that allows you to hook a file operation before or after the actual operation occurs. If, while in the monitoring thread, you wish to change context to a thread group other than the thread that resistered the hook, you must set the context specifier, set the hook, and then clear the specifier.

To alter the thread context, use the functions SetThreadContextSpecifier() and GetThreadContextSpecifier(). Then, when the thread starts, change to the correct thread group (see Figure 2). If you can operate under the thread group that registered the hook, CLIB will set up this context for you.

FIGURE 2: File system monitor hook example

   :
   :
BYTE in_use = 0;
int  mainThreadGroupID;
main()
{
   mainThreadGroupID = GetThreadGroupID ();
   :
   : "wrap" monitor hook call for context specification
   :
   SetThreadContextSpecifier(GetThreadID(),NO_CONTEXT);
   ccode = NWAddFSMonitorHook(FSHOOK_PRE_OPENFILE, openFileCallBackFunc,
                              &preOpenFileHandle);
   SetThreadContextSpecifier(GetThreadID(),USE_CURRENT_CONTEXT);
}
int openFileCallBackFunc(OpenFileCallBackStruct *ofcbs)
{
    static int cnt = 0;
    int     ccode = 0, interruptedThreadGroupID;
    char    user[48];
    WORD    objType;
    long    objID;
    BYTE    loginTime[7];
    LONG    pc;
    BYTE    ps[255];
    BYTE    volName[16];
    interruptedThreadGroupID = SetThreadGroupID (mainThreadGroupID);
    ccode = GetConnectionInformation(ofcbs->connection, user, &objType,
                                     &objID, loginTime);
    :
    :
// dump out info. to a 'log file' within the call back routines.
    if (!in_use) {
       int  f_handle;
       in_use = 1;
       f_handle = open ("SYS:LOG\\OPENS.LOG", O_CREAT|O_RDWR);
       if (f_handle !=-1){
          Printf("open(pre) request.conn=%d.user=%s", ofcbs,
                 user->connection);
          close (f_handle);
       }
       in_use = 0;
    }
    :
    :
errorOut:
    SetThreadGroupID (interruptedThreadGroupID);
    return ccode;
}
END of FIGURE 2

Forcing NetWare 4.x NLMs to Stay Loaded

With NetWare 3.x NLMs, to prevent an NLM from unloading, you had to register the check() function and force an ungetch() of a "N" to the console at the correct time. This process is much simpler under NetWare 4.x. Two 4.x APIs called SetNLMDontUnloadFlag() and ClearNLMDontUnloadFlag() change a flag in the NLM header that prevents the NLM from being unloaded at the console.

Thread Management

The NetWare 4.x OS kernel design has changed. Kernel processes for polling, scheduling, and idling have been replaced with a more dynamic process management paradigm. Processes are now considered threads, and the kernel can now use multiple "run queues" to ensure fair treatment of all system processes. One facility to execute fair treatment is handicapping threads.
  • You can specify Temporary and Permanent Handicaps of Threads.

    Developers use the NetWare Internal Debugger to analyze NLMs if they trigger an abend or "lock up." When you invoke the debugger, a ".p" command checks the different processes currently allocated. In one recurring scenario for new NetWare 4.x developers, the server seems to "hang," and the developer invokes the debugger. One of the processes dedicated to handle screen I/O is listed under "Processes not on the run queue" and the reason is listed as "handicapped wait." "Handicapped wait" is a new NetWare 4.x state that a process or thread enters, either implicitly or explicitly, when the process is delayed for whatever reason.

    Handicaps come in two varieties: temporary and permanent. A process can become temporarily handicapped if you call ThreadSwitchWithDelay(). This call reschedules the thread to be placed on the RunList after a specified number of context switches have taken place.

    The number of switches in each temporary handicap is a specifiable parameter inside NetWare ( see NetWare NLM Library Reference Volume II, Edition 1.1, "ThreadSwitchWithDelay," p. 1415).

    A process can become permanently handicapped in two ways. Calling SetThreadHandicap() sets an explicit permanent handicap by setting the number of context switches a thread is permanently handicapped before being rescheduled (see NetWare NLM Library Reference Volume II, edition 1.1, "SetThreadHandicap()," p. 1225).

    Under NetWare 4.x, the kernel also is able to permanently handicap a process if necessary. (This would be an implicit handicap from the programmer's point of view.) If a particular NLM does not yield frequently enough, a handicap can be placed on the thread's Process Control Block (PCB) by the operating system. This handicap prevents the thread from rescheduling itself immediately.

    For example, if a handicap of 100 is placed on a thread, 100 other processes will run and yield before that thread is rescheduled on the RunList (see NetWare 4.0 Architecture, Rev. 6.0, May 1993, "Temporarily Handicapping a Thread," "Permanently Handicapping a Thread," p. Kernel-5).

  • The kernel executes threads in a specific order.

    Interrupts are handled first, followed by worker, then threads, then permanently handicapped threads, then temporarily handicapped threads. When none of the above want to run, except temporarily handicapped threads, low priority threads can run (see NetWare 4.0 Architecture, Rev. 6.0, May 1993, "3.2 Six Priority Levels," page Kernel-4).

  • The new kernel no longer has to schedule work.

    When a thread has to be run, the kernel runs the work directly. Because of this new paradigm, the number of thread switches is minimized, making it very inexpensive for the running process to yield control to check if other processes want to run (see NetWare 4.0 Architecture, Rev. 6.0, May, 1993, "3.5 Implications," p. Kernel-12).

Using Handles with NetWare 4.x

With NetWare 4.x, new definitions were introduced for old NLM concepts like handles. Under NetWare 3.x, for example, the word "handles" was used to describe access to screens, TLI endpoints, semaphores, and files. Since handles were usually associated with files under NetWare 3.x, this concept was accepted. Under NetWare 4.x, however, the concept of handles has changed. Listed below are six ways this change affects developers.
  • CreateScreen() from a 3.x NLM requires a DestroyScreen() under NetWare 4.x.

    NLMs developed under NetWare 3.x that access the System Console screen will receive messages from NetWare v4.01 regarding unreleased memory resources when the NLM terminates. This problem becomes apparent in NetWare v4.01, since CreateScreen() now returns a screen handle to each screen for each NLM calling CreateScreen(). Simply call DestroyScreen() before terminating the NLM to remove the unreleased memory resources warning message.

  • Under NetWare 4.x, accessing another NLM's screens requires a new procedure.

    Under NetWare 3.x, you can access another NLM's screens by calling ScanScreens() and GetScreenInfo(). The screen handle returned from GetScreenInfo() can then be used since the handle is unique.

    Under NetWare 4.x, this procedure does not work because the screen handle is unique only to its NLM. You must access another NLM's screens in a different way. Call ScanScreens() to retrieve all screen IDs. Then, pass the screen ID (typecast to char *) to CreateScreen() as the first parameter to obtain a screen handle to that screen.

  • OpenSemaphore() returns a 0 handle.

    In versions of NetWare before 4.x, many developers checked for a zero semaphore handle as an error condition. In NetWare 4.x, a zero semaphore handle is considered a valid handle.

  • t_open() does not return a unique number.

    Prior to NetWare 4.x, t_open() returned a handle that was actually a pointer, so it was unique across all NLMs. Under NetWare 4.x, file opens return handles, much like handles under DOS. Since t_open() used the CLIB open() call internally to gain access to the streams, it now returns a handle. This handle is unique only to the NLM that called open(), so the handle plus the NLM ID is unique across all NLMs under NetWare 4.x.

  • I/O Redirection is supported for NetWare 4.x only.

    I/O Redirection on first-level files and file handles is supported only for NetWare 4.x (dup and dup2). Redirection of second-level files is supported for all NetWare versions (Stream I/O Services).

  • The maximum number of file handles that can be open at once for NetWare 4.x is 1700.

NWSNut Development

The NLM SDK v3.0 gives you the ability to create NLMs with the Novell NetWare NLM look and feel utilizing the NWSNut APIs. The NDEMO example included in the SDK demonstrates the basic capabilities of NWSNut. Following are some of the issues developers have encountered when developing with NWSNut. If you are developing with NWSNut, there are several precautions you should keep in mind:
  • Always call NWSInitializeNUT() for each CLIB screen/NUT handle pair.

    NWSInitializeNUT() creates the NWSNUT screen with a header and a NUTInfo structure containing NWSNUT data. This structure allows NWSNUT to monitor of NWSNut for each NLM that may be using NWSNUT services concurrently.

  • Always call NWSRestoreNUT() for each CLIB screen/NUT handle pair.

    You must notify NWSNUT when you are through using the NWSNUT resources. Then NWSNUT can free memory allocated on your behalf and prevent later memory accesses that may be invalid once your NLM is unloaded.

  • Default messages must be linked into your NLM.

    NWSNut requires you to link default messages into your NLM. These messages are normally created using the Message Tools included with the SDK. The NLMLink linker supplied by Novell and WATCON's WLink v9.5 linker support the linking of message files.

  • There are two known problems with NWSNut and related utilities.

    The NWSNUT import file causes errors to be generated at link time if you use it unmodified. Add commas to all entries missing trailing commas in the import file to rectify this problem. Also, the MSGLIB utility which ships with the SDK requires an updated version of the IBM$RUN.OVL file. This file is available on CompuServe in the NDEVREL forum (Section 7, IBMRUN.ZIP).

  • NWSNut NLMs will run on the NetWare 3.x platform as long as you are also running the AFTER311 compatibility module.

Directory Services & NetWare 4.x

NetWare Directory Services (DS) is Novell's implementation of enterprise-wide network access and replaces the older server-centric bindery. The primary purpose of the Directory is to provide dynamic name-to-address mapping between objects and addresses. NLM development of Directory-Aware applications is very similiar to client Directory Services application development. When developing to Directory Services, always remember:
  • You should define NWNLM before including DS header files.

    Defining NWNLM before including the Directory Services header files ensures that the compiler's preprocessor will process the header files correctly for the NLM environment.

  • NWDSMapNameToID() is required with QMS and DS.

    The NWDSMapNameToID() function is required when working with Queue Management Services (QMS) and Directory Services. When used against the Host Server of the queue, this function returns an object ID of the queue, queue server, queue user, or queue operator. One important note: the ID returned is only valid for the duration of Directory Services login.

  • Directory Services examples are available from Novell.

    Using NetWare Directory Service is really not as difficult as you may have been led to believe. Novell Developer Support now has examples for creating user objects, accessing QMS, as well as many other Directory-Aware services.

Though by no means all-inclusive, this information will save you time and energy as you continue your development in the NetWare 4.x NLM platform. If you have additional questions about NetWare 4.x, NLM development, or porting 3.x NLMs to the 4.x environment, please contact Novell Developer Support at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588.

Introduction to the NetWare Btrieve RECPLAY Utility

Novell's Btrieve Developer's Kits contain tools such as BUTIL and BTRTOOLS to make Btrieve application development a smoother process. Additional tools and toolsets are also available to developers and network administrators through Novell Developer Support and Novell's NOVLIB forum on CompuServe (Library 7, BTOOLS.EXE) for troubleshooting Btrieve applications. This article provides an introduction to one of these toolsets, RECPLAY.

RECPLAY gives developers and system administrators a specialized set of tools for troubleshooting NetWare Btrieve v6.x applications. Specifically, RECPLAY allows you to:

  • Isolate Btrieve or NetWare SQL problems by looking at the sequence of Btrieve operations that take place before the failure.
  • Isolate network and hardware related issues by replaying the history file on a different file server or network.
  • Resolve timing related problems and facilitate testing and debugging by replaying the history file.
  • Isolate performance issues by recording the start and end time of every operation. This allows the user to recognize which Btrieve operations take longer to execute.
RECPLAY contains four separate tools:
  • BRECORD.NLM
  • DUMPTR.EXE
  • CRDUMP.EXE
  • BREPLAY.NLM
This article provides a general description of each tool in the RECPLAY toolset and how they can be used together. Specific details on the various options available for each tool are documented in a text file that is supplied with the RECPLAY toolset.

General Usage

In some environments, it is useful to see what Btrieve calls are being made by an application. For example, NetWare SQL users may wish to find out which Btrieve calls are made as a result of running a particular SQL statement. To record Btrieve calls for viewing:
  1. Load BRECORD at the file server.
  2. Run the application.
  3. Unload BRECORD.
  4. Run the DUMPTR utility on a DOS workstation.
For debugging purposes, it may be helpful to record Btrieve calls and then replay the calls on the same or a different server. To do this:
  1. Load BRECORD at the file server.
  2. Run the application.
  3. Unload BRECORD.
  4. Run DUMPTR to create a script file out of the history file that was created by BRECORD. You may make modifications to the script file if you wish.
  5. Run CRDUMP to convert the script file to a binary file. This step is unnecessary if you did not make any changes to the script file created in step 4.
  6. Load BREPLAY and specify the binary file from either:
    1. Step 5, if you have made changes to the script file, or
    2. Step 1, if you simply want to replay exactly what your application did.

Tool Usage: BRECORD.NLM

BRECORD.NLM records all Btrieve calls into a history file. Any workstation executable or other NLM can make these calls. BRECORD.NLM can be configured to only record the calls for specific Btrieve files or all files.

BRECORD.NLM creates the history file immediately after you load it. However, it will be 0 (zero) bytes in size until BRECORD is unloaded. This history file is stored in binary format and can be viewed with the DUMPTR utility.

BTRIEVE.NLM v6.x must be loaded before you can run BRECORD.NLM.

The following command will record all Btrieve operations made to a file called PATIENT.DTA located in SYS:\DATA into a binary file called BREC.DMP in the same directory. Btrieve will create BREC.DMP or overwrite it if it already exists in SYS:\DATA.

LOAD BRECORD /f=sys:\data\brec.dmp
  /n=sys:\data\patient.dta

Tool Usage: DUMPTR.EXE

DUMPTR.EXE is a DOS workstation utility that displays readable output from the history file to the screen. You can redirect this output to a file using the DOS redirection operator. DUMPTR.EXE also creates a script file which can be edited and formatted back to a new history file.

As an example, the command below will read the binary file BREC.DMP created by BRECORD.NLM and display all the Btrieve operations that were recorded, including the key and data buffer of each call. The resulting output will be redirected to the BREC.TXT file.

DUMPTR /f=\data\brec.dmp /k
  /s >brec.txt
Figure 3 shows an example of the output created by the previous DUMPTR command. The Btrieve operation being performed is shown in the "opcode" column, and the resulting status of this operation is listed in the "stat" column (0 indicates that the Open operation was successful). The "cursor ID" represents a handle to a file for operations that access a file (i.e., Open or Get Equal). This column will be blank for non-file operations such as Version or Reset. The cursor ID specified on the Open is used to identify the file on subsequent operations. For example, if you see a Get Equal on cursor ID 2, you will know it is reading the PATIENT.DTA file.

FIGURE 3: Example output file format redirected to BREC.TXT

                                                         System
  opCode        stat cursor client ID  key    start t.  end time   exec.t.
                     ID                number       (0.1 ms)
------------------------------------------------------------------------
  Open           0   2      0200400a   0            24        63     39
key  buffer:41 55 53 2d 54 45 4b 33-31 31 2f 53 59 53 3a 44   SERVER10/SYS:...
            41 54 41 2f 50 41 54 49-45 4e 54 2e 44 41 54 00   DATA/PATIENT....
data buffer:00 00 00 00 00 00 00 00-00 56 00 da 84 56 00 00   .........V...V..
            00 57 00 84 20 00 00 00-00 00 00 00 00 00 00 00   .W..............
            00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
END of FIGURE 3
The "client ID" references the user who made the Btrieve call. All calls from the same user will have the same client ID. The "key number" column will show the key number used on the call, or will be blank for operations that do not use a key number.

The system times ("start t.," "end time," and "exec.t.") represent the system start time, end time, and execution time for that operation. In the example in Figure 3, the Open operation took 3.9 milliseconds.

The key buffer and data buffer information shows what is being sent in to Btrieve for the particular call. The buffers are shown both in hex and in ASCII. Again, these parameters will only show when appropriate. For example, the key buffer is required for an Open, Get Equal, Get Next, Create, etc. The data buffer is required for an Open, Get Next Extended, Get Direct, etc.

You can also enter a command to create a script file. The following command generates as scriptfile called, SCRIPT.TXT, and dumps the Btrieve operations recorded by BRECORD.NLM from BREC.DMP to this text file.

DUMPTR /f=\data\brec.dmp
  /r=script.txt

Tool Usage: CRDUMP.EXE

CRDUMP.EXE is a DOS workstation utility that formats a script file to a binary file. Script files created with DUMPTR.EXE can be edited for troubleshooting purposes and reformatted in binary format using CRDUMP.EXE. This binary file can be used by BREPLAY.NLM to re-execute all of the operations.

The following example command converts the script file, SCRIPT.TXT, created by the DUMPTR utility with the /r option, into a binary file that can be used by BREPLAY.NLM.

CRDUMP script.txt brec.fil

Tool Usage: BREPLAY.NLM

BREPLAY.NLM executes Btrieve calls previously recorded by BRECORD.NLM. To run BREPLAY.NLM, BTRIEVE.NLM v6.x must be loaded.

The following example command replays every operation that has been previously recorded by BRECORD.NLM or created from a script file with CRDUMP.EXE. It also writes a status report to a list file named BRECLST.OUT after every 200 operations are played.

LOAD BREPLAY /f=sys:\data\brec.dmp /p=200 /l=sys:\data\breclst.out
RECPLAY is an in-house utility made available to developers and network administrators as a courtesy. This utility is provided as is and it is not an official Novell product. Novell is not responsible for maintaining or enhancing this product.

For more information on this toolset, contact Novell at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588.


TECHNICAL INSIGHTS:

t_event() is Not Supported (NetWare Client SDK 1.0e)

The prototype for the function t_event() is contained in the TIUSER.H file, but this function is not supported. For this reason, t_event() is not documented and this function should not be used.

The prototype for this function will be removed from the header file in future releases of the NetWare Client SDK.

NWSetAuditingIdentityFails with Error 0x97 (NLM SDK 3.0)

The call to NWSetAuditingIdentity() fails with the error, 0x97 (ERR_AUDITING_NOT_ENABLED) even though the user has enabled auditing for Directory Services via AUDITCON.

The AUDITCON utility must be used to initiate auditing server events. To enable auditing on a volume from the AUDITCON main menu, select "Available Audit Options". Then, in sequence, choose:

  • Auditing Configuration
  • Audit By Event
  • Audit By Server Events
  • NLM Add User ID Record
Changes must be saved before the NLM function will work. On page 53, the NetWare Using NetWare Services for NLMs v1.1 manual notes:

"For Auditing to begin adding records from your NLM, the AUDITCON option "NLM Add Audit Record" has to be enabled. For details, see the section "Server Events" in the chapter on Auditing in NetWare 4.0 OS Architecture."

The NetWare 4.0 OS Architecture manual (Chapter 8, page Auditing-9) also describes Auditing Options for Volumes and Servers. It does not men-tion needing to enable auditing for setting an identity.

UC Option on Btrieve Extended Operations (Btrieve v5.x and v6.x)

Btrieve v5.1x and above now support the UC option on the Get Next Extended (36) and Get Previous Extended (37) operations. This option tells Btrieve to begin searching for records that match the provided filter (if defined) with the current record instead of the Next/Previous record. The application still must establish positioning with a Get First (12), Get Equal (5) or some other operation before using this option in the extended call.

UC functionality is automatically provided in the 5.15 and 6.x versions of the NetWare Btrieve NLM. All other current versions of Btrieve must be patched in order for the UC option to be functional, including:

  • NetWare Btrieve VAP (BSERVER.VAP v5.15),
  • Btrieve for DOS (BTRIEVE.EXE v5.10a)
  • Btrieve for MS Windows (WBTRCALL.DLL v5.10)
  • Btrieve for OS/2 (BTRCALLS.DLL v5.10)
Patches for these versions of Btrieve are available in Novell's NOVLIB forum on CompuServe (Library 7, BTR515.EXE or BTR510.EXE depending on the version of Btrieve being used). You can also obtain these patch files from Novell Developer Support (see "Contacting Novell" at the end of this issue).

The UC functionality is also available with the Step Next Extended (38) and Step Previous Extended (39) operations, but only with the Btrieve NLM (v5.15 and all 6.x versions). The UC option can not be used on the Extended Step operations when using the client versions of Btrieve or the Btrieve VAP. Any attempt to do so will return a successful status code, but no records will be returned in the data buffer.

Documentation for MSGLIB Missing (NLM SDK 3.0)

The NLM Development and Tools Overview discusses the messaging services in Chapter 14. All of the components of messaging are described except for MSGLIB. This oversight has been reported and will be corrected as soon as possible.

UMSG_GET_SEL_NEXT and List Component (AppWare Foundation for Windows 1.70)

With a multiple selection list instance for which multiple line items are selected, if you would like to retrieve all selected items, you must:
  • Get the index of the very first selection using the USMG_GET_SEL message
  • Use the index of the first selection as "param1" in a UMSG_GET_SEL_NEXT message to obtain the next messages.
However, only the index of the current selection is returned. This situation occurs because the index passed in for the UMSG_GET_SEL_NEXT should be one greater than the index of the current selection. To receive the index of the next selection in a List instance using the UMSG_GET_SEL_NEXT message, the index of the current selection you pass in "param1" should be incremented by one as shown in Figure 4.

FIGURE 4: Incrementing the index of current selection by one

/* _lNid is the nid of the list instance */
/* fNdx and nNdx are nint32 variables */
 if ((fNdx = UMsgSend( &Access, _lNid,
                       UMSG_GET_SEL, N_NULL, N_NULL)) != UMSG_LOC_NONE){
         UMsgSend( &Access, _lNid, UMSG_GET_DATA,
                   fNdx, (UMsgParam)(pnstr) line);
         fNdx++; /* Increment the current selection index */
         while ((fNdx = UMsgSend( &Access, _lNid,
                                  UMSG_GET_SEL_NEXT, (nparam) fNdx,
                                  NMakePtrParam (&nNdx)))
                                                != UMSG_LOC_NONE){
            UMsgSend( &Access, _lNid, UMSG_GET_DATA,
                      nNdx, (UMsgParam)(pnstr) line);
            fNdx = nNdx; /* assign the index of the next selection */
            fNdx++; /* Increment the current selection index
                       to get the next selection */
            } /* End of the while loop */
        } /* End of the if condition */
END of FIGURE 4

Calling Netware SQL APIs from NLMs (NetWare SQL v3.00)

Two files are required to call NetWare SQL APIs from an NLM: NWSQLNIF.H and NWSQLAPI.IMP. Make sure to use the appropriate cdecl statement in the NWSQLNIF.H file. Two different cdecl statements are commented in the header file. One statement is for the WATCOM v9.01 (or higher) Compiler and the other is for versions of the WATCOM Compiler before v9.01.

Insert the appropriate cdecl statement at the top of the NWSQLNIF.H file. Also make sure to replace the cdecl statement in the NWTYPES.H file with the one used in the NWSQLNIF.H file. The NWTYPES.H file is located in the NOVH directory of either the WATCOM Compiler or the NLM SDK v3.0. The NWSQLAPI.IMP file must be imported into the .LNK file of the application.

QueryServices() Returns Status 1 (NetWare Client SDK 1.0e)

Using NWIPXSPX.DLL (dated 11-2-93) from the NetWare Client SDK v1.0e, a call to QueryServices() from a MS Windows application will fail with a status 1, when it should succeed and return a status 0.

Novell is aware of the problem and is working on a solution. Currently, the workaround is to use the version of NWIPXSPX.DLL that is dated 5-18-93 from the NetWare Client SDK v1.0d.

NetWare OS/2 Requester Produces Status 95 (NetWare Btrieve (NLM) v6.10)

NETX must be loaded and the LOGIN process must be executed in every Private DOS session. Even though the MAP command may display drive mappings, those resources actually are not available to the DOS session. Use the LOGIN command to allocate resources to the DOS box. Otherwise, a Btrieve status 95 (Session No Longer Valid) may be returned if you use a Private DOS box with OS/2 v2.1 and the NetWare OS/2 requester v2.01.

When using Private DOS sessions with the 2.01 version of the NetWare OS/2 requester and the Btrieve OS/2 requester v6.1x, always verify that NETX is loaded and that the LOGIN procedure described above has been followed.

Erroneous Status 82s and 2s (Btrieve for DOS 5.10a)

When a user attempts to read a Btrieve file that is being modified, the file may actually be busy. This situation may result in the read operation receiving incomplete data, causing an erroneous status 82 (Lost Position) or status 2 (I/O Error).

Currently, there is no solution for the client Btrieve engines, except to retry the operation. The status messages are in error and disappear when the write operation completes. The status messages result from a timing window problem.

No erroneous status is returned when using transactions. Also, this situation does not exist with the Btrieve NLM or VAP, since only one engine handles the writes and reads for all users.

MS AppStudio and .VBX Custom Controls (AppWare Foundation for Windows 1.70)

When you attempt to use an AppWare Foundation .VBX on a dialog box, Microsoft AppStudio returns the following error:
"Cannot drop VB controls in non-MFC dialogs."
When creating a new resource in AppStudio, AppStudio presents a dialog box that permits you to select the current resource type. The resource type defined in AppStudio must be a Microsoft Foundation Class (MFC) Resource Script.

To prevent this error, select "Resource Script" from the list box and select the "Use Microsoft Foundation Classes" checkbox. Doing so automatically adds another include file, AFXRES.H (provided with MS Visual C++), to your resource file.

Establishing Multiple Btrieve Sessions Triggers Status 91 (NetWare Btrieve (NLM) v6.10)

Versions of NetWare Btrieve prior to v6.10c may return a status 91 (Server Error) if many users attempt to establish a session simultaneously.

NetWare Btrieve returns this status because BSPXCOM.NLM has posted only one Listen-For-Connection Event Control Block (ECB). BSPXCOM.NLM v6.10b, which is included with NetWare Btrieve v6.10c, now posts five Listen-For-Connection ECBs for establishing sessions with workstations.

NetWare Btrieve v6.10c is available for downloading from Novell's NOVLIB forum on CompuServe (Library 7, BTR61.EXE), or from Novell Developer Support.

: Bindery Access Levels & NetWare 4.01 (NetWare Client SDK v1.0x)

NWGetBinderyAccessLevel() always returns 0x33 (Supervisor Access Level) for the access level on a NetWare 4.01 server. This situation does not occur on NetWare 3.11 or NetWare 4.0.

To ensure that the proper bindery access levels are returned, apply the Directory Service updates for NetWare 4.01. The patches are available on Novell's NOVLIB forum on CompuServe (Library 1, DSPAT.EXE).

NLM Optimization and WATCOM v9.5 (NLM SDK v3.0)

An NLM compiled for optimization under WATCOM v9.5a generates a call __STOSB when the code contains a loop in which an array is initialized to the same value. WLINK then returns an error with the undefined symbol, __STOSB. This symbol is not in CLIB.IMP or CLIB NLM.

This situation has been tested with CLIB v3.12, CLIB v4.01b, and WATCOM v9.5a with the compile options, "/ms /w4 /s /zp1 /3s /oax." The problem does not occur under WATCOM v9.01e because optimization is handled differently.

For example, if your source code contains the following segment:

int i;
for (i=0; i<12;i++)
  internet[i]=0;
WDISASM generates the information in Figure 5 under WATCOM v9.5a.

FIGURE 5: Assembly code generated by WDISASM (WATCOM v9.5a)

 0000  53                InitUserId      push    ebx
 0001  8b 5c 24 10                       mov     ebx,+10H[esp]
 0005  b9 0c 00 00 00                    mov     ecx,0000000cH
 000a  89 d8                             mov     eax,ebx
 000c  31 d2                             xor     edx,edx
 000e  e8 00 00 00 00                    call    __STOSB
 0013  8b 44 24 08                       mov     eax,+8H[esp]
 0017  66 89 43 0c                       mov     +0cH[ebx],ax
 001b  8b 44 24 0c                       mov     eax,+0cH[esp]
 001f  66 89 43 0e                       mov     +0eH[ebx],ax
 0023  5b                                pop     ebx
 0024  c3                                ret
END of FIGURE 5
WATCOM v9.01e would generate the information in Figure 6 (with a different function name, same "for" loop).

FIGURE 6: Assembly code generated by WDISASM (WATCOM v9.01e)

 0000  57                my_printf       push    edi
 0001  55                                push    ebp
 0002  89 e5                             mov     ebp,esp
 0004  81 ec 04 04 00 00                 sub     esp,00000404H
 000a  8d bd fc fb ff ff                 lea     edi,-404H[ebp]
 0010  b9 03 00 00 00                    mov     ecx,00000003H
 0015  8c da                             mov     dx,ds
 0017  31 c0                             xor     eax,eax
 0019  06                                push    es
 001a  8e c2                             mov     es,dx
 001c  f2 ab                             repne   stosd
 001e  07                                pop     es
END of FIGURE 6
WATCOM prefers that their static link libraries be used for producing NLMs with WATCOM v9.5a, rather than using the CLIB.NLM entry points. __STOSB is defined in these libraries.

In the old method of using CLIB.NLM for all the entry points, WATCOM recommends that you extract the module STOS from the static library and link it as an ordinary object module. If using NLMLINK, you have no choice but to link the STOS module, since NLMLINK does not understand the libraries at all.

Alternately, using WLINK you may be able to leave __STOSB in the library and use both modules, but in that case you must place the static library at the end of the library path. Using WLINK may include more library functions than desired, so you need to experiment to determine the side effects. WLINK users could also extract the module and link it in.

Editable List Instances (AppWare Foundation for Windows 1.70)

In the AppWare Foundation, Editable List Instances and Edit Text Instances are associated through a Instance Relation (for more details, see the documentation on "Instances"). When filtering messages for a Editable List Instance and an associated Edit Text Instance, the messages are directed to the List Instance first. Thus, the order in which you process messages is of critical importance.

List Instance filters are handled first, followed by the Edit Text filters. Be careful when filtering for the same messages as this may affect program flow or data.

Allocating Memory for ALM Development (ALM SDK v1.0)

The recommended memory requirement to do quick AppWare Loadable Module (ALM) debugging and testing is about 6MB to 8MB. Anything less will affect MS Windows performance and interfere with debugging. With less memory allocated, unpredictable crashes may occur while debugging ALMs. If these symptoms are seen, examine both the available TPA and the amount of total memory (including Windows Virtual Memory) and try any of the following:
  1. Use virtual memory (performance will drop dramatically). Enabling 32-bit disk access (if appropriate for your disk) will help minimize this performance drop. As always, be careful when creating a permanent swap file on a compressed drive. The exception to this rule is when using Novell DOS 7 and its included Stacker drivers, which handle compressed permanent swap files correctly.
  2. Remove Visual AppBuilder from the ALM debugging environment. Do this by creating an application, then running the created application.
  3. Remove any unnecessary MS Windows programs (e.g., Clock, Notepad). The exception to this rule might be a system load monitor or a memory monitor.
  4. Remove any disk caches using extended or expanded memory. (Again, performance will drop.)
  5. Add more memory or move to a machine with more memory.

WINDOW Objects & "Opened" Signal (Visual AppBuilder for Windows v1.0)

If a Window object is configured to be Initially Visible (using the Initially Visible button in the Edit Window dialog), the object's "Opened" Signal is never raised. This situation is counter-intuitive if you hook a function chain to a Window Object on the signal "Opened," as the signal is never raised with this condition. As a workaround, make your Window Object Not Initially Visible and hook a function chain to the Application Object, which opens the Window Object.to generate the desired signal.

NIBBLES AND BITS

Fast Answers to Common Questions

Visual AppBuilder for Windows

Tip: The List :: Clear List function does not clear a list. Until this is corrected, assign an empty list to the filled list as a workaround.

Tip: Once the Text Object style option Editable has been unchecked, the Vertical Scrollbar option is dimmed and its check box is disabled. To have a non-editable text object with a vertical scroll bar, select the Vertical Scrollbar option before unchecking the Editable option.

AppWare Foundation for Macintosh

Q - What versions of Macintosh Programmer's Workshop (MPW) C can you use with the AppWare Foundation for Macintosh v1.70 ?

A - You can use either MPW C v3.2.4, or MPW C v3.3b1.

NetWare Client SDK

Q - Can I distribute the NetWare Client SDK DLLs with my application?

A - You may legally distribute the NetWare Client SDK DLLs with your application provided that you have signed and returned the Derivative Software License Agreement to Novell.

Q - I obtained the Client API for Assembly documentation and it said to look for APIASMnn.EXE up on CompuServe for the latest documentation updates but it wasn't there! Where is it?

A - This file is now available on CompuServe in NOVLIB library 7. The filename is APIASM.EXE.

Q - How do I change the default context for a workstation under Directory Services?

A - Use NWSetDefaultNameContext(), instead of NWDSSetContext(). The context established by NWDSSetContext() is only valid for the duration of your application.

Tip: The NetWare Client API for Assembly documents assembly system calls. Making these calls from MS Windows is neither documented nor supported. Customers writing MS Windows applications should use the C functions as documented in the NetWare Programmer's Guide for C.

Tip: Novell has released a quarterly update to the NetWare Client SDK v1.0d bringing the latest revision to v1.0e. This update can be obtained from Novell's NDEVREL forum on CompuServe, Library 6, in the following files:

CLINEW.TXT - Description of files
CLIWIN.ZIP - MS Windows updates
CLIOS2.ZIP - OS/2 updates
CLIDMC.ZIP - DOS Microsoft C updates
CLIDBC.ZIP - DOS Borland C updates
CLIINC.ZIP - Include file updates
Only members of the Professional Developer's Program may access Library 6. If you are a member, but your account has not been enabled for access to library 6, send a message to account 76711,111 requesting access.

Tip: The NetWare Client SDK v1.0e is fully compatible with the Borland C++ v4.0 compiler. Although Borland's new compiler will create 32-bit code, since it does not create an EZ-OMF object, it currently will not support NLM development.

Q - What is the breakdown of field information returned by NWGetDirSpaceLimitList() in the 512-byte returnBuff?

A - The returnBuff parameter breaks down as shown in Figure 7. There is no predefined structure for the returnBuff parameter.

FIGURE 7: Field breakdown for NWGetDirSpaceLimitList() returnBuff

  Offset   Field           # Bytes    Remarks
  ----------------------------------------------------------------------
    0      numberOfEntries    1       Number of entries returned. An
                                        entry consists of the next three
                                        fields:  Level, Maximum, Current
    1      Level              1       Distance from the directory to
                                        the root.
    2      Max                4       Maximum amount of space assigned
                                        to a directory.
    6      Current            4       Amount of space assigned to a
                                        directory minus the amount of
                                        space used by a directory and
                                        its subdirectories.
    10     Level              1       <-  These 3 fields
    11     Max                4       <-  repeat numberOfEntries
    15     Current            4       <-  times. (up to 512 bytes)
    *
    *
    *
    etc.
END of FIGURE 7

Q - I need to connect to an SCO UNIX machine and the server advertise can take up to two seconds to respond to my query. I rewrote QueryServices() to wait up to two seconds, but I'd prefer to stick with the true Client SDK libraries. Is there any other way to adjust the "time-out" value on the NetWare Client SDK QueryServices() call?

A - QueryServices() has a built-in "time-out" value. Issue the query services call, then loop until a response or a predetermined "time-out" occurs. This predetermined "time-out" is hard-coded, so you must modify the code to wait for a longer period of time.

NLM SDK

Q - Can I use Borland C++ v4.0 for NLM development?

A - No. Borland C++ v4.0 will not produce the Phar Lap Easy-OMF format object files that are required by NLMLINK to generate an NLM.

Q - When my NLM calls LoginToFileServer() against a remote server, the call returns status 5. What is this status and what should I do about it?

A - Status 5 is an NetWare Core Protocol (NCP) error code indicating a broadcast error. The likely reason for LoginToFileServer() to return this code is if the "Reply To Get Nearest Server" parameter is set to OFF for the server. It will take the server longer to locate other servers on the network with this parameter set to OFF, and if an NLM tries to login to an unknown remote server, the login may "time out" before the remote server is found.

Status 5 generally is returned only when the server has just been started or when you have just run "RESET ROUTER" on the console. It does not seem to occur if "Reply to Get Nearest Server" is left with its default setting of ON.

Q - The NLM SDK v3.0 documents GetScreenInfo() and briefly mentions that it replaces the MapScreenIDToHandle() and that I should not use the latter. However, since GetScreenInfo() does not work with CLIB v3.11d and v3.11e (the currently available versions), it seems that I have to use MapScreenIDToHandle(). How do I use this call?

A - Here is the prototype for using MapScreenIDToHandle():

     extern int  MapScreenIDToHandle(
            int  __screenID,
            char *__name,
            LONG *__attrib );

Q - When writing an NLM, how do you respond to queries? Does another process take control of socket 0x0452, or is that taken care of for you in NLMs and VAPs?

A - You do not have to respond to queries as an advertising NLM. The file server you are running on is a router, so it will respond for your advertising NLM. (The same holds true for VAPs as well.)

In general, when running on a client or a server, you only have to make the call to AdvertiseService() at the beginning of your application. Once you have invoked that function, your application should not have to deal with any queries or broadcasting every minute. AdvertiseService() will take care of all SAP duties in the background.

NetWare for OS/2

Tip: Under OS/2 2.1 running the NetWare requester 2.01, there may be instances when you receive the following error message:
Application could not demand-load segment NETAPI.number.

This message indicates that the application is trying to make a LAN Manager-specific call, which in turn tries to "demand-load" the DLL for Lan Manager and produces the error. These LAN Manager-specific calls are not supported by the requester. To avoid this situation, make sure that all APIs are not referencing specific DLLs outside of their environment.


MAD'S COLUMN

Hello and welcome to the February 1994 issue of Novell Professional Developer Bullets.

By now, many of you have read the press release regarding Novell's plans for its database product line. To briefly recap: on January 26, Novell announced a Memorandum of Understanding (MOU) to transfer ownership of the database products to Btrieve Technologies Inc. (BTI). This is a very positive statement of direction by both Novell and BTI concerning this product line and database developers.

The definitive agreement will be reached within the next eight weeks. (The press release and a Q & A fact sheet is available on Novell's Automated Fax System: dial 1-800-NetWare, choose option #1, choose option #1 again, and request document #5007.) All registered users and developers will receive a letter of notification when the agreement is finalized.

Meanwhile, because this is an MOU and not a definitive agreement, it's "business as usual" here at Novell. "Business as usual," of course, means that developer support, pre-sales product information and sales for the database products are still being handled through Novell's 1-800-NETWARE telephone number. I know that many of you have called BTI asking for these services, and it has delayed your responses because your calls must then be forwarded to Novell for completion.

If you do have questions specific to Btrieve Technologies Inc. please call 1-800-287-4383 (1-800-BTRIEVE). Thank you in advance for your cooperation and...

Happy_Programming! Mad Poarch
Director
Developer Support/Services


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.

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.