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  

MAY 1992 VOLUME 4 NUMBER 5


INDEX


MAD'S COLUMN

Hello and welcome to the May 1992 issue of Bullets!

I hope that the information provided in "NLMs: From 'Hello World' to World-Class Computing" over the last two months has assisted you in writing your own NLMs and distributed applications.

In talking with a wide variety of folks during the past two months, I have discovered that developers and their managers do not always agree about NLM development. In general, I have found that current NLM developers:

  • feel that the present SDK has come a long way in a short time and contains highly useful, stable, well-documented and supported API sets.
  • believe that the NetWare v3.11 APIs and tools are good -and that those which will be included in the NetWare v3.2 SDK are "very good" to "screaming" (i.e., "excellent").
On the other hand, many managers:
  • are not aware that Novell has developer APIs available or feel that NLMs are very difficult to understand and write.
  • feel that Novell is not committed to its developers and programs.
Whether these managers' opinions are the result of misinformation or a simple lack of information, I do not know, I'll leave that for you to decide. I can say that Novell is more committed to developers today than it was last year. And, we are strengthening that commitment on a daily basis. If you could only see the plans on my whiteboard....

Happy_Programming!

Mad Poarch
Director
Developer Support/Service


ARTICLES:

NLMs: From "Hello World" to World-Class Computing (Part II)

In the April 1992 issue of Bullets, "NLMs: From 'Hello World' to World-Class Computing (Part I)" discussed the similarities between building NetWare Loadable Modules (NLMs) and building applications for other environments. The article examined the APIs available in the NLM environment, and discussed issues like thread synchronization and using NetWare APIs. Part I also investigated the design and function of the communication protocol (CP) layer of a distributed application and examined the CP implementation in the distributed application example, DAX, that is available on NetWire (NOVLIB forum, LIB 1, DAXn.ZIP, where "n" is the version).

This month, Part II will explore the three remaining software components of a distributed application: the distributed application protocol (DAP), and the client and server portions of the distributed application. As before, this article will include an in-depth discussion of how these layers are implemented in the DAX example, and how you can customize this example program for use in your own distributed application. Regardless of the server or client operating system platforms, the issues and techniques discussed in this article can be applied to developing any distributed application.

Distributed Application Protocol

The DAP layer implements the protocol used by the client and server parts of a distributed application. In this case, protocol is the structure of messages exchanged between the two applications. Novell's NetWare Core Protocol (NCP) is one example of a distributed application protocol. NCP is the protocol NetWare clients use to communicate with a NetWare file server. For example, when a DOS client application wants to open a file on a NetWare volume, it issues DOS interrupt 21 function 3D. The NetWare shell, NETX.COM, intercepts the request, builds an NCP request packet, and sends it to the server. The request contains information such as the filename that the application wants to open and the mode in which to open the file. The server receives the NCP, opens the file, and sends a reply packet back to the requesting workstation. The reply packet contains a return code and, if the open was successful, a file handle that the workstation uses on subsequent requests to read or write the file.

Some messages exchanged between the client and server are standard for almost any distributed application, while others are unique to a specific application. Requests for allocating and deallocating sessions with a server application will appear in almost any distributed application. The remaining messages are usually unique to a specific application. Regardless of the message type, each message that the distributed application supports is implemented essentially the same way.

In the same way that the CP protocol layer hides the details of a given communication protocol from the DAP, the DAP conceals the details of the distributed application protocol from the application itself. The client application uses several APIs in the DAP layer to communicate with the server application. This modular design allows you to replace the DAP Layer with minimum difficulty, simplifying the creation of new distributed applications.

The DAX Implementation of DAP

Having discussed the DAP Layer in general terms, it is time to examine how this layer is implemented in the DAX example. Distributed applications handle the overall flow of a request and reply in the following manner:
  1. Client application calls API in DAP layer
  2. DAP API fills in the necessary fields in the DAP request buffer, then passes the data to an API in the CP layer.
  3. CP API fills in the necessary fields in the CP request buffer, builds a protocol packet conforming to the underlying communication protocol (in this case, IPX) then calls an API in IPX to transmit the request.
  4. On the server side, IPX passes the incoming request to a buffer set aside by the CP NLM.
  5. A thread in the CP NLM looks at the data in the CP header, performs a few authentication details, then calls an API in the DAP layer to queue the request. Note that only the DAP related data is given to the DAP API, the CP header is stripped off by the CP layer.
  6. A thread in the DAP NLM identifies the request type, calls an API to service the request, then calls another API to queue the reply.
  7. The sending thread in the DAP NLM unlinks the reply from the send queue, then passes the data to an API in the CP layer.
  8. The CP API fills in the necessary fields in the CP reply buffer, builds a protocol packet, then calls an IPX API to transmit the reply.
  9. The client CP layer receives the reply, strips the CP header information, and passes the DAP data to the DAP layer.
