Developer Links
SUPPORT FORUMS  
SAMPLE CODE & TIDS  
TEST/DEVELOPMENT KIT INFO
 
DEVELOPER LABS  
NOVELL SUPERLAB  
SUPPORT DOCUMENTS  
STRATEGIC/EXECUTIVE ISSUE TRACKING  
SYSOP PROGRAM  
     
Related Links
 
 
 
 
 
Related Links  
 

 
DEVELOPER SUPPORT HOME  

JULY 1993 VOLUME 5 NUMBER 7


INDEX


MAD'S COLUMN

Hello and welcome to the July 1993 issue of Bullets!

Last March when I was discussing "March Madness," we left off with a word from our sponsor. The NBA finals were nearing, the Indy-500 was pending and baseball's All-Star game was way in the future.

Now, four months later, it was North Carolina over Michigan, the Bulls over the Suns, and Ricky Mears and the American League came up winners. Time flies.

Now it's time for the 1993 Olympic Festival to begin. Each non-Olympic year, a different US city hosts this showcase for American athletes. Over 4,200 participants, 12,000 volunteers and 1,000 journalists at 22 different geographic locations will combine efforts in going for the gold.

The July 23rd - August 1st activities in San Antonio will not only showcase human athletic skills and robustness but those of NetWare's SFT III as well. Each host city has the responsibility for designing and implementing its own technological solution. This is the first festival where PC- based hardware and software will provide the entire computing solution!

Novell is proud to be a contributor to the Olympic Festival and we hope we win "our gold medal" as well, and maintain our championship status. In each event, I'd like to congratulate all of the athletes in advance. Who knows--their second career may be writing NetWare programs.

Happy_Programming!

Mad Poarch
Director
Developer Support/Service


ARTICLES:

Writing a Network Resource Manager with the MacIPX SDK

Novell's MacIPX Software Developers Kit v1.0.1 is a quantum leap toward providing full Macintosh integration into NetWare. In addition to making the IPX/SPX transport protocol available to the Mac, the MacIPX SDK includes a well- documented set of APIs that allows you to access this protocol when developing cross-platform NetWare client applications.

The Macintosh is a logical target for a utility like the Network Resource Manager, since it offers an intuitive user interface and efficient multiprocessing. The Resource Manager allows a network administrator to manage workstation configuration throughout the network. This article examines using NetWare Diagnostic Services and the MacIPX SDK to create a Network Resource Manager for the Macintosh.

NetWare Diagnostic Services are built into the device drivers that support the IPX/SPX transport protocol. Examples of diagnostic functionality include the ability to identify all internetwork nodes and their software components, to query these nodes for statistical information, and to perform point-to-point tests such as timing studies. Diagnostic APIs, which automatically perform the packet formation and data retrieval for these services, are included with the NetWare Client SDK and the NetWare C Interface products for DOS, Windows and OS/2. To use these services in a similar manner on the Mac, the first step is to create a set of Diagnostic APIs using the MacIPX SDK.

The Mac Diagnostics make use of both the IPX and SPX support provided in the MacIPX SDK. The IPX-based APIs are used to query the network for nodes (responders) or target a particular node and request that it listen for an SPX connection. The SPX-based APIs are used to establish and maintain a diagnostic connection with a particular responder and query its componentry. MacIPX also includes a set of SAP (Service Advertising Protocol) APIs, but they are not used here.

Resource Manager Design

The design of the Network Resource Manager application centers on the type of information that is available from the diagnostic services. The design is expandable to incorporate additional responder data as well. The Manager takes advantage of the intuitive interface and aesthetic presentation built into the Macintosh operating system. It is menu driven; it allows the user to acquire information on an ad hoc basis, rather than search through reams of undesired data. In addition, the Manager presents its information in dialog boxes with controls that allow the user to zoom in on a particular node or component.

The Manager's design allows administrators to spontaneously query the network for information from respondent nodes through the use of the Target Broadcast menu option. Given the list of responders, you can then select a particular node (using the Target Node menu option, or by selecting it from the responders list) and continue to query it for the information he seeks. Target Node establishes a diagnostic session with the specific respondent. Subsequent selections from the Diagnostics menu address that particular responder until another Target is chosen or the application is terminated.

Available Information from NetWare Diagnostic Services

The NetWare Diagnostic APIs can be divided into five categories:
  • IPX/SPX Component Functions
  • Driver Component Functions
  • Shell Component Functions
  • Bridge Component Functions
  • Environment Support
IPX/SPX Component Functions return version, statistical and timing information for any target node. Statistical information includes success/failure counts in requests and transmissions. Diagnostics can determine transmission efficiency with the timing and packet count functions.

The Driver Component Functions retrieve the configuration and statistics for the shell or bridge drivers. Another API returns the bridge driver status. Shell and Bridge Component functions deliver specific information about the component software, including tables and addresses. Diagnostic's environment support determines available components at a node, either through specific targeting or broadcasting a configuration request.

Target Machines

There are currently two ways to determine the node to address with the Network Resource Manager: either through direct entry of the node's full IPX address (network:node) or by selecting the address from a list of respondents to the target broadcast. Use of the 10-byte hexadecimal address is an "unMac-like way" to identify a network object. You can use an alternate method, however, since there are several ways to handle identity on the Macintosh platform.

Converts from other platforms might expect a discussion on the use of the NetWare Bindery at this point, since it is a straightforward way to obtain names and other connection information about network objects. A Bindery lookup by object type equal to OT_USER returns a list of valid user names. You could then query the file server for connection information about the user object to target a workstation by address. Unfortunately, full support for the Bindery APIs isn't available with MacIPX. While the SDK does include a bindery lookup API, MacIPXScanBinderyObject() establishes a temporary connection to the server and does not match its security to the requesting workstation. This temporary connection has attached security and cannot look up user objects.

Other devices on the network available to the Mac workstation can query the Bindery for user information. The "Future Enhancements" section of this article explains the solution that a future version of the Resource Manager will use. Presently, the operator must know the IPX address of the targets, possibly through the use of the "USERLIST /a" utility. The Resource Manager uses this address in its call BeginDiagnostics() to receive a diagnostic connection ID and a component list for the respondent.

BeginDiagnostics() consists of two functional parts: First, it opens a temporary socket and issues an IPX request to the diagnostic socket on the target machine. The target machine responds back with an SPX socket number on which to establish a connection and a list of components present on that machine. BeginDiagnostics() then establishes an SPX connection with the target on its requested socket and returns the connection ID to the caller for use with future diagnostic calls. EndDiagnostics() terminates this connection.

IssueConfigRequest() is a new diagnostic API created to add functionality to the Network Resource Manager. It is not available with other platform specific SDKs, but is documented in the NetWare System Interface Technical Overview. With MacIPX, IssueConfigRequest() is implemented with a series of IPXSend() and IPXReceive() calls. It takes advantage of the exclusion list feature in the request broadcast and builds a list of unique respondent nodes and components. The limit of 80 addresses in the exclusion list implies a maximum number of respondents returned with this API.

Unlike other diagnostic APIs, IssueConfigRequest() uses an Event Service Routine to receive the incoming packets instead of querying the OS queue head or Event Control Block (ECB) status fields. This may be a more efficient means of receiving large quantities of packets in a short time period. The Network Resource Manager makes use of IssueConfigRequest() in the Target Broadcast menu option.

Network Area Information

The broadcast option of the Manager can determine what kinds of resources are available on the network by sorting the respondents into groups by type. Previous discussions have centered on broadcasting for workstation respondents. You could just as easily use the broadcast method to list available bridges. With this information, the Network Resource Manager determines the layout of the network in terms of segments and routes.

Two processes implement the "ad hoc" responder access: you can select a target through a list of respondent nodes using the Target Broadcast menu option. The other choice gives users a more global view of the network with the Topology Window. From this window, you can select a target network to query, or select a target node within that network segment. The Target Topology menu option sorts the responses by network and continues the exclusion list process for each network segment until the maximum number of responses is reached.

Additional Node Data

To add to the functionality of the Network Resource Manager, the basic design is expanded to query nodes for additional data using a method similar to diagnostics. This design could allow the Network Resource Manager to determine third-party software versions and system hardware configurations, as well. Obviously collecting of this type information is platform-dependent.

Interrupts are available to DOS (and Windows) applications that return hardware setup information like drive type(s), monitors, and total and available memory. Operating system APIs duplicate this functionality on OS/2 machines and Macintoshes. You might collect setup data from a node by installing a system that mimics diagnostic responder functionality. For example, on a DOS machine, you could create a TSR (terminate and stay resident program) that opens a known socket upon initialization and sleeps until it receives a request for configuration (from the Mac requester) on that socket. It then collects the hardware configuration information and replies back. A TSR would work for both DOS and Windows environments. OS/2 would use a daemon and the Mac an INIT, but the concept is the same.