The DAP layer extracts the results, and returns them to the client application.

Part I of this article discussed the advantages of designing a distributed application with four software layers:

  • Communication protocol
  • Distributed application protocol
  • Client application
  • Server application
This design enables you to maintain a very modular program. In some situations, however, you may want embed the server application within the DAP layer. When the server code for each request is minimal, combining it with the DAP layer simplifies the design and reduces the overhead involved with synchronizing error conditions across multiple layers of a software application. For example, when the CP layer detects a failed session, it must clean up resources in use by that session, and then notify the DAP layer to do the same. If the server application is completely isolated from the DAP layer, it must be notified to release resources being used by the failed session too. Of course, similar logic must be in place to handle clean up when an error is detected in the server application. It must notify the DAP Layer, which must clean up and then notify the CP Layer.

Most of the requests supported by the DAX example were implemented with a single line of code. Because of this, it was possible to embed the server application within the DAP software layer. This design allows you to customize the application to your specific needs quickly and painlessly.

DAX Source Directories

The DAX example comes with a number of source directories. Take a moment to look at the layout of these source directories:
  • DAP - Common source and headers
  • DAP/DAPE - Engine code & headers
  • DAP/DAPA - Client code & headers
  • DAP/DAPA/DOS - MakeFile for DOS client
  • DAP/DAPA/NLM - MakeFile for NLM client
The DAP directory contains header files and source files common to both the client and server components of the distributed application, including the source code for the messages that the protocol supports and the error message routine. In addition, the header file, CONFIG.H, is stored here. this file defines constants that determine various configuration defaults for this layer and contains seven configuration parameters for the DAP layer.

The first configuration parameter, DAPMAXDATA, defines the maximum packet size of any single packet within the DAP layer (i.e., the maximum size of a message, be it reply or request) that can be exchanged between the two applications.

The next three constants are specific to the server application. INCDATAAREA identifies whether or not the server application's data structure is defined inside the DAP structure. In DAX, since the server application logic is embedded in the DAP layer, INCDATAAREA is set to TRUE. DEFMAXSESSIONS sets the default maximum number of clients the server application can support. Finally, DAPSTATISTICS defines whether the logic for enabling statistical information will be included in the build. When DAPSTATISTICS is set to TRUE, the DAP spawns a thread of execution that continuously updates various statistical data on the main screen of the server application.

The final three constants are used during the build of the client software. DEFRETRYCOUNT specifies the number of times the DAP layer should resend a request to the server application before giving up. DEFRESPONSEDELAY stipulates how many tenths of a second to wait between each resend of the message. DEFSEQUENCENUMBER is the sequence number assigned to the first packet exchanged between the client and server.

Also included in the DAP directory is the header file, DAP.H. This file contains declarations and constants used by both the client and server portions of the DAP layer. The first items of interest in DAP.H are the protocol packet types supported by the DAX example.

Two of these protocol packet types, DAPALLOCATESESSION and DAPDEALLOCATESESSION, are used by nearly any distributed application. When you customize this example for your own application, these two protocol packet types will probably be the only two you reuse. The remaining seven are specific to DAX.

DAP.H also contains the packet layout structures for the DAP layer. The type declarations are shown below:

..typedef struct {

....UINT32    packetType;

....UINT32    sequence;

....UINT32    sessionID;

....UINT32    timesTried;

....UINT32    requestCode;

....UINT8     data[DAPMAXDATA];

  }DAPRequest;

..typedef struct {

....UINT32    packetType;

....UINT32    sequence;

....UINT32    returnCode;

....UINT8     data[DAPMAXDATA];

....UINT32    dummy[2];

  }DAPReply;
The DAPRequest structure defines the layout of a request that the client application sends to the server application. DAPReply defines the layout of the data returned by the server application in response to a DAPRequest.

"packetType" tells the DAP layer what type of message is being transmitted. Future versions of DAX supporting broadcasting and bidirectional messaging will use this field to identify what type of message has been received.

"sequence" contains the sequence number of a given request. This value is set by the client when a request is made of the server. The server copies the sequence number from the request packet over to the reply packet. The client (application) uses this value to ensure that the reply received was in response to the request generated.

The "sessionID" is assigned by the DAP layer on the server side when the client performs an "allocate session" request. For the "allocate session" request, this value should be zero.

"timesTried" informs the server side when it has been necessary to resend a request and is used for statistical purposes only.

"requestCode" is the protocol packet number (i.e. DAPALLOCATESESSION).

"data" contains the information necessary for a given protocol packet, and is usually unique for each protocol packet type. Of course, each protocol packet has one format for the "data" on the request, and another for the reply.

"returnCode" is the return code of the protocol request and is only valid if the request is processed by the server.