Adding this type of functionality greatly expands the usability of the Network Resource Manager. At first, this project seems very complex. However, it is really only three program shells that share communications functionality. This type of application development is a perfect candidate for the NetWare Client SDK (DOS, Windows and OS/2) and for the MacIPX SDK for the Macintosh INIT.

Programming with MacIPX

The Network Resource Manager uses the diagnostic APIs in the NetWare C Interface for DOS as a basis for diagnostic services on the Mac. This method reveals many technical issues common to cross platform NetWare development and specific to DOS-to-Mac porting. Fortunately, the design of the diagnostic APIs on the DOS side is very uniform. Definitions, compiler options and advice to programmers resolve many of the issues.

Except for the APIs from the environment category (BeginDiagnostics(), IssueConfigurationRequest(), etc.), most APIs follow a particular pattern in execution. The process is to:

  • Set up an SPX packet containing the diagnostic request
  • Issue an SPX send
  • Wait for a response
  • Copy response data into its structure
  • Return a success code.
The primary functions for handling this process are SendSPXPacket() and GetDiagnosticResponse(). SendSPXPacket() accepts as parameters the diagnostic connection ID, the request buffer and the request buffer size. GetDiagnosticResponse() is similar except that it uses two buffers and two size parameters. The first buffer is the response data from the transport of the request, (i.e., whether the request was valid, accepted and replied to); the second buffer contains the data itself. Figure 1 lists excerpts from the source for these two functions; they contain several items particular to developing with MacIPX.

FIGURE 1: Source excerpts for SendSPXPacket( ) & GetDiagnosticResponse( )

static int SendSPXPacket(WORD connectionID,
                         BYTE *buffer1, WORD size1)
{
   int ccode, returnCode;
   SPX_SESSION CSB;
   SPX_HEADER requestHeader;
   SPX_ECB requestECB;

   memset((char *)&requestHeader,0,sizeof(SPX_HEADER));
   memset((char *)&requestECB,0,sizeof(SPX_ECB));
   ccode = SpxGetConnectionStatus(connectionID, &CSB);
   if ( !ccode )
   {
      requestHeader.connectionCtl = 0x00;
      requestHeader.dataStreamType = 0x00;
      requestECB.ESRAddress = 0;
      requestECB.fragCount = 2;
      requestECB.fragList[0].fragAddress = &requestHeader;
      requestECB.fragList[0].fragSize = sizeof(requestHeader);
      requestECB.fragList[1].fragAddress = buffer1;
      requestECB.fragList[1].fragSize = size1;

      SpxSendSequencedPacket(connectionID,&requestECB);
      while ( requestECB.status == ST_SENDPACKET && !CheckTerm() )
         IpxRelinquishControl();
      if ( requestECB.status == 0x3000 && !exitProgram )
         returnCode = NO_ERRORS;
      else
         returnCode = COULD_NOT_SEND_REQUEST;
      }
   else
      returnCode = BAD_CONNECTION_ID;

   return returnCode;
} // END - SendSPXPacket

static int GetDiagnosticResponse(WORD connectionID, BYTE *buffer1,
   WORD size1, BYTE *buffer2, WORD size2)
{
   int foundECB = FALSE;
   int returnCode = RECEIVED_REPLY_IN_ERROR;
   SPX_ECB *comeBack;
   SPX_HEADER *replyHeader;
   BYTE *replyPtr;

   while ( !foundECB )
   {
      // wait for there to be a packet in the queue
      while ( !diagQueue.qHead && !exitProgram )
      {
         IpxRelinquishControl();
         CheckTerm();

         // might want to put a time out in here
      }

      // we have one, get it and check it
      comeBack = (SPX_ECB *)diagQueue.qHead;
      Dequeue((QElemPtr)comeBack,&diagQueue);

      replyHeader = (SPX_HEADER *)comeBack->fragList[0].fragAddress;
      replyPtr = comeBack->fragList[1].fragAddress;

      if ( replyHeader->destConnectID == connectionID )
      {
         if ( comeBack->status == 0x3000 )
         {
            returnCode = NO_ERRORS;
            memcpy(buffer1,replyPtr,size1);
            memcpy(buffer2,replyPtr+size1,size2);
         }
         else
            returnCode = RECEIVED_REPLY_IN_ERROR;

         foundECB = TRUE;
      } // END - if this was our packet
   } // END - while !found

   if ( exitProgram )
      return DX_ABORTED;

   SpxListenForConnectionPacket(connectionID,comeBack);
   return returnCode;
} // END - GetDiagnosticResponse

END of FIGURE 1

Porting Issues

Differences in definitions may cause problems for those familiar with programming in the DOS environment or porting applications from DOS to Macintosh. These include definitions for structures, return codes, and formal parameters, as well as the inclusion and exclusion of certain APIs.

The ECB is the structure whose fields contain information necessary to send IPX or SPX packets; it is used in almost every IPX/SPX API. The ECB structure member names and functionality vary across the client platforms. The DOS structure, for example, contains an inUse field and a completionCode field; inUse indicates what is happening to the ECB while in use by the transport, and completionCode is the ECB function result. MacIPX combines the functions of these two fields into the status field.

The Mac ECB contains a number of new fields that are not available on other platforms. The MacOSQueue field is a OS defined variable type that can be used to link incoming ECBs for future processing. The savedA5 field gives the application's ESR (Event Service Routine, an interrupt process used to handle incoming ECBs) access to global data.

It is always a good practice to check the API return codes and ECB completion codes. Defining codes in header files to account for the difference between the environments prevents conflict when developing across platforms. For example, a returnCode of 0 (zero) usually means that an API call is successful. On DOS platforms, 0 also implies a successful IPX or SPX request. DOS completionCodes are one-byte (e.g., 0xFC for event canceled). On the Mac, ECB status fields are two bytes long. This field is set to 0x0000 for a successful IPX request and to 0x3000 for a successful SPX request. In the event of failures, codes similar to DOS failures are in the low order byte (i.e., a canceled event will contain 0x90FC in the ECB status field).

As stated previously, using #define statements in your header files accounts for most of these differences without having to make modifications to the code. The Resource Manager uses an include file, DIAG.H, which incorporates these definitions.

"Timer tick" is another conditional definition in DIAG.H. IPXScheduleIPXEvent() expects a tick equal to 1/60 of a second, based on the vertical retrace interval built into the video circuitry. Under DOS, a tick is approximately 1/18 of a second, so defined to maintain compatibility with the time circuit design of the original IBMPC. Since the Macintosh uses a different architecture, you may expect such a difference in a hardware-specific definition. Some MacIPX APIs return ticks values in terms of 1/18 seconds (e.g., IPXGetLocalTarget()). These functions usually return time values from requests made to IBM-compatible machines.

The DOS Diagnostic Services use some APIs that are not included with the MacIPX SDK. One missing API is IPXGetIntervalMarker(), which is sometimes used to check for "time out." On the Mac, a good replacement is to use the clock() ANSI C function or the TickCount() OS API. Figure 2 compares the use of these functions.

FIGURE 2: Comparison of IPXGetIntervalMarker() & clock()

DOS Method:

   startTicks = IPXGetIntervalMarker();
   while( IPXRecvECB.inUseFlag )
   {
      IPXRelinquishControl();
      endTicks = IPXGetIntervalMarker();
      if( endTicks - startTicks > 72 )
         break;
   }
   ...

Macintosh Method:

   startTicks = clock();
   while ( !recvQueue.qHead )
   {
      IpxRelinquishControl();
      endTicks = clock();
      if ( endTicks - startTicks > 72 )
      {
         ErrorCode = REMOTE_TIMEOUT;
         break;
      }
   }
   ...

END of FIGURE 2
Another missing API is IPXScheduleSpecialEvent(), a specialized form of IPXScheduleIPXEvent() that does not require an open socket to act upon. In DOS, the special event API triggers a timer for the timing functions. The Manager code uses the clock() function, but IPXScheduleIPXEvent() could also have been used with a temporary socket.

Mac Advantages & Caveats

Programming with the MacIPX SDK offers some definite benefits. For example, the use of the Macintosh OS object, MacOSQueue, inside the ECBs is useful for testing if packets have been received or to check packet order. There is one disadvantage that is particularly evident when using MacIPX to communicate with a non-Mac target: DOS machines return information in structures with members aligned on odd-byte boundaries, but Mac compilers do not offer options to handle packing structures.

Packed structures are used throughout NetWare since they increase transmission efficiency by eliminating pad data on the wire. Think C and the Macintosh Programmer's Workshop (MPW) do not support packed structures and will align any non-byte member on a word boundary. Thus, if you create your structures to duplicate those defined in the NetWare System Interface Technical Overview, you may discover that the information returned in packets, when overlaid on this structure, becomes unrecognizable.

There are a couple of ways to resolve this dilemma. The first method requires you to code your structure access in Assembly language. For a lighter approach, you could use a method similar to the one shown in Figure 3.

FIGURE 3: Macintosh packed data structure method

From DIAG.H

#define getShort(a) (*(unsigned short *)a)
#define getLong(a) (*(unsigned long *)a)
#define getPtr(a) (*(unsigned long *)a)
#define getStruct(a,t) (*(t *)a)

typedef struct StructAllResp {
   BYTE completionCode; // PAD
// long intervalMarker;
   BYTE intervalMarker[4];
} AllResponseData;

#define SIZE_AllResponseData 5

typedef struct StructAddressTable {
   BYTE serverUsed;
   BYTE orderNumber;
   BYTE serverNetwork[4];
   BYTE serverNode[6];
   WORD serverSocket;
   WORD receivedTimeOut;
   BYTE immediateNode[6];
   BYTE sequenceNumber;
   BYTE connectionNumber;
   BYTE connectionOK; // PAD
// WORD maximumTimeOut;
   BYTE maximumTimeOut[2];
   BYTE reserved[5];
} AddressTableStruct;

#define SIZE_AddressTableStruct 32

END of FIGURE 3
In instances where the next structure member is of even size and should start on an odd-byte boundary, the member is defined as an array of BYTES, which the Think compiler will not pad, and then cast into the appropriate type when accessed for data. Macintoshes will allow this approach since, unlike DOS machines, there is no reverse-byte ordering with which to contend. Figure 3 also contains the macros used to access these members; for example, getShort() retrieves a short integer from a two-byte member.

DOS programmers frequently check for incoming packets by testing the ECBs that have been posted for listens to see if they are still in use. Typically, this looks like a program loop through all of the posted ECBs (in Diagnostics there are four) with an if() test and a break. With Macs, there is a much cleaner way: as part of the program initialization, declare a Qhdr structure as a global variable, and assign a pointer to this structure in each ECB. When packets arrive, MacIPX will enqueue them on this OS queue. Then, to check for a packet, test the QHdr element that points to the head of the list to see if any ECBs have come back. For cross platform portability, you may still use the ECB.inUse method, if desired. Figure 4 compares the two methods.

FIGURE 4: Comparing use of ECB field and OS Queue Checking ECB.inUse: int ECBPtr; int returnCode; for (ECBPtr=0; ECBPtrfragList[0].fragAddress; if ( replyHeader->destConnectID == connectionID ) returnCode = TRUE; } END of FIGURE 4

Future Enhancements

The Resource Manager is a useful utility in its present form, and it thoroughly exercises the diagnostic services. However, there is still room for improvement: the Resource Manager could be enhanced to make use of other areas of IPX/SPX transport service and overall useability. A few enhancements on both the requester side and the respondent side have already been mentioned and are summarized briefly here. Look for Part Two of this article in a future issue of Bullets, which will discuss adding this functionality using the NLM SDK and the NetWare Client SDK.

Server Support

Additional server, or requester, support can include the ability to target respondents with a network object name rather than an IPX address. As documented earlier, MacIPX cannot lookup user objects in the bindery (though the NetWare C Interface for Macintosh provides this functionality), MacIPX does contain full SPX support, however, and can use SPX to communicate with other server applications that have access to user objects.

Object name lookup capability will be added to v2.0 of the Resource Manager through the use of an NLM. The basic design is as follows: The NLM will load and advertise on a private socket. When the Manager needs to find the available responders, it will issue a Service Query through the SAP API QueryServices() to find the NLM. It will then send a bindery lookup request to the NLM via SPX, which will in turn return a list of connected objects and their IPX address. The Network Manager will display this list of object names (rather than the list of addresses) at the Target Broadcast menu option. The administrator will select a user, and the program will use its corresponding IPX address to initiate a diagnostic session.

Client Support

Version 2.0 of the Resource Manager will include enhanced responder functionality. Network administrators may want to determine more information about a particular workstation than just its connectivity components. Using the same methodology as the diagnostic support, you can query a target for its hardware configuration and even its storage contents through the use of responder applications resident on each machine.

The Diagnostics menu option will query these expanded responders. If the expanded responder is not installed for that target, the menu option will be "grayed out" and unavailable. Behind the scenes, the requester will issue a DiagHardwareConfig() request on a well known socket to the desired target. No response will signify that the responder is not present.

The expanded responders will have slightly different architectures based on the machine type on which they are resident. Machines running the DOS and Windows operating systems will use TSRs that will load as part of the startup process and open a well known socket upon which to receive SPX DiagHardwareConfig() requests. The same functionality will apply to OS/2 machines and other Macs except that they will use daemons and INITs, which require different application generation techniques.

When the expanded responders receive a request on their socket they will issue the appropriate OS APIs (OS/2 and Macs) or interrupts (DOS) to gather the available information and send it back in sequenced SPX packets to the requester.

The MacIPX SDK provides comprehensive support of the IPX/SPX transport protocol on NetWare. It is easy to use for both the experienced Mac programmer and novice alike. The documentation provides sufficient information on the transport concepts so that you could readily use this tool to begin your NetWare programming experience.

IPX and SPX are the building blocks for NetWare-compatible applications. This article has discussed using this protocol to add significant functionality to Mac applications by writing diagnostic APIs using MacIPX. You can write your own using these techniques, or if you prefer, the source code for the APIs is available in the file MACDIAG.SIT. The Resource Manager is contained in MACNRM.SIT. Both files are available on Novell's NDEVREL CompuServe forum (section 9) and Applelink (Support, 3rd Parties). These files are provided as is and thus are not supported by Novell. If you have questions on using the MacIPX SDK, contact Novell Developer Support.

NLM SDK v3.0: New Features for NLM Developers

In July, Novell began shipping the NLM SDK v3.0. The article discusses new features available in this SDK.

Support for NetWare 3.x and 4.x

This SDK provides the tools necessary for developing both NetWare 3.x and 4.x NLMs. Previously, Novell offered the Network C for NLMs SDK for developing NetWare 3.x NLMs, and the NLM SDK for NetWare 4.0 for developing 4.x NLMs.

AppleTalk SDK for NLMs Added

With this release of the NLM SDK, the NetWare 4.0 Interface for AppleTalk for NLMs SDK has been incorporated into the NLM SDK. This interface allows you to create NLMs that communicate with an AppleTalk client, such as a Mac. This SDK provides a full set of interfaces that allow you to access these AppleTalk protocols:
  • AppleTalk Data Stream Protocol (ADSP)
  • AppleTalk Echo Protocol (AEP)
  • AppleTalk Session Protocol (ASP)
  • AppleTalk Transaction Protocol (ATP)
  • Datagram Delivery Protocol (DDP)
  • Name Binding Protocol (NBP)
  • Printer Access Protocol (PAP)
  • Zone Information Protocol (ZIP)
This SDK enables NLMs developers to access the AppleTalk protocol stack using either TLI or native NetWare AppleTalk C function calls. In the AppleTalk protocol stack, TLI provides access to DDP and ADSP. Through a single procedural interface (TLI), NLMs can access multiple protocols, such as AppleTalk, TCP/IP, and IPX/SPX. To develop applications using the NetWare 4.0 Interface for AppleTalk for NLMs SDK you must have NetWare 4.0 and

NetWare for Macintosh 4.0.

WATCOM C/386 v9.01 & C/C++32 v9.5 Compiler Support Beginning with the NLM SDK v3.0, support is provided for WATCOM 386 v8.5 through v9.5 compilers (the compiler is not included). Support is now provided for C++ NLM development using the WATCOM C/C++32 compiler.

NDebug Source Level Debugger Added

NDebug provides the ability to do source level debugging, similar to WATCOM's VIDEO debugger. NDebug supports both local and remote debugging. (Source code must be placed on the DOS partition of the debug server when performing NLM hosted (local) debugging.) The NDebug utilities that extract debug information from the load modules do not support the WATCOM v9.5 compiler at this time.

NLM SDK Install Utility Updated

The Install utility has undergone three major changes. First, the utility now uses an ASCII file INSTALL.LST. This file contains the information needed by the Install utility to identify the various subsystems and file specifications that need to be installed.

Second, the /NovellNet switch has been changed to simply /NetWare. This switch is used to install the SDK from a network directory conforming to the SDK staging area. The switch could install the SDK directly from a network directory structure such as:

/PATH/1 - contents of disk 1
/PATH/2 - contents of disk 2
/PATH/n - contents of disk n

Third, MAKEINIT has undergone several changes:

  • It now includes $(appletlk), a new macro that supports the AppleTalk APIs in a manner similar to how other API subsets are handled.
  • The $(startup) macro is undefined if the WATCOM tools v9.5 are detected.
  • The OS/2 tool support has been withdrawn, but will be added in a subsequent release.
  • Depending on which compiler version is installed, the real mode/protected mode macro definitions are different.