Finally, the DAP.H header file contains the structure layouts for a structure called DAPDATA, used on both the client and server side to track a given session in the DAP layer. These structures are not transmitted across the network; they are used locally to maintain the session. On the client side, the DAPInitialize API returns a pointer to one of these structures whenever a session is established. All subsequent calls to the DAP layer use this pointer as a parameter. This design allows you to use these APIs in a multithreaded environment, such as the NLM implementation of the client application. The client application does not modify this structure; in fact, it knows nothing about the contents of the structure. Only the APIs in the DAP layer of the client software can "see" the elements of this structure.

Figure 1 shows the layout of the client DAPDATA structure. Items of interest in the client DAPDATA structure include "CPid," the handle returned by the CP layer when a session is established with the server. "CPid" is passed on subsequent calls to the CP layer, much like the DAPDATA structure pointer is passed into the DAP layer. In addition, the DAP layer knows nothing about the "CPid" variable, it just passes it to the APIs in the CP layer. (See Part I of this article for a discussion of this structure). Finally, both a DAPRequest and DAPReply structure are declared within the client's DAPDATA structure.

FIGURE 1: Layout of the Client DAPDATA Structure

typedef struct  {

     void    *CPid;         // data for CP layer

UINT32  sessionID;     // ID between client & server DAP Layer

UINT16  retryCount;    // retry count for session

UINT16  responseDelay; // units to wait for a reply

UINT16  timesTried;    // #times sent duplicate msg

UINT16  sendFailed;    // #times actual send failed

char    serverName[48];

UINT32  nextSequence;  // next sequence # to use

DAPRequest  dapRequest;

DAPReply    dapReply;
}DAPDATA;

End of Figure 1
The server DAPDATA structure is different from that of the client. Figure 2 shows the layout of the server application's DAPDATA structure. The linked list pointers "next" and "prev" are used to queue up requests. When the client sends in a request, the DAP layer queues this structure to a linked list for processing by a separate thread. These pointers are also used for queueing up this structure for an outgoing message. "CPid" is obtained from the CP layer when a new session is established between the client and server. The DAP layer uses this ID when sending replies to the client. "DAPState" is used to provide state information for this client. It is used to control the flow of the structure between the multiple threads of execution. Once again, memory for both a DAPRequest and DAPReply structure is reserved here, providing temporary storage for incoming and outgoing requests.

FIGURE 2: Layout of the Server DAPDATA Structure

typedef struct  _dd{
        struct _dd  *prev;    // pointer to previous link
        struct _dd  *next;    // pointer to next one in link
        UINT32      CPid;     // client ID for CP layer
        UINT32      DAPState;
        UINT32      DAPFlags;
        DAPRequest  dapRequest;
        DAPReply    dapReply;
    #if INCDATAAREA
        struct{
        SINT32      lastResult;
        SINT32      mailBox001;
        }applData;
    #else
        void        *applData;
    #endif
}DAPDATA;

End of Figure 2

Server implementation

The server implementation of the DAP layer is depicted in Figure 3. Incoming messages are given to the DAP layer using an API defined by the DAP layer during initialization. Requests are queued via DAPEnqueueRequest, processed by the DAPServiceRequestQueue thread of execution, and then queued for sending back to the client by DAPServiceReplyQueue. The server application itself is implemented within the Request 1 through Request n functions.

FIGURE 3: Server implementation of the DAP layer

 __________              __________         _________
| Service  |  Requests  |          |       | From    |
| Request  |<-----------| Enqueue  |<------| CP      |
| Queue    |            | Request  |       | Layer   |
|__________|            |__________|       |_________|
        |
      __V_________ ____________ _______________
     |            |            |               |
 ____V_____   _____V____   _____V____       ____V_____
|          | | De-      | |          |     |          |
| Allocate | | Allocate | | Request  | *** | Request  |
| Session  | | Session  | |    1     |     |    n     |
|__________| |__________| |__________|     |__________|
     |            |            |               |
     V____________V____________V_______________V
        |
 _______V__              __________         _________
|          |  Replies   | Service  |       | To      |
| Enqueue  |----------->| Reply    |------>| CP      |
| Reply    |            | Queue    |       | Layer   |
|__________|            |__________|       |_________|

End of Figure 3

The Client Application

Having implemented the underlying CP layer, DAP layer, and server application, a client application is all that is required to complete the distributed application. When you browse the code provided for the client applications that come with DAX, you will immediately see that the details of communicating with the server application are entirely hidden from the client application. Once the CP and DAP layers are written, you can use and reuse them with only slight modifications.

This article includes a final example of the minimum requirements for a client application. The example program, named ADD, is displayed in Figure 4.

FIGURE 4: Example program ADD

#include 
#include 
#include 
#include 
#include "h/appl.h"
#include "dap/dapapi.h"