If the Install utility is unable to detect the compiler version, the values defined for the macros $(watdrive) and $(wat386loc) will be incorrect. In this case, you should edit the MAKEINIT file to reflect the correct values for these macros before attempting to rebuild examples or projects using MAKEFILE's created by QMK386.

For more information on the NLM SDK v3.0, contact Novell Developer Support at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588. You must be a member of the Professional Developers' Program to purchase the NLM SDK v3.0.

Using WATCOM's C/C++32 Compiler to Create NLMs

In June, WATCOM began shipping their C/C++32 v9.5 compiler, which includes support for NetWare 3.x and 4.x platforms. This article discusses some development issues you may encounter using the new compiler.

Using the New Compiler Without Utilizing C++ Features

You may be one of the developers who simply upgrades to the latest tool offering from WATCOM, but do not need to use the C++ features. In this case, you can create NLMs that rely entirely on the CLIB Runtime Library NLM and use the tools the same way as before.

However, be aware that if the NLM SDK Install utility detects the WATCOM C/C++32 9.5 compiler, it will install under the assumption that you are using the WATCOM static library (which is required for C++ NLM development). Specifically, it will define the $(startup) macro to expand to nothing, which will cause the linker to get the $(startup) code from WATCOM's CLIB3S. If you need to use the WATCOM v9.5 compiler under the same environment that you had with the WATCOM v9.01 compiler, you need to perform one of the following two steps:

  • Install the NLM SDK v3.0 in a location other than where the WATCOM C/C++32 compiler was installed. The NLM Install utility will prompt you for the WATCOM compiler version. Choose WATCOM C/386 instead of WATCOM C/C++32. Also, be sure to correct the path specifications for $(watdrive) and $(wat386loc) in MAKEINIT.
  • OR
  • Before running the NLM SDK Install utility, rename the NOVH subdirectory (created by the WATCOM Installation utility) to "WATNOVH", and the Novell header files will be copied into the NOVH subdirectory. Define the $(startup) macro to point to the PRELUDE.OBJ file supplied by Novell (in the NOVI directory). This file will be copied to the NOVI directory regardless of the compiler version detected.

You may also want to prevent accidental linking of the CLIB3S.LIB file by adding the "option nod" linker directive to any link files or you can use the "/zl" compiler switch to prevent the compiler from putting default library names into the object modules. This step is not required, but it might prevent you from accidentally linking the CLIB3S.LIB file.

In addition, do not use the "/BT" switch with WCC386, or the compiler will place a reference to __WATCOM_prelude in the object, which will cause errors during the link phase (unless of course the undefsok option is specified).

Using the New Compiler Utilizing C++ Features

If you need C++ for your NLMs, you will need to do the following:
  • Link in CLIB3S.LIB. It provides the base support necessary for the C++ class libraries.
  • Use the System NetWare option of WLINK. This option will ensure that the correct libraries are linked into your load module. Do not use the PRELUDE.OBJ provided by Novell or the C++ support will not work.

Using the WATCOM Compile & Link Utility to Create NLMs

Now you can use WATCOM's compile and link command-line utility to create NLMs. Assuming your path specifies the binary directories, and the INCLUDE and WATCOM environment variables have been set, the command to compile and link the "Hello World" C example program is:

WCL386 /BT=NetWare /L=NetWare HELLO.C

The "/BT" (Build Target) switch is used by WCC386 to establish the default compiler switches required to build NLMs. Specifically, it establishes the following defaults for WCC386:

/3s Use stack-based parameter passing
/ms Use the small memory model (required so CS: overrides are used when referencing constants, stored in code segment.)

Also, "/BT" causes WCC386 to generate a reference to __WATCOM_Prelude, to ensure that WATCOM's version of PRELUDE.OBJ is used. Thus, if you choose not to use the WATCOM static libraries, do not use the "/BT" switch with WCC386.

The "/L" switch instructs WLINK to use the System NetWare defaults, which specifies items like linking with the proper WATCOM static libraries.

You can also set INC386 (or INCLUDE) and LIB386 to specify search locations for the WATCOM tools; however, LIB386 won't help the linker find the NOVI path, thus import files would require full path specifications. QMK386 uses full path specifications currently, along with INC386 and LIB386, but the next version (v2.20) will set the INCLUDE and WATCOM environment variables.

IMPORTANT: If you use "/ms" to force the code generator to include CS: overrides when accessing constants in the code segment, be aware of the following issue. 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 thru 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 appears to work, but may not be the optimal solution for all developers.

Using the WATCOM CLIB3S.LIB

In order to create a C++ NLM, you must use the WATCOM static library CLIB3S.LIB in addition to any other specific C++ class libraries, also provided by WATCOM. Without these libraries, C++ features are not available to NLM developers. WATCOM requires some additional instance data in the thread package and CLIB3S.LIB handles allocating and releasing these resources without any intervention from the NLM developer.

To clean up all the resources allocated by the static library, WATCOM registers an atexit() routine during startup. Therefore, only 31 additional atexit() routines may be registered by NLM developers when using the static libraries. In addition, if an NLM aborts via the abort() API some resources will not be cleaned up, including local semaphones which will result in a server abend.

(WATCOM offers a fix that will remedy the abort() problem by not using system semaphores. See "Patch for NetWare Developers" below for details.) Only Protected-Mode Compiler & Linker Tools Available Previous versions of the WATCOM C compiler provided both real mode and protected mode versions of the compiler and linker tools. However, WATCOM C/C++32 v9.5 only provides protected mode versions of these tools. Note that WCC386P.EXE and WLINKP.EXE are still included in the BIN directory. These tools are simply stub utilities which spawn WCC386 and WLINK respectively.

Source-Level Debugging for NetWare 4.0 Available

As with prior versions of the compiler, WATCOM includes full source-level debugging support with their latest toolkit. New with v9.5 of the compiler is support for source-level debugging on NetWare. All source-level debugging is performed remotely, via serial, parallel, or network (SPX) communications.

NLM Headers and Imports

WATCOM now ships the Novell NLM Header and Import files, allowing developers to build NLMs without the requirement for the Novell NLM SDK. However, since no API documentation or other value-added tools are provided, any serious NLM development still requires the purchase of the NLM SDK.

There are a few differences between the WATCOM NLM headers and the Novell NLM headers. The most notable difference is the standard C FILE structure. In order to provide support for implementing C++ I/O support for NLMs, WATCOM required a substantial number of changes be made to the FILE structure. Novell was unable to incorporate all of these changes into the current CLIB implementation on NetWare 3.x and 4.x, so WATCOM created a static library which sits on top of the CLIB Runtime Library NLMs.

If you choose to build NLMs that do not rely on CLIB3S, be sure to install Novell's NLM header files from the NLM SDK.

Patch for NetWare Developers

Novell added the AppleTalk API support header files and import file after WATCOM had created the master diskettes for the WATCOM C/C++32 compiler. In addition, there are several known bugs with v9.5 that are fixed in a patch offered to NetWare developers:
  • You cannot debug multi-threaded NLMs.
  • beginthread() has a race condition that could cause memory problems.
  • You cannot restart or kill an NLM in the debugger because CLIB3S uses semaphores. The debugger uses _exit() to kill the NLM but this does not free semaphores.
  • The export statement in the linker does not work.
  • CLIB3S keeps pointers to memory and semaphores in its file structures. If a thread from another NLM is the cause of the memory allocation, this memory is attributed to that NLM, not the one keeping the static pointer.
The patch for NetWare developers is available on CompuServe on Novell's NDEVREL forum (Library 1, WAT95P.ZIP). It can be downloaded from WATCOM's BBS service at 1-519-884-2103.

For more information on the NLM SDK v3.0 which includes support for the WATCOM C/C++32 compiler, contact Novell at 1- 800-NETWARE (1-800-638-9273) or 1-801-429-5588. You must be a member of the Professional Developers' Program to purchase the NLM SDK v3.0.


DEVELOPER NEWS:

Novell Announces AppWare

In June, Novell announced AppWare, a new layer of software that leverages today's popular operating systems, development tools, and applications.

Developers who create network applications must deal with the growing number of operating systems, development APIs, computing standards, and development toolkits available today. AppWare hides these complexities from developers by providing them with one uniform set of APIs for accessing different operating systems, graphical user interfaces (GUIs), and network services. In the AppWare environment, developers can write the application code once and run the application on different operating systems and networks.

AppWare: What Problems Does It Address?

On average, one major new operating system or service API is delivered to developers every 45 days. This rapid pace makes it virtually impossible for application developers to keep up with emerging technologies. Resource constraints force developers to choose among the available alternatives. Often developers can only afford to focus on one platform or operating system, limiting the markets and users that their products can address. AppWare provides solutions for the following problems:
  • Multiple Networking Models - application developers are currently faced with an unprecedented need for network access and functionality. Developers must contend with a variety of network models to deliver the services and data their users require.
  • Multiple Desktop Platforms - Developers must learn all the details of the desktop platforms on which their applications run. For example, if a developer had to write a million lines of C code to create an application for MS-Windows, that developer would likely have to rewrite that code for each platform on which the application will run such as Macintosh, Unix, or OS/2.
  • Inefficiency of Network Application Development Tools - Traditional application development required writing code from scratch using third generation languages (3GLs) such as C or C++. Typically, this method of application development is used by horizontal application vendors who work on multi-million dollar projects that can take years to complete. Corporate and vertical software developers, however, can no longer afford to create applications using this method. The industry has reached a point where developers are demanding more effective tools than are available today.

The AppWare Solution

AppWare is not an operating system or an application. AppWare is a new layer of software that provides two components of technology that address the problems created by multiple networking models and multiple desktop platforms: the AppWare Foundation and the AppWare Bus.

The AppWare Foundation insulates programmers from the growing complexities of multiple operating systems, GUIs, and networks. AppWare does not replace existing operations systems, GUIs, and network services; rather it leverages, unifies, and improves them.

The second AppWare component, the AppWare Bus, is a software engine that provides large-grained, interchangeable software modules that corporate and vertical developers can use and reuse to quickly construct new network applications, without having to write code. These software components, called AppWare Loadable Modules (ALMs), provide access to the functionality provided by both local operating systems and network services.

The AppWare Bus and ALMs are the software equivalent of the PC mother board and interchangeable plug-in cards. When ALMs are plugged into the AppWare Bus, their functionality becomes rapidly accessible for building new applications, and third parties can offer their technology in the form of new ALMs. Business application developers will be able to create new applications quickly and easily by linking different ALMs.

Developers will use one set of APIs to build ALMs. Applications written on top of the AppWare Foundations API set are simply recompiled to run on DOS, MS Windows, Windows NT, OS/2, UnixWare, and the Macintosh desktops, as well as NetWare and UnixWare servers.

Novell intends to work with developers, development vendors, operating system suppliers, and other third parties to make AppWare a standard for network application development. Novell has already created basic and network ALMs, and is actively working with a number of ISVs to provide additional ALMs. For example, Cheyenne Software is creating ALMs for imaging and document management. Various third parties have already built ALMs for accessing Oracle and Sybase databases.

AppWare will remain open and extendible and will incorporate important development and interface standards. Therefore, AppWare will be welcomed into companies that want to protect themselves from the vagaries of proprietary system components.

Visual AppBuilder: 5GL Application Development Tool

Visual AppBuilder provides a 5GL-level development environment, and is tightly integrated into the AppWare environment. Visual AppBuilder allows applications to be constructed by selecting and manipulating on-screen icons that represent different ALMs. Developers use on-screen links to create application logic, thereby providing for rapid development of network applications.

Visual AppBuilder is designed for programmers unfamiliar with the details of 3GL development. The range of applications developers can create is limited only by the range of ALMs provided by Novell and third parties. Visual AppBuilder is ideal for corporate and vertical business application developers.

For example, consider a developer who wants to provide an easy-to-use automated telephone directory system for a global corporation. The directory information is stored in an Oracle database, and the users of this program are non-technical so it should have a slick multimedia front end. In addition, the available hardware offers automatic answer and dialing through the telephony services on the network.

Using a 3GL tool, such an application might take years to complete. With Visual AppBuilder, a developer would simply use on-screen graphic icons to connect the Oracle database ALM, the multimedia ALMs, and the telephony ALM to create the new application. By avoiding traditional line-by-line hand coding, the application could be created quickly. Also, since it is built on the AppWare foundation, the application could be quickly ported to any common operating system or network.

Integration with Other Third-Party Development Tools

For procedural developers, ALMs can be built using 3GLs and the AppWare Foundation. ALMs can be created with almost any compiler including Microsoft, Borland, Symantec, LightSpeed, SABER, GNU, and MPW compiler. Debugger support includes Multiscope, CodeView, and SADE debuggers.

For Additional Information

More information on AppWare is available through the Novell Developer Relations Automated Fax System. Call 1-512-794-1799 and request document 2900 (AppWare press release). To order white papers on AppWare, Visual AppBuilder, and AppWare Architecture, request document 2905 (AppWare white paper order form).

Novell Announces Vertical Application Developer Services

To provide the technical and marketing assistance required by vertical application developers, Novell offers the Vertical Application Developer Services. Membership is reserved for developers writing or providing industry-specific applications and solutions to the various vertical markets, such as finance, legal, manufacturing, retail, and others.

Vertical application developers gain access to these services through a fee-based subscription. In addition, Vertical Developer Services subscribers get all the same benefits that member of the Novell Professional Developers' Program and the Univel Developers' Programs receive.

Technical Assistance

Novell Vertical Application Developer Services offers the following technical assistance for your development efforts in the vertical marketplace:
  • One Year License to the NetWare Operating System - with each annual subscription, members receive a free one- year subscription to the NetWare or UnixWare OS of their choice.
  • Priority Developer Support - receive priority access to high-level support without going through the basic channels.
  • NDEVREL - a forum on CompuServe that allows vertical developers to share information privately and communicate with Novell and Univel staff.
  • BrainShare Conference - receive a 10% discount.
  • Ongoing Information Updates - receive a technical newsletter, as well as mailings and updates specific to their industry or market.
  • API Special Interest Group - participate in the Novell Compass Program, a roundtable format in which developers and Novell engineers discuss future API direction.
  • Developer Services Advisory Council - join Novell staff and other vertical developers to periodically discuss vertical industry application challenges.
  • Development Technology Lab - the Novell Developer Relations Technologies Engineering Lab is available to subscribers needing one-on-one engineering assistance.
  • DeveloperNet Labs Certification - subscribers receive a 15% discount. Marketing Support
  • Directory Listings - gain product exposure through the Yes, It Runs With NetWare Resource Guide; the Yes, It Runs With UnixWare Resource Guide, and the NetWire CompuServe forum.
  • Sales Leads & Assistance - Corporate-sponsored events and the resulting leads can be sent to subscribers as appropriate. Controlled mailing list access to the Novell reseller channel is granted on a case-by-case basis, and the NetWare Users International (NUI) mailing list is available.
  • Evaluation Copies - Subscribers can send evaluation or demo copies of their applications to Novell field sales offices for valuable application input.

Sign Up Now

Complete a subscription form and return it with your $495 annual subscription fee to Novell Vertical Application Developer Services. Subscription forms are available through Novell's Automated Fax System at 1-512-794-1799, and in the Developer Program Information section on the main NetWire menu on CompuServe.

New Releases of Novell Development Tools

NetWare for SAA Tools v1.0

Description:

Incorporates the functionality of NetWare 3270 Tools, NetWare for SAA LU6.2 Tools, & NetWare Open NetView SDK (which lets you build apps that send alerts to the IBM NetView console and respond to RUNCMDs from the NetView console).

Products Replaced:

  • NetWare 3270 Tools v2.0
  • NetWare for SAA LU6.2 Tools v1.4
  • NetWare Open NetView SDK v1.0
Upgrade Path?

No, but existing customers with replaced products will continue to receive individual product updates.

Available: Now

Part Number: 884-000081-001

LAN WorkShop v1.1a

Description:

Incorporates the functionality of the LAN WorkPlace Toolkits for DOS, Windows, OS/2 and Macintosh, as well as NetWare TIRPC for DOS, Windows and NLMs Toolkits.

Products Replaced:

  • LAN WorkPlace for DOS Toolkit v4.1
  • LAN WorkPlace for OS/2 Toolkit v3.0
  • LAN WorkPlace for MAC Toolkit v1.3
  • NetWare TIRPC for DOS, Windows & NLMs Toolkit v1.3
Upgrade Path?

Yes, all owners of replaced products will be updated with the LAN WorkShop v1.1a.

Available: Now

Part Number: 884-000061-002

NLM SDK v3.0

Description:

Provides the tools needed for developing NetWare 3.x and 4.x NLMs, as well as NLMs that can communicate with an AppleTalk client. Products Replaced:

  • Network C for NLMs
  • NLM SDK for NetWare 4.0
  • NetWare 4.0 Interface for AppleTalk for NLMs SDK
  • NetWare 3.x Interface for NLMs SDK
Upgrade Path?

Yes, all owners of replaced products will be updated with the NLM SDK v3.0.

Available: Now

Part Number:884-000090-001

NetWare Client SDK v1.0e

Description:

Provides a single interface for writing DOS, DR-DOS, OS/2, and Microsoft Windows applications that directly access the core services of NetWare 2.x, 3.x & 4.x via a comprehensive library of client APIs.