#include 

static  DAPDATA *dd;

atexitproc()
{
   if( dd ){
      DAPDeAllocateSession(dd);
      DAPDeInitialize(dd);
   }
}

main(int argc, char *argv[])
{
   int     rc;
   long    x,y,z;

   if( argc == 3 ){
      x = atol(argv[1]);
      y = atol(argv[2]);
   }
   else{
      printf("usage: ADD op1 op2\n");
      exit(1);
   }
   atexit(atexitproc);
   if( (dd = DAPInitialize(SERVERNAME, SERVERTYPE)) == NULL ){
      printf("Could not initialize DAP\n");
      exit(1);
   }
   printf("Initialized okay...\n");
   if( (rc = DAPAllocateSession(dd)) != NULL ){
      printf("Allocate Session failed '%s'",
      DAPTranslateReturnCode(rc));
   }
   printf("Attached to server '%s'\n",SERVERNAME);
   if( (rc = DAPAddOperands(dd,x,y,&z)) != NULL ){
      if( DAP_CRITICAL_ERROR(rc) ){
          printf("\n\n\t%s. rc = %d\n",
                 DAPTranslateReturnCode(rc),rc);
          DAPDisplaySessionData(dd);
          exit(1);
      }
      else{
          printf("\n%s\n", DAPTranslateReturnCode(rc));
      }
   }
   printf("%ld + %ld = %ld\n",x,y,z);
   if( (rc = DAPDeAllocateSession(dd)) != NULL ){
      printf("\n\n\t%s. rc = %d\n",
             DAPTranslateReturnCode(rc),rc);
   }
   DAPDeInitialize(dd);
   dd = NULL;
   return 0;
}

End of Figure 4
ADD takes two arguments for an addition operation, attaches to the application server, sends a request, and prints the results. This application uses only five DAP API calls:
  • DAPInitialize()
  • DAPAllocateSession()
  • DAPAddOperands()
  • DAPDeAllocateSession()
  • DAPDeInitialize()
The first two and last two APIs will be present in any client application which utilizes the services provided by the DAX server application. The function of each specific client application will determine which other APIs you must incorporate. As shown in Figure 4, the example client application makes no API calls to the CP layer. The client application is not aware of how its requests are communicated to the server application and there is no need for it to know.

Using the DAX example program as a prototype or point of departure, you should be able to create your own distributed applications. The NetWare 3.x environment offers a full set of APIs for application programmers: an ANSI-compliant runtime library, an execution thread API, synchronization APIs, POSIX APIs, NetWare APIs, and other platform specific APIs. For more information on the Network C for NLMs software developer's kit, contact Novell's Professional Developers' Program at 1-800-RED-WORD (1-800-733-9673), or 1-512-794-1796.


TECHNICAL INSIGHTS:

Using BROLLFWD with Btrieve for DOS (Btrieve for DOS v5.10)

The Btrieve for DOS Installation and Operation Manual discusses how to log Btrieve files to another volume on the server. However, it does not describe how to log a Btrieve file to another physical hard drive or mapped drive.

To log a Btrieve file to another physical drive, make an entry in the BLOG.CFG file in the following format:

 [=]
In this entry, "" is the absolute pathname of the Btrieve file to be logged without the drive letter (it must begin with a backslash (\) character). "" is the absolute pathname to the associated log file including the drive letter.

For example, if a Btrieve file called TEST.BTR resides on the server in the F:\DATA directory and the log file is located on a local hard drive (Drive C:\BTR\LOG\TEST.LOG), the entry in the BLOG.CFG file should be:

\DATA\TEST.BTR =C:\BTRIEVE\LOG\TEST.LOG

This information applies to Btrieve for DOS only. With NetWare Btrieve, do not specify a drive letter for either the Btrieve filename or the logfile.

Borland C++ & Btrieve (Btrieve for Windows v5.10)

Name Mangling is an attribute of the Borland C++ compiler which allows multiple definitions of functions within an application. Name mangling is documented in Chapter One of the Borland C++ Programmer's Guide, v2.0.

This attribute is not compatible with the WBTRINTF.C file supplied with Btrieve for Windows v5.10. When you link a program, unresolved externals can appear and the linker may return "unresolved external btrv()" errors. The linker will also return all functions defined in the C file in lower case (Btrieve for Windows prototypes and functions do not contain a lower case "btrv()"). This situation occurs because the C file is compiled as a C++ file and consequently the compiler applies name mangling to the BTRV function and every other function defined.

To disable the name mangling attribute, set a compiler directive to treat functions as regular C functions if files are being compiled as C++ files by default. The directive is:

#ifdef __cplusplus   extern "C" {   endif