Products Replaced:

  • NetWare System Calls for DOS
  • NetWare C Interface for DOS
  • NetWare C Interface for Windows
  • NetWare OS/2 Developer's Kit
Upgrade Path?

If you purchased product before Sept. 12, 1993, you can purchase at a discount with proof of purchase. If you purchased products after 9/12/93, new product is free until 8/30/93.

Available: Now

Part Number: 884-000031-006


TECHNICAL INSIGHTS:

Using Microsoft Access with Btrieve (Btrieve for Windows v5.10)

This Technical Insight describes the most common issues Btrieve users encounter while using Microsoft Access to access Btrieve data files.

The Data Dictionary

Microsoft Access can access (read or modify) a Btrieve file only through that file's data dictionary. A data dictionary is a set of files that define fields for each record of a Btrieve file. To produce the data dictionary files (DDFs) for a Btrieve file, you must know the starting offset, length, and type of each portion of a file's records that corresponds to a field. You can then use NetWare SQL, Xtrieve PLUS, or a similar product to define the DDFs for that Btrieve file. Access cannot create DDFs for a Btrieve file.

File Owner Names

Access opens DDFs with the Novell default DDF owner name; therefore, if security is defined on a set of DDFs, Access cannot read the DDFs. In this situation, Access returns the error Couldn't Decrypt File.

If a Btrieve file has an owner name, but does not require you to specify the name in order to read the file (level 1 or 3), Access does not prompt you for the owner name. Although Access can read the data from the file, attempting to edit the file's data causes Access to return the following error: "Couldn't update; database is read-only."

If a Btrieve file has an owner name, and that file requires that you specify the owner name in order to read or modify the file (level 0 or 2), Access prompts you for the owner name. If you are using Btrieve v5.x, Access opens the file for normal use after you specify the owner name. However, if you are using Btrieve v6.x, Access cannot open the file even after you specify the owner name. Instead, it returns the error, "Couldn't Decrypt File." This error occurs because Btrieve v6.x requires that the data buffer length be set to the length of the owner name plus the null terminator on an Open operation. Access sets the data buffer length only to the length of the owner name.

Tables and the Btrieve File Format

Access can create a Btrieve file and define it to a set of DDFs that have been previously defined by Xtrieve PLUS, NetWare SQL, or a similar application. Access refers to this action as exporting a table in Btrieve format.

When exporting a table in Btrieve format, Access always adds the four-byte integer field "M_I_C_R_O_S_O_F_T" as the first field of the table. Access also makes this field the only index in the table.

Access translates its own data types into specific Btrieve data types when it exports a table in Btrieve format. The list in Figure 5 shows the data types that result when Access exports data to a Btrieve DDF file.

FIGURE 5: Resulting data types when Microsoft Access exports data to a Btrieve DDF file

Access Data Type         DDF Data Type

Text                     string
Number                   float
Date/Time                date
Currency                 money
Counter                  integer
Yes/No                   logical
Memo                     note
OLE Object                    lvar

END of FIGURE 5
You can use Access to read a Btrieve file's format from one set of DDFs and then export the table for that Btrieve file to another set of DDFs. You can also use Access to join, query, or update the tables for Btrieve files that are defined in different sets of DDFs.

Access allows you to join Btrieve-based tables to tables that use other formats (such as Access, Paradox, or dBASE IV). However, you cannot export data from such a joined view or restricted query to a Btrieve file. You can export only single unrestricted tables to Btrieve format.

Transaction Processing

Access operations occur mainly inside transactions; therefore, you must configure Btrieve for transaction processing.

Btrieve for Windows

WBTRCALL.DLL, the Btrieve for Windows DLL, is no longer packaged with Access. You can purchase this DLL from Novell in the Btrieve for Windows Developer's Kit. The Requester version of this DLL is available from CompuServe in the NOVLIB forum (Library 7, BTRREQ.ZIP). You can use this Requester with Access to access Btrieve files that reside on a NetWare v2.x, v3.x, or v4.0 server running the Btrieve engine. For information about how to install the Btrieve engine packaged with your version of NetWare, see the Btrieve Installation and Operation manual included in the NetWare documentation.

Access returns error -5001 if you are using the Btrieve v6.x Requester and WBTRVRES.DLL is not available in your path. Access also returns error -5001 whenever it receives a Btrieve status code that it has not been programmed to handle. Most of these Btrieve status codes are greater than 90.

Access can also return the error Disk or Network Error. This error occurs if Access tries to read a Btrieve file's associated DDFs using a pre-v6.x version of WBTRCALL.DLL, but the DDFs have been created by Xtrieve PLUS, NetWare SQL, or other application that used Btrieve v6.x to create those DDFs. This error resembles Btrieve Status Code 2, which Btrieve returns when an application attempts to access a v6.x-formatted file with a client (v5.x) engine. To solve this problem, either run the Btrieve v6.x NLM with the v6.x version of BREQUEST or WBTRCALL.DLL, or make sure all files accessed with the client WBTRCALL.DLL are stored in v5.x format.

AdvertiseService() & QueryService() Socket Numbers (NetWare Client SDK v1.00d)

AdvertiseService() in the NetWare Client SDK, advertises successfully, but the socket number is swapped. This situation does not occur with the NetWare C Interface for DOS or the NetWare C Interface for Windows.

You must use NWWordSwap() on the socket, which is returned by QueryService() or BinderyScan(), prior to its direct use in ECBs or other APIs.

Calling Btrieve from 32-bit Applications (Btrieve for OS/2 v5.10)

The current Btrieve for OS/2 engine, v5.10, is a 16-bit DLL. In order to access this DLL from a 32-bit OS/2 application, the Btrieve entry points have to be "thunked." Some aspects of this process depend on which compiler you use. Figure 6 illustrates the process when using Borland's 32-bit OS/2 compiler. Figure 7 demonstrates the process for IBM's C-Set/2 OS/2 compiler.

FIGURE 6: "Thunking" Btrieve entry points with Borland's 32-bit OS/2 compiler

#include 
#include 
#include 

#define FPSZ char __far16 *  /* Far pointer to null-terminated string */
#define FPUSHORT USHORT __far16 *    /* Far pointer to unsigned short */

extern USHORT __far16 __pascal BRQSHELLINIT (FPSZ);
extern USHORT __far16 __pascal BTRVINIT (FPSZ);
extern USHORT __far16 __pascal BTRVSTOP (void);
extern USHORT __far16 __pascal BTRCALL (USHORT, FPSZ, FPSZ,
                                        FPUSHORT, FPSZ, BYTE,
                                        CHAR);

USHORT BTRV (USHORT, PSZ, PSZ, PUSHORT, PSZ, SHORT);

void main() {
.
.
.
}

/* Borland C++ interface to the Btrieve OS/2 dynamic link
library */

USHORT BTRV (USHORT operation, PSZ posblock, PSZ databuf,
             PUSHORT datalen, PSZ keybuf, SHORT keynum)
{

  BYTE keylen = 255;
  CHAR ckeynum = keynum;

  return (BTRCALL (operation, posblock, databuf, datalen,
                   keybuf, keylen, ckeynum));
}

END of FIGURE 6
     FIGURE 7: "Thunking" Btrieve entry points with the C-Set/2 32-bit OS/2 compiler

#include 
#include 
#include 

extern USHORT _Far16 _Pascal BTRCALL (USHORT, PSZ, PSZ,
                                      PUSHORT, PSZ, BYTE,
                                      CHAR);
extern USHORT _Far16 _Pascal BTRVINIT (PSZ);
extern USHORT _Far16 _Pascal BTRVSTOP (void);
extern USHORT _Far16 _Pascal BRQSHELLINIT (PSZ);

USHORT BTRV(USHORT, PSZ, PSZ, PUSHORT, PSZ, SHORT);

main() {
.
.
.
}

/* IBM C-Set/2 interface to Btrieve OS/2 DLL */

USHORT BTRV (USHORT operation, PSZ posblock, PSZ databuf,
SHORT datalen, PSZ keybuf, SHORT keynum)
{

  BYTE keylen = 255;
  CHAR ckeynum = keynum;

  return (BTRCALL (operation, posblock, databuf, datalen,
                   keybuf, keylen, ckeynum));
}

END of FIGURE 7

Loader Cannot Find Symbol (NLM SDK for NetWare 4.0 v1.00b)

When an NLM compiled with NITERROR.H is loaded on a Netware 3.11 file server, the loader cannot find the symbol __get__NWErrno_ptr. With the NLM SDK for Netware 4.0, NITERROR.H defines NetWareErrno as
#define NetwareErrno *__get_NWErrno_ptr()
However, this symbol is not found in CLIB.NLM v.3.11d, so the loader returns an error message. This symbol is actually located in CLIB.NLM v.4.0.