#ifdef __cplusplus   }   endif
With this directive in place, functions between the two statements will be treated as standard C functions and name mangling will not be performed. Function prototypes can be defined in a series of include files which can be placed between the compiler directives. For example, WBTRV.H could be included between the directives and then the function BTRV would not be mangled by the compiler. There are many ways to implement this directive, but the compiler will mangle function definitions if you do not use some implementation.

VIPX.386 & IPXSendPacket (NetWare System Calls for DOS v1.0)

When using IPX via the NetWare System Calls for DOS in a Windows DOS box, VIPX.386 v1.11 does not update the AL register when ECBs are successfully posted with IPXSendPacket(). Instead, VIPX.386 updates the AL register when errors occur. If the AL register is not cleared before making the IPXSendPacket call, garbage in this register may be interpreted as an error condition. To avoid this situation, clear the AL register before making the IPXSendPacket call.

Preferred ConnectionID in Windows Applications (NetWare C for Windows v1.22)

Under Windows, a workstation's preferred ConnectionID variable can be reset to zero even though the application has previously called SetPreferredConnectionID() and set it to a ConnectionID other than zero. When an application calls SetPreferredConnectionID() and then waits before sending a request to the server, other Windows applications can change the PreferredConnectionID in the interim. To avoid this situation, call SetPreferredConnectionID() before each request to the server.

Network C for NLMs Documentation Updates (Network C for NLMs v2.0b)

ChangeDirectoryEntry()

The ChangeDirectoryEntry API returns an error code 1 if any of the following conditions occur:

  1. OwnerID is invalid
  2. LastUpdatedID is invalid
  3. LastArchivedID is invalid
  4. maximumSpace is invalid, i.e. less than -1 or equal to 0x7FFFFFFF
The Network C for NLMs documentation will be updated to include this information in the next revision.

FEGetOriginatingNameSpace()

The documentation for the CLib API FEGetOriginatingNameSpace does not describe the return values of the different name spaces. The function returns:
0 for DOS
1 for Macintosh
2 for NFS
3 for FTAM
4 for OS/2

These values are mentioned in the documentation for the GetNameSpaceName() function.

Converting Decimals to Binary Strings (Btrieve (all versions))

When developing Btrieve applications in Microsoft BASIC, you may need to perform BIT manipulations occasionally. For example, you might need to extract file information from the return data buffer on a Btrieve STAT operation.

The BASIC code segment shown in Figure 5 demonstrates how to build a string of binary information from a decimal number. You can then parse this string to extract the appropriate bit information.

FIGURE 5: Converting decimal no. to string of binary info

Bin$=""                            'Initialize the string

  INPUT"Decimal number = ";Decimal 'obtain the decimal number

 FOR i = 14 TO 0 STEP -1           'Positive numbers only
   pow2 = 2^i
   IF Decimal >= pow2 THEN
      Decimal = Decimal - pow2
      Bin$ = Bin$ + "1"
   ELSE
      Bin$ = Bin$ + "0"
   END IF
NEXT i
PRINT"Binary String = ";Bin$

End of Figure 5

New Patches for HLLAPI v2.2.f.11 (3270 Tools for DOS v1.5)

A new HLLAPI patch file, HLLAPI.ZIP, fixes the following problems:
  • The Pause function was calculating wait time inaccurately.
  • The Find Field Length function returned a invalid field length for row 24 of the presentation space (PS).
  • The Find Field Position returned an invalid field position for offset 1.
HLLAPI.ZIP can be downloaded from Novell's CompuServe forum, NetWire (NOVLIB forum, LIB 9).

Sessions and NetWare SQL v3.0 (NetWare SQL v3.0)

NetWare SQL 3.0 is priced and sold by number of available sessions. Novell will offer 250-, 100-, 50-, 20-, 10-, and 5-session versions. This system is similar to the NetWare stratification but there is one major difference: NetWare is user-count stratified and NetWare SQL v3.0 is session-count stratified.

With 250-user NetWare, 250 workstations can be logged into the system simultaneously. There are 250 connections available on the server. Consequently, Windows and OS/2 workstations can run multiple NetWare applications from a single workstation, and each application only counts as a single connection.

With NetWare SQL v3.0, session-count does not necessarily equate to NetWare user-count. With 250-session NetWare SQL, it is possible to use all 250 sessions without having 250 workstations logged into NetWare. In Windows and OS/2, every application that makes a connection to NetWare SQL is considered a session. So, if there were 10 Windows NetWare SQL applications running on 25 Windows workstations, all available NetWare SQL sessions would be used, even though there would be only 25 NetWare connections.

The Btrieve NLM v6.x (included with NetWare SQL v3.0) is also session-count stratified, although the limit is based on the sessions parameter configured in the setup utility (maximum = 250 sessions).

Running Brequest in an OS/2 DOS Box (NetWare Btrieve (NLM) v5.1x)