To make the NLM load under CLIB.NLM v.311d, either compile the NLM with the version of NITERROR.H provided with the Network C for NLMs v.2.0e, or modify the NITERROR.H file from the NLM SDK for Netware 4.0 as shown below.

#define NetwareErrno __get_NWErrno()
The symbol, __get_NWErrno(), is found in both the CLIB.NLM v.3.11d and v.4.0. The only difference between __get_NWErrno() and __get_NWErrno_ptr() is that the latter will let you set NetwareErrno to a value in addition to returning its value whereas __get_NWErrno() only returns the value of NWErrno.

Defining UPPER.ALT ACS with Microsoft PDS BASIC v7.x (Btrieve (all versions))

Using PDS BASIC 7.X, if you want to define an alternate collating sequence to a particular key, then in the Btrieve Create operation, you must allocate 265 bytes at the end of the File Specification structure after all of the file and key specifications variables. The code segment in Figure 8 demonstrates one method for performing this allocation.

FIGURE 8: Defining UPPER.ALT alternate collating sequence with PDS BASIC v7.x

DEFINT A-Z
REM ****  GLOBAL CONSTANTS

Const BCreate       =    14
Const BString       =     0
Const Duplicates    =     1
Const Modifiable    =     2
Const Sequence      =    32
Const ExtendedType  =   256

TYPE KeySpec
         KeyPos      AS INTEGER
         KeyLen      AS INTEGER
         KeyFlags    AS INTEGER
         KeyTot      AS LONG
         KeyType     AS STRING * 1
         Reserved    AS STRING * 5
END TYPE

TYPE FileSpec
         RecLen      AS INTEGER
         PageSize    AS INTEGER
         IndxCnt     AS INTEGER
         NotUsed     AS STRING * 4
         FileFlags   AS INTEGER
         Reserved    AS STRING * 2
         Allocation  AS INTEGER
         KeyBuf      AS KeySpec
         AltColSeq   AS STRING * 265
END TYPE

DIM FileBuf AS FileSpec

FileName$ = "SAMPLE.BTR "
PosBlk$   = SPACE$(128)

REM ************* SET UP FILE SPECS *************

FileBuf.RecLen    = 20
FileBuf.PageSize  = 1024
FileBuf.IndxCnt   = 1
FileBuf.FileFlags = 0

REM ************* SET UP KEY SPECS ***************

FileBuf.KeyBuf(0).KeyPos   =  1
FileBuf.KeyBuf(0).KeyLen   = 20
FileBuf.KeyBuf(0).KeyFlags = ExtendedType + Modifiable + Duplicates + Sequence
FileBuf.KeyBuf(0).KeyType  = MKI$(BString)

REM **** COPY 265 BYTES OF UPPER.ALT TO STRUCTURE VARIABLE

OPEN "UPPER.ALT" FOR BINARY AS #1 LEN = 265
GET #1,1,FileBuf.AltColSeq
CLOSE #1

BufLen = LEN(FileBuf)

CALL BTRVFAR(BCreate, STATUS, PosBlk$, VARPTR(FileBuf),
             VARSEG(FileBuf), BufLen, FileName$, 0)

IF STATUS <> 0 THEN
  PRINT"Error Creating File. Status = ";STATUS%;"
        Press a key to continue"
  DO
  LOOP WHILE INKEY$=""
  END
ELSE
  PRINT"File SAMPLE.BTR Created Successfully!"
END IF
END

END of FIGURE 8

Directory Services & Stack Sizes (NetWare Client SDK v1.00d)

Some Directory Services (DS) functions require up to 6K of stack space. This requirement can cause stack overflows if enough space has not been reserved.

Make sure the stack size is increased when making DS calls. At least an 8K stack is recommended. The stack size may need to be increased if DS calls using RSA encryption are used. Stack size can be increased as a linker option with Microsoft C. The following line is required in the source file when compiling with Borland tools:

unsigned _stklen = 8192;

xFetch Option 5 Documentation Error (NetWare SQL (NLM) 3.00)

The NetWare SQL Relational Primitive xFetch(), option 5, is used to retrieve the record positions of previously fetched records. The NetWare SQL Application Programming Interface manual that comes with the NetWare SQL Developer's Kit v3.00 has a documentation error concerning this option.

According to the manual, when fetching record positions, the lRecordCount parameter should be set to zero. If this is done, xFetch() will return a successful status, but no positions will be returned in the data buffer. To retrieve the position, specify the lRecordCount parameter to be the number of records fetched on the previous xFetch() call.

Truncation of String Type Fields (NetWare SQL (NLM) v3.x)

If a table has a field of type "string" that is 25 characters long and it contains only 20 characters of data and you want to reduce the field size to 20 characters, the following statement must be issued using XQL v2.11:

ALTER TABLE MODIFY char (20).

The statement is successful with XQL v2.11, but NetWare SQL v3.x returns the following status:

Status 850: Data value cannot be converted to new data type

This statement is illegal in NetWare SQL v3.x because it will not truncate a "string" type field in this situation. You should first change all of the strings in the database to fit within the new field size. For example:

UPDATE TABLE1 SET FIELD1 = LEFT(FIELD1, 20)

Then, call NetWare SQL to modify the size of the fields with the ALTER TABLE statement.

BTRIEVE.NLM & ELRDFX.NLM (NetWare Btrieve (NLM) v5.15)

NetWare v3.11 server performance degrades severely or hangs during heavy read/write Btrieve operations. This issue has been resolved with the NetWare patch, ELRDFX.NLM. This patch was previously provided in the NetWare v3.11 patch kit (311PTx), but has been removed to call attention to the fact that if VREPAIR is run while this patch is loaded, data corruption can result. The patch is now available on NetWire in the NSD area (ELRDFX.ZIP).

There is also a third-party companion NLM called ELRDCK.NLM that can be found in NOVLIB, LIB16, in the file ELRDCK.ZIP. If this NLM is loaded, it will issue a warning and sound a beep if there is an attempt to run VREPAIR with ELRDFX loaded.

Improving Disk I/O Speed (Network C for NLMs v2.0(e))

NetWare's "elevator seeking" design optimizes file I/O. For this optimization to work properly, reads and writes must be cached at the server so they can be handled in an orderly manner.

NetWare provides additional functions to NLMs that allow them to handle I/O more immediately, but while these functions provide greater optimization for an application, they can interrupt NetWare's "elevator seeking," thus degrading performance of other applications performing file I/O. These functions are discussed below:

  • Using FEsopen(), with the "write through" bit set, along with AsyncRead() and qwrite() will improve disk I/O performance. The call to AsyncRead() returns a pointer to cache where the retrieved data is located. This pointer is passed to qwrite() to write back to the same cache. I/O speed increases because the application does not have to allocate its own read and write buffers. Data can be flushed to disk using FEFlush().
  • Direct File System (DFS) allows a developer to manipulate data directory on the disk. DFS is not built in to NetWare v3.x, but is inherent in NetWare v4.x. DFS bypasses cache as well as NetWare's "elevator seeking" method for writing to disk. You should only use DFS when the NLM engine is solely responsible for servicing any files that it accesses.
  • According to the documentation, qwrite() is faster than write(). qwrite() is faster because it does not check buffer lengths or syntax like write(). The performance gain is minimal, however.
  • The call to gwrite() allows multiple buffers to be written while write() only handles one buffer. The only other difference between these two calls is that gwrite() does not return until all buffers are written.

Constants for GetPhysicalDiskStats() (NetWare C Interface for DOS v1.20)

According to the documentation, constants for the driveType field in the structure PHYS_DISK_STATS should be defined in NIT.H. However, the constants are not found in NIT.H or any other include files.

Constants for this field are defined as:

PDT_XT                   1
PDT_AT              2
PDT_SCSI            3
PDT_COPROCESSOR          4
PDT_PS2MFM               5
PDT_PS2ESDI              6
PDT_CT_SBIC              7

Field & Table Names in Upper Case (NetWare SQL (NLM) v3.00x)

NetWare SQL (NLM) v3.00 returns field and table names in capital letters if SQL-Level functions like XQLDescribe are used. This situation can interfere with an application written under v2.11 if the application expects field or table names to be case-sensitive, particularly if the it is performing string comparisons.

If you explicitly type field names in a select statement, the names returned by XQLDescribe will be exactly as you typed them in the SQL statement. However, when you type "*" for the field list, if the view contains more than on file, NetWare SQL returns the heading in the format, "filename.fieldname." NetWare SQL v3.0 pulls the filename from an internal structure containing the original file/view/alias name as typed in the SELECT statement.