BREQUEST.EXE will not run in an OS/2 DOS box on OS/2 v1.3 because of incompatibilities between the SPX APIs in the DOS box and OS/2. If you run DOSBOX.EXE with BREQUEST.EXE, the error "IPXOpenSocket Failed" will be returned. This problem cannot be corrected in v1.3 of the NetWare OS/2 requester.

New API in CLib PATCH311 (Network C for NLMs V2.0b)

PATCH311 includes a new CLib API called SpxListenForConnectedPacket. This API allows you to post an ECB on a specific SPX session. The prototype is:

int SpxListenForConnectedPacket(unsigned short socket, SPX_ECB *ECBp, unsigned short connection);

where "socket" is the open socket (0 if specified in ECB), "ECBp" is a pointer to the listen ECB and "connection" is the SPX connection number assigned when the connection was established. You should also add this API to your import symbol list, or add it to the CLIB.IMP file.

SetCapturePrintQueue() System Call (NetWare System Calls for DOS v1.0)

The documentation of SetCapturePrintQueue(), B8h (06h), instructs you to pass the first(low) word of the Queue ID in the BX register and the second (high) word in the CX register.

However, if these are reversed and the high word is passed in BX and the low word is passed in CX, the function returns successfully but it does not work; no error codes will be returned, the target print queue will not be set, and capturing will fail.

Btrieve for Windows Load Parameters (Btrieve for Windows v5.10)

With the local requester, WBTRCALL.DLL, every Windows session can specify different Btrieve load parameters if each application calls the WBTRVINIT function. This call allows you to pass a string containing the Btrieve load parameters, and should be the first Btrieve call made by your application.

If you do not use the WBTRVINIT call, then the load parameters specified in the "[btrieve]" section of WIN.INI will be used. If there is no "[btrieve]" section in WIN.INI, the local requester is loaded with default parameter values.

When you use WBTRCALL.DLL, the Btrieve load parameters are essentially "global" since they can only be specified in the "[brequestDPMI]" section of the WIN.INI file. The WBRQSHELLINIT call is not currently implemented to initialize the WBTRCALL.DLL requester from within an application.

NetWare Lite & ODI Cards Correction (NetWare Lite v1.0)

In the April 1992 issue of Bullets, "NetWare Lite & ODI Approved Cards" (Technical Insights) incorrectly stated that, "A network card driver suitable for other NetWare networks will not work with NetWare Lite unless it is an ODI version of the driver." In fact, NetWare Lite will work with both ODI and IPX-based LAN drivers. If you choose to use ODI, you should contact the card manufacturer to see if an ODI driver is available for the card. If not, you must install another network card which has an ODI driver."

Determining if NASI is Loaded (NASI v3.0)

To determine whether or not the NetWare Asychronous Services Interface (NASI.EXE) TSR is loaded, follow the procedure listed below.
  • Since NASI uses interrupt 6Bh, view the contents of the two words at offset 1ACh.
  • Go to the segment and offset plus three bytes (SEG:OFFSET+3) listed in the two-word entry.
  • Compare the value of the next four bytes with the value, NCSI.
  • If the values match, NASI is loaded.

Function Incorrectly Sets "errno" (Network C for NLMs v2.0b)

When you attempt to create a directory that already exists, the mkdir function correctly returns an error [-1] but incorrectly sets "errno" to ENOENT (1-No such file or directory). It should actually be set to EACCES (6-Permission Denied). There is currently no workaround for this situation.

Register Passing with Microsoft C v6.0 (NetWare C Interface for DOS v1.2)

Microsoft C v6.0 contains a new command line parameter, /Gr, which specifies that functions will pass parameters in registers. If you use this parameter, none of the NetWare C Interface for DOS functions will be resolved at link time. Microsoft does not export these symbols with an underscore before the function name when you use register-passing.

To resolve these functions at link time, you must perform the following two steps:

  • Include stddef.h before nit.h.
  • Add the "cdecl pragma" before each of the NetWare C Interface for DOS functions that you are going to use.
These steps will ensure that symbols are exported with the underscore before the function name and the parameters will be pushed on the stack.

Calling CLib Functions from an AES Process (Network C for NLMs v2.0b)

Before an AES process calls a CLib function, the ThreadGroupID must be set to the ThreadGroupID of any CLib NLM; the most obvious choice is the NLM which scheduled the AES process. The ThreadGroupID can be added as an element of the AES structure that is passed to the AES function.

The AES function should set the ThreadGroupID (saving the current ThreadGroupID), make the CLib calls, then before exiting the AES process, set the ThreadGroupID to the value when the process was invoked. This information applies to both SLEEP and NO SLEEP AES processes. However, with NO SLEEP AES processes, there is one additional restriction: the AES process may not call any CLib blocking functions.


NIBBLES AND BITS

Fast Answers to Common Questions

Network C for NLMs

Tip In the March 1992 issue of Bullets, "Nibbles & Bits" incorrectly stated that, at high speeds, "the COMX driver does not guarantee that all characters will be received, because it disables interrupts for too long." In fact, it is the LAN and disk drivers (not the COM driver) which disable interrupts for too long. Bullets was, however, correct to suggest using a driver like the ARTIC driver and the WNIM driver because they have their own CPU on board and, for that reason, are more reliable at high speeds.

Q - Where can I find PATCH311.NLM ?

A - You can download PATCH311.NLM from NetWire (NOVLIB, LIB 4, PAT311.ZIP). This file is also available in the NDEVREL forum (LIB 7, filename: PCL311.ZIP). This file contains the debugging information as well a DOC file that lists each included patch.

Q - If I use a ScheduleSleepAESProcessEvent and call localtime(), when I unload my NLM, I get a resource warning that I have not freed 104 bytes (or a multiple of 104 bytes) of short term memory. What should I do?

A - Running localtime() in this context allocates memory that the NLM cannot free because the localtime structure pointer is saved as part of the AES thread, rather than one of your NLM's threads. CLib cannot detect the allocated memory and therefore does not free it. For the same reason, you should not call asctime(), ctime(), gmtime(), strtok(), rand(), and srand() in an AES thread.

Xtrieve PLUS

Q - How can I configure Xtrieve PLUS v4.10 so that it does not use the new printer support, but instead works like Xtrieve PLUS v4.01a?

A - In the Configure menu, choose the "Switches" option. Then set the "Printers" option to "NO." If you wish, you can save this configuration to make it effective every time you load Xtrieve PLUS v4.10.

Q - How can I print an Xtrieve PLUS v4.10 report with different size letters and different fonts on a Hewlett Packard LaserJet printer?

A - If you set Configure/Switches /Printers to "NO," you can add a new entry under Configure/Print /Attributes. There will be three columns: attribute name, start sequence, and stop sequence. Refer to the HP LaserJet Printer Manual, and type the escape sequences for the fonts and sizes you wish to use. Before printing the report, remember to select all desired attributes from the Report/Attributes menu.

Btrieve

Q - When I program with Btrieve, why does Btrieve return a status 22 if I perform a Stat operation, even though I have allocated the maximum number of key spec buffers (24)?

A - Your file may be using an alternate collating sequence, which requires you to allocate an additional 265 bytes in the data buffer that you send to the Stat operation. Nine bytes are for the name of the alternate collating sequence and 256 are for the actual sequence.

Q - When I perform a Get Next Extended operation, Btrieve returns a status 62. What does this mean?

A - Status 62 often indicates an error in one of the values in the descriptor or extractor (i.e. your data buffer). To check for this error, make sure the first two bytes of the data buffer contain the exact length of the data buffer you are sending to the Get Next Extended operation. The Data Buffer Length parameter in the call to Btrieve does not have to be the exact length of the data buffer, but if it is longer , any variable defined after the data buffer will be overwritten.

NetWare for SAA

Q - Can UNIX or OS/2 clients access an IBM host via Netware for SAA?

A - Yes. The latest release, Netware for SAA v1.2, includes support for UNIX and OS/2 clients through third-party software. CLEO Communications has announced a version of 3270LINKIX software that works with Netware for SAA and provides 3270 terminal emulation for UNIX clients. Wall Data's RumbaPM client software now takes full advantage of NetWare for SAA to provide OS/2 users with IBM host connectivity.

VIPX.386

Tip To determine if VIPX.386, the NetWare driver for Windows, is loaded into memory, issue an INTF2 call with the value 1684h in the AX register and 0200h in the BX register. The function name is WindGetDeviceApiPoint(). If the return code in ES:DI register is 0, VIPX.386 is not loaded. Otherwise, VIPX.386 is loaded.

NetWare C Interface for Windows

Tip If you are using the NetWare C Interface for Windows SDK v1.22, and need to have full compatibility with Windows 3.1, use the current version, v1.30. You can obtain the upgrade to v1.3 by calling 1-800-RED-WORD.

NOVELL EDUCATION

Novell Education offers classes for many of the Database & Development Products including Btrieve, XQL, NetWare SQL, Xtrieve PLUS and the NetWare Client APIs. These classes are designed to introduce participants to the powerful features of Novell's development tools, database products, and NetWare services. Nearly 50% of class time is devoted to hands-on activities.
  • 901 - Programming with NetWare Client APIs
    June 10-12 Sunnyvale, CA
    Aug. 12-14 Washington, DC
  • 905 - Programming with Btrieve
    Aug. 12-14 Sunnyvale, CA
  • 906 - Programming with Btrieve: Advanced Features
    June 16-18 Austin, TX
  • 907 - Xtrieve PLUS
    July 14-15 Dallas, TX
  • 910 - Programming with XQL
    June 9-11 Austin, TX
  • 920 - Programming with Network Communication Services
    June 15-16 Sunnyvale, CA
    Aug. 17-18 Washington, DC
  • 930 - Developing NetWare Loadable Modules (NLMs)
    July 15-17 Washington, DC