With all fields selected, NetWare SQL must read the dictionary to get field names. If the filename in the SELECT is in a different case than the field in the dictionary, you would end up with names like "patients.FIRST^NAME" or "PATIENTS.First^Name." So, NetWare SQL converts the names to uppercase to make the file and field names consistent. When there is only one file in the view, NetWare SQL still converts the field name to upper case to make it consistent with the way "*" works with multiple files in the FROM clause.

If you have an alias or view name in the FROM clause (and more than one file in the FROM clause), NetWare SQL v3.0 returns "alias.fieldname" while NetWare SQL v2.11 returns "file.fieldname." For example, with the statement:

SELECT * FROM patients a, appointments b
where a.id = b.id

NetWare SQL v2.11 returns the names as:

Patients.ID Patients.First^Name Patients.Middle^Name
...

NetWare SQL v3.0 returns the names as:

A.ID A.FIRST^NAME A.MIDDLE^NAME ...

If names must be returned in a particular case, enter each field in the SELECT statement the way you would like to see it returned by XQLDescribe. Also, the Primitive level functions such as xDDFile and xDDField will not return the names in capital letters. They will be returned exactly as they were entered into the data dictionary, since these primitive-level functions read the dictionary directly.

Set Directory Operation Fails To Change Drive Btrieve for DOS v5.10a

After a Btrieve Set Directory (17) operation is issued to change the current drive and directory, the current directory is left unchanged.

The Set Directory (17) operation is documented as having the ability to change the current drive and directory at the same time in one call. With all 5.x versions of client Btrieve and all versions of NetWare Btrieve through v6.10, Set Directory does not function as documented. If you attempt to change the drive and directory to a drive and directory other than the current one, a status 0 (Successful) is returned, but the current drive and directory will be left unchanged. The operation functions correctly if there is no attempt to change the current drive, but only the current directory.

To change the current drive and directory with the Set Directory operation, you must call the operation twice. First, issue the function only specifying the DRIVE:. Doing so will change the current drive to the drive specified on the call. Then, issue the Set Directory operation once again specifying the desired path.

Illegal UNION in CREATE VIEW Statement (NetWare SQL (NLM) v3.00x)

When a UNION statement is implemented with a CREATE VIEW statement, only the records from the first SELECT statement are returned. This situationwas originally reported as a bug.

Actually, the use of a UNION statement with a CREATE VIEW statement is illegal for the SQL standard. An error message will be implemented which corresponds to this situation.

API Requires Larger Buffer (Network C for NLMs v2.0 (e))

FEMapVolumeAndDirectory() is passed a buffer in which it returns the NetWare-style path. In addition to returning the path in this buffer, however, it also returns a second copy 500 bytes beyond the beginning of the buffer. If the buffer is not large enough to hold both of these copies memory corruption will occur.

CLIB v3.11 places the second copy approximately 240 bytes after the first; CLIB v3.11d puts the second copy 500 bytes after the first. To ensure that no corruption occurs, add at least 500 bytes to your buffer size. For example, if you are expecting the returned path to be no larger than 100 bytes allocate at least a 600-byte buffer for the path.

Running NetBIOS in a DOS Session with OS/2 (NetWare OS/2 SDK v2.0)

You cannot run the DOS NetBIOS emulator in a DOS session under OS/2 when you have loaded the OS/2 NetBIOS emulator. You can use the DOS NetBIOS TSR from a private DOS box if OS/2 NetBIOS is not loaded. Conversely, the OS/2 NetBIOS is fully functional, but unavailable to DOS sessions.

You may use IBM's virtual NetBIOS for DOS simultaneously with Novell's NetBIOS for OS/2 if you install NTS/2 from IBM to support multiple protocol stacks. Doing so will alter your CONFIG.SYS file to use IBM's landd, lanpdd and lanvpp devices files, which will remap the NetBIOS calls to the OS/2 NetBIOS daemon.


NIBBLES AND BITS

Fast Answers to Common Questions

AppWare

Q - Where can I get information on AppWare?

A - Call 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588 and choose the option for Novell's Automated Fax System (AFS). Then, request document #2900. This document is approximately 20 pages long.

MacIPX SDK

Q - When I call SpxTerminateConnection() all I have to do is check the ECB status and make sure the status was successful. Do I have to actually set up the Macintosh queue and look at the packet?

A - Yes, you could check for a successful status, but it is safer to make sure the status is no longer ST_SENDPACKET. If the remote end crashed just before you sent the terminate packet, the terminate packet probably would never be sent successfully (i.e., it would not get "ACKed"). MacIPX would try to retransmit it a number of times, then abort the connection. In this case, the ECB will indicate that the connection was aborted. By checking that the status is not ST_SENDPACKET, you know that either the packet was "ACKed," or that MacIPX aborted the connection.

This function is asynchronous, so you cannot use a "stack" ECB. It must be allocated, or it must be a global function.

NetWare

Q - Do I need to make any changes to my application to run it under NetWare SFT III?

A - No, everything is taken care of at the SFT level. Even if the primary server goes down, the SPX connection will still be valid.

Q - How can I identify the actual file server on which a queue resides under NetWare Name Services?

A - The DOMAIN QUEUE OBJECT has a property called Q_FILE_SERVER that contains the name of the server that the real queue is on.

NetWare Client SDK

Q - Where can I find the latest version of the DOS workstation files, including the DOS Requester?

A - These files are located on CompuServe in the NOVFILES forum, DOS\Windows Client area. The name of the files to be downloaded are:

  • WSDOS1.EXE
  • WSWIN1.EXE
  • WSDRV1.EXE

NetWare Btrieve (NLM)

Q - After selecting a Named Database to backup, the following error messages were returned:

Error: File not found for database
Error: Btrieve status 0 reading FILE.DDF dictionary file for database
Error: Status 88 received on Btrieve End Continuous Operations.

Why did this occur and what should I do?

A - The NetWare SBACKUP utility uses both NetWare SQL v3.00 and NetWare Btrieve v6.00. Basically, a status 88 will occur if there is anything wrong with the Btrieve files. In this case, a file that was associated with the Named Database was not in the directory that the utility was trying to backup.

This status will also be returned if the files selected for backup were already in Continuous Operations. The SBACKUP utility will itself do a Continuous Operations on all the files associated with the Named Database. Thus, the utility will not be able to perform the backup.

The simple solution is to ensure that all files are in the proper location specified in the Named Database. The other solution is to ensure that the files are not in Continuous Operations when using the SBACKUP utility.

Btrieve for Windows

Q - Are there any third-Party ODBC drivers for Btrieve for Windows?

A - Q+E Software (formally Pioneer Software) has a product called ODBC Pack 1.0. This product currently includes 11 drivers for various database engines, including Btrieve. Q+E technical support said that the Btrieve file must be in NetWare SQL format. In other words, it requires .DDF files. The product also includes a utility to build the .DDF files if you do not have them.

NetWare SQL (NLM)

Q - NetWare SQL v3.00 returns a status 2103 (NetWare SQL not active on the requested server) when I load NetWare SQL on the server. Why?

A - NetWare SQL v3.00 will return a status 2103 when the maximum number of configured SPX sessions is reached. Load NDBSETUP and set the 'Maximum Number of SPX Clients' option to a higher value.

Q - How do I run SQLSCOPE from an OS/2-Windows session?

A - Setup a Private DOS box and log in to the network from that DOS box. Then, load NSREQ, make sure that WXQLCALL.DLL is in the path, and run WINOS2 SQLSCOPE.

The above procedure can be used for any Windows-based NetWare SQL v3.0 application.


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, and 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. Back issues of Bullets and developer FYIs are also available (NOVLIB, library 11). 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 Fed Ex 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 NDEVREL 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's 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 touchtone 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.

DeveloperNet Labs

For information on DeveloperNet 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

Feature Articles: Ken Lowrie, Holly Roff, Vicki L. Smith

Contributors: Gaurang Amin, Linda Anderson, Vitek Boruvka, Ralph Ellis, Steve Iribarne, Sadruddin Khawaja, Rudy McNeese, Clint McVey, Chris Ojeda, Paige Parker, Matt Pinsonneault, Raj Perubhatla, Mike Shoemaker, Nancy Sneary, Michael A. Spano, Aslam Tejani, Howard C. 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, NetWare SFT III, Xtrieve PLUS, DeveloperNet 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 and CodeView are registered trademarks, and Windows, Windows NT, Microsoft QuickBasic and Visual Basic are trademarks of Microsoft Corporation. Apple, AppleLink, AppleTalk, Macintosh, and Macintosh Programmers Workshop (MPW) 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. Univel and UnixWare are trademarks of Univel, Inc. Paradox is a registered trademark of Borland International. dBASE IV is a registered trademark of Ashton- Tate Corporation. WATCOM and WATCOM C are registered trademarks of WATCOM Systems, Inc. Sybase is a registered trademark of Sybase, Inc. Oracle is a registered trademark of Oracle Corporation.