To register or obtain information on pricing, location and course content for classes held in the US, call 1-800-233-3382, 1-801-429-5508 or 1-800-NET-WARE. International customers should call 1-801-429-5508. All courses are subject to cancellation or rescheduling within two weeks of the scheduled date, depending on enrollment.
  • For information on availability, location, and prices of international classes, contact your local Novell office.

    FUN & FACTS

    Test your "developing" skills with the various Professional Development Series products by taking our Fun & Facts quiz. Have fun and good luck! (See the end of this section for answers.)
    1.   With Novell's Network C for NLMs SDK, how do you set the break-point when you get a
    message on the console saying "Module did not release [X] resources" and "Resource : Small
    Memory Allocations" while unloading your NLM?
    
    A.   'b=malloc-4b+[dmalloc-7]'
    B.   'b=malloc-3d+[dmalloc-5]'
    C.   'b=malloc-4d+[dmalloc-9]'
    2.   With the LAN WorkPlace Toolkit for DOS v4.01, what is the link interface driver which,
    instead of interpreting received packets, simply copies identification information from the packet
    into a receive ECB and passes the ECB to the link support layer (LSL)?
    
    A.   NLID (Novell Link Interface Driver)
    B.   MLID (Multiple Link Interface Driver)
    3.   OS/2 workstations can boot from NetWare server using what program?
    
    A.   RIPL (Remote Initial Program Load)
    B.   OS2RPL (OS/2 Remote Program Load)
    C.   OS2INIT (OS/2 Initialize)
    4.   NetWare NFS is implemented as a family of different remote procedure calls. How many
    different calls are there?
    
    A.   23
    B.   18
    C.   15
    D.   14
    5.   In NetWare C Interface for Windows, what function releases the resources allocated by
    NWIPXSPX.DLL?
    
    A.   IPXDeinit()
    B.   SPXDeinit()
    C.   IPXSPXDeinit()
    D.   IPXDeinitialize()
    6.   What status code does Btrieve return when you attempt to perform an INVALID
    OPERATION?
    
    A.   62
    B.   48
    C.   27
    D.   1
    7.   What Btrieve operation is valid in the v5.10 DOS and VAP versions, but not the NLM
    version?
    
    A.   Reset (28)
    B.   Extend (16)
    C.   Insert Extended (40)
    8.   What is the pre-defined function key in Xtrieve PLUS to display the Help screen?
    
    A.   F1
    B.   F2
    C.   F7
    D.   F10
    9.   In Xtrieve PLUS, what is the maximum length of a user password?
    
    A.   8
    B.   12
    C.   14
    10.  What BROLLFWD command line option is used for automatic recovery of all files on a
    volume?
         A.   /v
         B.   /r
         C.   /a
    
    FUN & FACTS ANSWERS
    1.   C
    2.   B
    3.   A
    4.   B
    5.   C
    6.   D
    7.   B
    8.   A
    9.   A
    10.  C
    

    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.

    ACKNOWLEDGEMENTS

    Publisher: Mad Poarch
    Editor: Kirk R. Humphries
    Design: Creative Services, Provo

    Contributing authors:
    Linda Anderson, Michael Eisa, David Harris, Laura Heater, Sudz Khawaja, Ken Lowrie, Rudy McNeese, Clint McVey, Chris Ojeda, Paige Parker, Bill Prentice, Randy Reddy, Mike Shoemaker, John E. Stewart, Aslam Tejani, Maggie Walczynski

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

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

    Novell, the N design, NetWare, Btrieve, XQL and LAN WorkPlace are registered trademarks, NetWare System Calls for DOS, NetWare Loadable Module (NLM), NetWare SQL, NetWare Btrieve, Xtrieve PLUS, NetWare C Interface for DOS, NetWare System Interface Technical Overview, NetWare RPC, NetWare RPC 386, NetWare LU6.2, Report Executive, and Professional Development Series (PDS) are trademarks, and NetWire, Direct Connect and Professional Developers' Program (PDP) are servicemarks of Novell, Inc. Apple, Macintosh and AppleTalk are registered trademarks of Apple Computer, Inc. CompuServe is registered trademark of CompuServe Corporation. Microsoft is a registered trademark, and Windows is a trademark of Microsoft, Inc. IBM and OS/2 are registered trademarks, and SAA is a trademark of International Business Machines Corporation. Sun Microsystems and NFS are registered trademarks of Sun Microsystems, Inc. WATCOM is a trademark of WATCOM Systems, Inc.

  •