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  

JANUARY 1994 VOLUME 6 NUMBER1


INDEX


ARTICLES:

IPX/SPX for NetBIOS Developers

NetBIOS is a popular peer-to-peer communication method that it is supported under NetWare through a NetBIOS emulator. However, even though NetBIOS is supported, there are definite advantages to using Novell's "native tongue" protocols, IPX (Internet Packet eXchange) and SPX (Sequenced Packet eXchange), when doing peer-to-peer communication.

This article discusses the advantages of using IPX/SPX and provides an introduction to Novell's IPX and SPX protocols for developers who have a working familiarity with NetBIOS.

Why Use IPX/SPX?

The most obvious reason to use IPX and SPX is to improve performance; since NetWare emulates NetBIOS, processing NetBIOS commands involves more overhead than processing IPX/SPX commands. NetWare encapsulates emulated NetBIOS packets within IPX packets before they go out on the wire, so moving to IPX/SPX allows you to "cut out the middleman."

You lose no connectivity by switching protocols either, since the emulated NetBIOS layer cannot communicate with hardware NetBIOS systems. In fact, moving to IPX/SPX gives you a net gain in connectivity; NetWare has a 70% share of the network operating system market.

Also, since the NetBIOS emulator adds an additional layer of complexity to packets being sent out, it is more difficult to troubleshoot problems. Emulating NetBIOS involves an extra driver and an extra set of potential incompatibilities. Generally speaking, since IPX and SPX are not dramatically different from NetBIOS, it makes your job easier to work with the protocols that NetWare is designed to support.

Datagram Services

Novell's IPX protocol provides almost the same functionality as NetBIOS datagrams. Both specifications deliver packets on a best-effort basis, but with no guarantee of delivery or sequencing. Both IPX and NetBIOS also provide the capability to send packets either to a single node or to multiple nodes. NetBIOS supports the multicast, or the sending of a datagram to a selected group of nodes with the same group name. Since IPX is address-based instead of name-based, this capability is not directly supported; instead IPX must send an individual packet to each node.

NetBIOS also supports the broadcast datagram, a datagram that is broadcast to the entire internetwork. IPX supports broadcasts, but only to one subnet at a time. Usually, this restriction poses no problem, since mechanisms such as the NetWare Service Advertising Protocol (SAP) overcome this limitation.

The data portion of a NetBIOS datagram is limited in length to 512 bytes, whereas IPX packets allow 546 bytes of data on all networks and can sometimes be substantially larger than that depending on the maximum packet size supported by network routers. Some networks can handle packet sizes of 4096 bytes or more.

Session Services

As in the relationship between IPX and NetBIOS datagrams, Novell's SPX protocol serves much the same function as the NetBIOS session. Both SPX and NetBIOS sessions provide guaranteed delivery and sequencing of packets, but at the cost of increased overhead.

The primary difference between the two is the supported packet size. NetBIOS sessions support 64K packet sizes (128K with Chain Sends). SPX has the same 546-byte packet size limitation as IPX and, in fact, SPX allows slightly less data in a packet than IPX, since the SPX header requires an additional 12 bytes. SPX therefore supports 534 bytes of data on all networks with the potential for much larger packets if supported by the routers, although attaining a 64K packet size is unlikely.

Probably the most noticeable difference between IPX/SPX and NetBIOS is how each addresses packets. IPX/SPX addresses packets using network, node, and socket numbers. NetBIOS uses unique names to address packets. Each workstation can be uniquely addressed using the network and node numbers.

A workstation can then have as many open sockets as desired for receiving peer-to-peer data packets. Many methods exist for determining a workstation's network, node, and destination socket number, but for simplicity the example code in this article uses SAP to obtain this information.

The Waiting Game

With NetBIOS, you can choose to allow most NetBIOS commands to complete before returning control to the application, but most IPX/SPX commands return control immediately. In other words, most IPX/SPX commands are "no-wait" commands; there is no IPX/SPX "wait" counterpart.

Since most NetBIOS developers use the "no-wait" variants, this difference should not pose a problem, but if you need to use a "wait," you can code it very simply by issuing the command and then looping on the in use field.

Asynchronous Events

IPX/SPX also has a feature that is not used with NetBIOS: the asynchronous event. An asynchronous event can be initiated at any time and, as the name implies, can be set to occur independent of an application's execution path. An event could be set up, for example, to automatically broadcast an IPX packet every 45 seconds. The application initiating this event could then continue processing and leave the timing and broadcasting of packets to the IPX event handler.

The Network Control Block & the Event Control Block

From a developer's perspective, the "core" of NetBIOS is the Network Control Block (NCB). IPX and SPX are based on an Event Control Block (ECB) and an IPX/SPX header. Figure 1 describes the fields in the ECB.

FIGURE 1: The IPX/SPX Event Control Block

void far *linkAddress              Set by IPX
void (far *ESRAddress)()           Equivalent to NetBIOS POST routine
BYTE inUseFlag                     Set when the ECB is in use, zero when   it is available
BYTE completionCode                Equivalent to NetBIOS Command Completion
WORD socketNumber                  Socket number associated with ECB
BYTE IPXWorkspace[4]               Set by IPX
BYTE driverWorkspace[12]           Set by IPX
BYTE immediateAddress[6]           Node address of next "hop"
WORD fragmentCount                 Number of buffer fragments in packet
ECBFragment fragmentDescriptor[2]  Address and size of fragment(s)
END of FIGURE 1
Note that the ECB contains a field that has no equivalent in the NCB called the immediate address field. This field should be populated with the node address of the first "hop" on the way to the packet's ultimate destination. Novell provides an API call to populate this field, the IPXGetLocalTarget() API available in the NetWare Client SDK.

IPX Send Example

The sample code in this article includes simple examples written under DOS with the NetWare Client SDK. Figure 2 shows a routine sending an IPX packet.

FIGURE 2: IPX Send

/* Send "Hello!" to the station at network 0x11111111, node
   0x222222222222, socket 0x3333 using IPX */
void IPXSayHello()
{
   char buffer[] = "Hello!";
   ECB ecb;
   IPXHeader header;
   int transTime;
   header.packetType = 4;
   memset(header.destination.network, 0x11, 4);
   memset(header.destination.node,    0x22, 6);
   memset(header.destination.socket,  0x33, 2);
   ecb.ESRAddress     = NULL;
   ecb.socketNumber   = 0x4444;
   IPXGetLocalTarget(header.destination,
ecb.immediateAddress, &transTime);
   ecb.fragmentCount = 2;
   ecb.fragmentDescriptor[0].address = &header;
   ecb.fragmentDescriptor[0].size    = sizeof(IPXHeader);
   ecb.fragmentDescriptor[1].address = buffer;
   ecb.fragmentDescriptor[1].address = strlen(buffer) + 1;
   IPXSendPacket(&ecb);
}
END of FIGURE 2
The first apparent difference between IPX and NetBIOS is that IPX uses two buffers where NetBIOS would use one. The first buffer is the IPX Header containing the source and destination addresses, the packet type, and several "housekeeping" fields. Refer to Figure 3 for a description of the IPX header.

FIGURE 3: IPX Header

WORD       checkSum            Included to conform to Xerox IDP standard
                              Set to FFFF by IPX
WORD       length             Length of entire IPX packet including header
                              Set by IPX
BYTE       transportControl   Hop count - Set to zero by IPX
BYTE       packetType         IPX packet type is 4
IPXAddress destination        Address the packet is sent to
IPXAddress source             Address of node sending packet set by IPX
END of FIGURE 3
The second buffer is the data to be sent. Two fields in the IPX header must be set for an IPX send: the packet type and the destination address. IPX packets are type 4, SPX packets are type 5. The destination address consists of a four-byte network number, a six-byte node number, and a two-byte socket number.

If these examples used an Event Service Routine (ESR), the ESR address would be filled with the address of a procedure to be run when the send completes, but since NULL is specified, this routine will not be run. The ESR is equivalent to the NetBIOS POST routine. When the IPX send executes, the rest of the fields in the IPX header are filled in automatically, including the source address. You must specify the socket number to be included in the source address, but the socket need not be open to send a packet. For this example, socket number 0x4444 was arbitrarily chosen.

The immediate address field described above must be filled in as well, and the IPXGetLocalTarget() API call fills in this field with the appropriate value. It is passed the final destination of the packet and it calculates the address of the "first hop" on the way to the final destination. Note that if the target workstation is on the same subnet as the sending workstation the immediate address will be the same as the final destination. Otherwise, it will be a bridge or router on the subnet.

Each of the buffers sent in the IPX packet is considered to be a fragment. Since there are two buffers (the IPX header and the data), the fragment count is equal to two. The address and size of the fragments are then entered, starting with the IPX header. As soon as all of the relevant fields are filled, the example calls IPXSendPacket() and passes it the address of the ECB.

Receiving an IPX packet is much like sending one from a programming standpoint, except that you do not need to set the IPX header fields. In the ECB, you should set the ESR address, socket number, immediate address, and fragment descriptors.

Note about socket numbers: the socket number specified for an IPX send does not need to be open, but for an IPX receive the socket must be open. The API call to receive an IPX packet is IPXListenForPacket().

SPX Connection Example

Figure 4 contains a code sample that establishes an SPX connection. Before the request for an SPX connection is submitted, several ECBs are already listening for data (this is important). SPX temporarily "steals" two ECBs from the available and waiting ones for connection maintenance, and then it puts the stolen ECBs back in the pool when finished. If there are no pending ECBs for SPX to use, it cannot send an acknowledgement to the remote site and the connection will stall and time out.

FIGURE 4: Establishing an SPX Connection

/* Start an SPX connection with the station at network
   0x11111111, node 0x222222222222, socket 0x3333, use
   local socket 0x4444 */
#define NUM_BUFFS 5
void call()
{
  ECB send, receive[NUM_BUFFS], connect, term;
  SPXHeader sendHdr, rcvHdr[NUM_BUFFS], connHdr;
  char buffer[NUM_BUFFS][80], sendbuf[] = "Hello!";
  int i, ccode, packetsReceived;
  WORD spxConnectionID;
  for (i = 0; i < NUM_BUFFS; i++) {
      receive[i].ESRAddress = NULL;
      receive[i].socketNumber = 0x4444;
      receive[i].fragmentCount = 2;
      receive[i].fragmentDescriptor[0].address
        = &(rcvHdr[i]);
      receive[i].fragmentDescriptor[0].size
        = sizeof(SPXHeader);
      receive[i].fragmentDescriptor[1].address
        = &(buffer[i]);
      receive[i].fragmentDescriptor[1].size = 80;
      SPXListenForSequencedPacket(receive[i]);
  }
  connect.ESRAddress = NULL;
  connect.socketNumber = 0x4444;
  connect.fragmentCount = 1;
  connect.fragmentDescriptor[0].address = &connHdr;
  connect.fragmentDescriptor[0].size
    = sizeof(SPXHeader);
  memset(connHdr.destination.network, 0x11, 4);
  memset(connHdr.destination.node,    0x22, 6);
  memset(connHdr.destination.socket,  0x33, 2);
  ccode = SPXEstablishConnection(0, 0,
                                 &spxConnectionID,
                                 &connect);
  printf("SPXEstablishConnection return code
         = 0x%x\n", ccode);
  if (ccode != 0)
      return;
  while (connect.inUseFlag != 0)
      IPXRelinquishControl();
  if (connect.completionCode != 0)
      return;
  send.ESRAddress = NULL;
  send.fragmentCount = 2;
  send.fragmentDescriptor[0].address = &sendHdr;
  send.fragmentDescriptor[0].size = sizeof(SPXHeader);
  send.fragmentDescriptor[1].address = sendbuf;
  send.fragmentDescriptor[1].size = 7;
  SPXSendSequencedPacket(spxConnectionID, &send);
  packetsReceived = 0;
  while (packetsReceived < 10) {
      for (i = 0; i < NUM_BUFFS; i++) {
           if (receive[i].inUseFlag != 0) {
               if (receive[i].completionCode != 0) {
                   packetsReceived = 10;
               /* If we get an error, terminate */
                   break;
               }
               printf("Received: %s\n", buffer[i]);
               packetsReceived++;
           }
           SPXListenForSequencedPacket(receive[i]);
      }
      IPXRelinquishControl();
  }
  term.ESRAddress = NULL;
  term.fragmentCount = 1;
  term.fragmentDescriptor[0].address = &connHdr;
  term.fragmentDescriptor[0].size = sizeof(SPXHeader);
  SPXTerminateConnection(spxConnectionID, &term);
  while (term.inUseFlag != 0)
      IPXRelinquishControl();
  for (i = 0; i < NUM_BUFFS; i++)
      IPXCancelEvent(receive[i]);
}
END of FIGURE 4
This process may sound complicated, but everything happens transparently. As long as there are extra ECBs available, the application never knows they have been borrowed, since SPX puts them back in the exact same state they were in when they were pressed into service.

If the connection is established with the SPX watchdog enabled, the watchdog monitors the connection and notifies the application if the connection fails, even if the application is not currently sending data over the connection. This feature is useful for applications that start SPX connections, but use them infrequently. For simplicity, however, the example does not use the SPX watchdog.

After the listen ECBs have been posted, the connection ECB is then set up in much the same way the IPX send ECB was, except that this ECB has only one fragment: the SPX header. The destination network, node, and socket also are set the same way they were in the previous example.

SPXEstablishConnection() is passed a retry count of zero, indicating that you should use the default value for number of retries. This value is set in the workstation's NET.CFG file using the IPX RETRY COUNT parameter, which defaults to 20. The last zero passed in SPXEstablishConnection() indicates not to use the SPX watchdog. The SPX connection ID is returned as the third parameter. The SPX connection ID can be considered equivalent to the NetBIOS local session number.

Next, the sample code attempts to establish a connection. It polls the ECB's in use flag waiting for the event to complete. The IPXRelinquishControl() call is very important at this stage. If the code did nothing but sit in a tight loop, IPX and SPX would never get the chance to do any processing. IPXRelinquishControl() allows the IPX/SPX layer to get some work done.

Once the in use flag is set to zero, the example checks the return code to see if the attempt to establish a connection was successful. The code does not illustrate how to handle the various failure cases, but the most likely cause of a failure would be that the other side is not yet listening for a connection, just like in NetBIOS. After establishing the connection, packets can be sent to the remote station.

The SPXSendSequencedPacket() call requires much less information than its IPX counterpart. Since the connection is already established, all SPXSendSequencedPacket() needs is the SPX connection ID, an ESR address, and the fragment information.

After sending a packet, the example program waits for ten packets to arrive. When an ECB comes back, the example displays the data and then re-submits the ECB so that it can be used to receive a packet again. After receiving ten packets, it issues an SPXTerminateConnection() call to notify the other side that it is done.

The call to terminate the connection takes almost the same parameters that the establish connection call does, except that there is no need to fill out any information in the SPX header. Once the connection has been terminated, the pending listen ECBs must be cancelled. To do so, the example calls IPXCancelEvent(). Unlike most other ECB-related calls, IPXCancelEvent() does not return until the ECB has been cancelled so there is no need to poll the in use flag.

Event Service Routines

Event Service Routines (ESRs) serve the same purpose as the NetBIOS POST routines, but require a little more setup than the standard POST routine. Most ESRs are written in Assembly, although some call C functions.

Figure 5 shows a generic ESR that calls a C function after allocating its own stack. This is very important since the amount of free stack space (if any) at interrupt time is unknown, and any attempt by a C function to use the stack could result in memory corruption if the stack is overflowed. The only way to guarantee that this will not occur is to allocate sufficient stack space in the ESR.

FIGURE 5: Example Event Service Routine (ESR)

  .MODEL LARGE
  public       _ReceiveESRHandler
  extrn        _ProcessReceiveData:PROC
  .DATA
; The stack segment and pointer must be saved so that you can set up
; your own stack.
  stk_seg      dw 0                ; variable to store old stack segment
  stk_ptr      dw 0                ; variable to store old stack pointer
  stk_stk      dw 512 dup (0)      ; new stack of 1024 bytes in length
  stk_end      dw 0                ; the end of the stack
  .CODE
; @datasize is TRUE if the model is MEDIUM or LARGE and FALSE if the
; model is SMALL or COMPACT. Just modify the .MODEL ???? above for the
; model you want. ES/SI holds the seg/offset of the currently used ECB
; that ProcessReceivedData needs to process.
_ReceiveESRHandler PROC far
    mov        ax,DGroup
    mov        ds,ax
    mov        stk_seg,ss          ; Save the stack segment
    mov        stk_ptr,sp          ; Save the stack pointer
    mov        ss,ax               ; move the segment of new_stk into ss
    mov        sp,offset stk_end   ; move offset of new_stk to sp
IF  @datasize
    push       es                  ; push es if mem. model medium/large
ENDIF
    push       si
    call       _ProcessReceivedData
    mov        ss,stk_seg          ; Restore old stack segment
    mov        sp,stk_ptr          ; Restore old stack pointer
    retf
_ReceiveESRHandler ENDP
    END END of FIGURE 5
Figure 6 contains a code fragment demonstrating the use of an ESR. It receives ten SPX packets just like the example in Figure 3 does, but it uses an ESR instead of polling the in use flag. The assembly language routine from Figure 4 is declared as the ESR, and it in turn calls the C function ProcessReceivedData().

FIGURE 6: Using an Event Service Routine (ESR)

int packetCount = 0;
void ProcessReceivedData(ECB *ecb)
{
    packetCount++;
    printf("%s\n", ecb->fragmentDescriptor[1].address);
    SPXListenForSequencedPacket(ecb);   /* Re-issue the listen */
}
main()
{
    .
    . /* This code is identical to SPX setup code in Fig. 4, except */
    . /* for receive[i].ESRAddress line, which will be as follows: */
        receive[i].ESRAddress = (void (far *) () ) ReceiveESRHandler;
    .
    . /* The send ECB does not normally use an ESR. */
    .
    while (packetCount < 10)
        IPXRelinquishControl();
    .
    . /* Shut down connection, cancel ECBs */
    .
}
END of FIGURE 6
IPX and SPX may look a little more complicated than NetBIOS at first, but as soon as you begin using these protocols, you see how similar they really are. Using IPX/SPX requires slightly more effort, but the performance and compatibility gains when running under NetWare more than compensate. If you are thinking about becoming more familiar with IPX and SPX development, feel free to contact Novell's Developer Support group at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588.

NetWare System Calls & Protected Mode Programming

As the average user's desktop computer becomes more powerful, more and more software developers are deciding to develop protected mode applications to take advantage of the advanced features available in these newer, more capable machines. Developing protected mode NetWare applications that run under DOS can be challenging but the improvements in performance make it well worth the effort

For the most part, porting NetWare applications to protected mode is simple. The primary challenge in this process is in making the interrupt calls from protected mode to the NetWare Shell or VLM, both of which run in real mode. This article shows how to overcome this obstacle and highlights some of the features of protected mode.

Pros & Cons of Protected Mode

Developers working in protected mode enjoy some important advantages over their real mode competitors. In protected mode, you are not limited to 640K of application memory. In protected mode, 386 machines can access four gigabytes of memory, all of which is usable in a protected mode application. Protected mode applications can even take advantage of virtual memory, which substitutes disk space as extra memory so that applications requiring more than the available memory can run.

Another useful advantage of protected mode is improved performance. Protected mode applications can take advantage of 80386- and 80486-specific instructions which can perform tasks far faster than their real mode equivalents. Memory fetches also can be done faster and more efficiently under protected mode.

Until recently market share was the big concern for application developers resisting the move to protected mode programming. Many felt that they would lose too much market share by excluding older machines like 8086- and 80286-based computers. However, the baseline machine these days is 80386- based, and the market percentage of machines not capable of running in 80386 protected mode is dwindling.

At this point many developers ask, "With so many protected mode environments like OS/2 and MS Windows around, why should I be interested in writing protected mode applications under DOS?"

There are several reasons for writing protected mode applications under DOS. First of all, if a software development house has been engaged in real mode development, it has a substantial investment in DOS and running under a DOS extender provides the benefits of protected mode without having to learn a new operating system and set of development kits. Also, because of its simplicity DOS can be easier to develop for and in some cases provides higher performance than more advanced operating systems.

DOS Extenders

Running a protected mode application under a real mode operating system like DR DOS or MS DOS requires the use of a protected mode program loader called a DOS extender. This special piece of software places the processor into protected mode and provides some functions to manage memory and to allow access to standard DOS functions that would not normally be available from protected mode.

There are several popular DOS extenders on the market, including DOS/4G from Rational Systems, Phar Lap|386 Extender from Phar Lap, as well as many others.

Making Protected Mode System Calls

The basic procedure for making system calls in protected mode is the same as for real mode:
  • Allocate request and reply buffers
  • Fill the necessary parameters in them
  • Make the interrupt call
There are, however, some obstacles that must be removed to make this work from protected mode. First, when memory is allocated from protected mode it could be anywhere in the machine's available memory, but the NetWare DOS drivers can only work with memory blocks in the first megabyte of system memory. For this reason, you must ensure that request and reply buffers reside in the first megabyte.

Second, you must also perform some pointer arithmetic. The NetWare Shell and VLM expect far pointers and protected mode applications use a different memory addressing scheme (see Figure 8 below).

Third, making the interrupt call requires a special technique, since a protected mode application must switch to real mode to make the system call. To make the interrupt call, protected mode applications must:

  • Make the transition to real mode
  • Set up the real mode registers
  • Make the interrupt call
  • Switch back to protected mode.

Protected Mode Example

With this outline of the general procedure and the potential pitfalls, look at an example of a protected mode system call. The example program in this case is the Scan Bindery Object call (function E3h.) The example was created using WATCOM C/386 9.01 and was compiled for the DOS/4GW DOS extender, which is included with the compiler and is a variant of the DOS/4G extender. The DOS/4GW extender supports a subset of the DOS Protected Mode Interface (DPMI) specification version 0.9, which is a standard set of APIs used by protected mode DOS applications to access memory and DOS services. The example uses DPMI calls to allocate memory in the first megabyte, make the real mode system call, and then free the allocated memory.

Figure 7 displays the code that allocates a buffer in the first megabyte of memory, where DOS drivers can access it. It uses DPMI function 100h to allocate memory; this memory is always allocated at offset zero of a segment.

FIGURE 7: Allocating a Buffer with DPMI

int AllocDOSMemory(unsigned int size, int *segment, int *selector)
{
  union REGS regs;
  /* DPMI call 100h allocates a block of DOS memory.
     Note that no segment offset is returned - all blocks
     allocated begin at offset 0 of the segment. Memory
     is allocated in 16-byte paragraphs. */
  memset(®s, 0, sizeof(union REGS));
  regs.w.ax = 0x0100;
    /* Convert size from bytes to paragraphs. Be sure to add 1
     to the number of needed paragraphs after the bit shift
     so you don't allocate a block that is too small! */
  regs.w.bx = (size >> 4) + 1;
  printf("%u bytes requested. Allocating %d paragraphs (%d bytes)...\n",
     size, regs.w.bx, regs.w.bx * 16);
  int386(0x31, ®s, ®s);
  /* If carry flag is set, there was en error. */
  if (regs.w.cflag & 0x0001) {
     printf("\nAllocDosMemory DPMI call failed.  Return code = 0x%x\n",
        regs.w.ax);
     return(0);
  }
  *segment = regs.w.ax;
  *selector = regs.w.dx;
  return(1);
}
END of FIGURE 7
After properly allocating the request and reply buffers, you can fill the necessary fields to prepare for the system call. Figure 8 contains the code that allocates and fills the fields in the buffers. Then, Figure 8 shows the interrupt call using DPMI function 300h, which simulates a real mode interrupt. Notice that the far pointers for DS:SI and ES:DI consist of the segment returned from the DPMI function 100h call and an offset of zero. Once the call has been made, any information in the reply buffer can be processed, and then the memory for the buffers should be freed using DPMI function 101h.

FIGURE 8: Simulating a Real Mode Interrupt with DPMI

#define DWORD unsigned int   /* = real mode LONG. */
#define WORD  unsigned short /* = real mode INT. */
#define BYTE  unsigned char
static struct rminfo {
  long edi;
  long esi;
  long ebp;
  long reserved_by_system;
  long ebx;
  long edx;
  long ecx;
  long eax;
  short flags;
  short es, ds, fs, gs, ip, cs, sp, ss;
} rmi;
typedef struct {
  WORD  bufLen;
  BYTE  func;
  DWORD objectID;
  WORD  objectType;
  BYTE  nameLength;
  char  objectName[47];
} REQ_BUFF;
typedef struct {
  WORD  bufLen;
  DWORD objectID;
  WORD  objectType;
  char  objectName[48];
  BYTE  objectFlag;
  BYTE  objectSecurity;
  BYTE  objectHasProperties;
} REP_BUFF;
main()
{
  REQ_BUFF far *req_buff;
  REP_BUFF far *rep_buff;
  int req_seg, req_sel, rep_seg, rep_sel;
  char name[80];
  union REGS regs;
  struct SREGS sregs;
  if (!AllocDOSMemory(sizeof(REQ_BUFF),
      &req_seg, &req_sel))
      return(-1);
  if (!AllocDOSMemory(sizeof(REP_BUFF),
      &rep_seg, &rep_sel))
      return(-1);
/* Make 32-bit pointer from real mode request pointer */
  req_buff = MK_FP(req_sel, 0);
/* Make 32-bit pointer from real mode reply pointer */
  rep_buff = MK_FP(rep_sel, 0);
  req_buff->bufLen = sizeof(REQ_BUFF);
  req_buff->func = 0x37;
  req_buff->objectID = 0xffffffff;
  req_buff->objectType = 0xffff;
  printf("Name to search for: ");
  gets(name);
  _fmemcpy(req_buff->objectName, name, 47);
  req_buff->nameLength = min(strlen(name), 47);

  rep_buff->bufLen = sizeof(REP_BUFF);
  memset(®s, 0, sizeof(union REGS));
  memset(&rmi, 0, sizeof(struct rminfo));

  segread(&sregs);
  /* Set up real-mode call structure */
  rmi.eax = 0x0000e300; /* AH = E3 */
  rmi.ds = req_seg;  /* Request buffer pointer DS:SI */
  rmi.esi = 0;       /* (real mode segment:offset) */
  rmi.es = rep_seg;  /* Reply buffer pointer ES:DI */
  rmi.edi = 0;       /* (real mode segment:offset) */
  /* Use DPMI call 300h to issue the DOS interrupt */
  regs.w.ax = 0x0300;
  regs.h.bl = 0x21;
  sregs.es = FP_SEG(&rmi);

  regs.x.edi = FP_OFF(&rmi);

  int386x(0x31, ®s, ®s, &sregs);
  if (rmi.eax & 0x000000ff) { /* Return code in AL */
      printf("Scaseem complex, but it demonstrates the most
challenging situation you will encounter when developing in protected mode under DOS. The
benefits of protected mode fan Bindery Object call failed. Return
             code = %d.\n", rmi.eax & 0x000000ff);
      return(-1);

  }

  printf("Name: %Fs, ", rep_buff->objectName);
  FreeDOSMemory(req_sel);
  FreeDOSMemory(rep_sel);

}
END of FIGURE 8
Figure 9 contains the code for freeing memory allocated with DPMI function 100h. The handle returned by DPMI function 100h is simply passed to this function and the block is freed. This example demonstrates the use of one of the old INT 21h calls. You can apply these same techniques when using the calls in the new Client API for Assembly manual from the NetWare Client SDK v1.0d.

FIGURE 9: Freeing a Buffer with DPMI

int FreeDOSMemory(int selector)
{

  union REGS regs;

  /* DPMI call 101h frees a previously allocated block of DOS memory */
  memset(®s, 0, sizeof(union REGS));
  regs.w.ax = 0x0101;
  regs.w.dx = selector;
  printf("Freeing selector %d... ", selector);

  int386(0x31, ®s, ®s);

  /* If carry flag is set, there was en error. */
  if (regs.w.cflag & 0x0001) {
      printf("FreeDosMemory DPMI call failed.  Return code = 0x%x\n",
         regs.w.ax);
      return(0);
  }
  printf("Successful.\n");
  return(1);
}
END of FIGURE 9
The example discussed in this article may r outweigh the difficulty involved in making the transition from real mode development, and with this technique for making system calls from real mode, you are well on your way to being a successful protected mode NetWare developer.

TECHNICAL INSIGHTS:

NetWare SQL Index Optimization Update (NetWare SQL v3.00e)

In the September 1993 issue of Bullets (Vol. 5, No. 9, "Technical Insights"), "NetWare SQL Index Optimization Changes" discussed differences between how NetWare SQL v2.11 and v3.0 optimize a statement with a restriction like:
WHERE fld1 = 
  AND fld2 = 
NetWare SQL 3.00 (a-d) optimized on an index with either "fld1" or "fld2," but if both such indexes occurred, it used the index that was defined first in the table. With NetWare SQL v3.00e, when equivalent restrictions are present, and multiple indexes exist for those restrictions, the optimization algorithm chooses the index matching the first restriction, rather than the index that was defined first in the table.

In the above example, NetWare SQL would optimize on the index for "fld1," regardless of whether "fld1" or "fld2" is defined first in the table. This new scheme gives users more control over query optimization.

Apply patch level "e" to NetWare SQL v3.00 to obtain this new optimization. Patches are available in Novell's NOVLIB forum on CompuServe (Library 7, SQL30.EXE).

NetWare Client SDK 1.0e Libraries Released (NetWare Client SDK v1.0e)

The NetWare Client SDK v1.0e libraries have been uploaded to Library 6 of Novell's developer forum on CompuServe, NDEVREL. You may download the latest version immediately.

In addition to CLINEW.TXT, the file that lists the necessary files for the upgrade, You will find a file called CLIPRB.TXT that contains a list of known bugs in v1.0e. Five other .ZIP files in Library 6 supply all you need to bring the NetWare Client SDK up to date. The files are:

  • CLIDBC.ZIP - Borland DOS libraries
  • CLIDMC.ZIP - Microsoft DOS libraries
  • CLIINC.ZIP - header files
  • CLIOS2.ZIP - OS/2 DLLs & LIBs
  • CLIWIN.ZIP - Windows DLLs & LIBs
The following additional files have been uploaded to NDEVREL, Library 7:
  • CL3XDB.ZIP, contains the debug symbol version of CLIB.NLM v3.12d. This is the debug version of the QRM for 3.x.
  • CL4XDB.ZIP, contains the debug symbol version of CLIB.NLM v4.01b. This is the debug version of the QRM for 4.x.
Please note that you must have v1.0d of the SDK installed on your system, since the .ZIP files contain only files that have changed since the the NetWare Client SDK v1.0d was released.

Thunked Headers for NetWare Client SDK (NetWare Client SDK v1.0d)

New thunked headers for the NetWare Client SDK have been uploaded to Novell's NDEVREL on CompuServe (Library 1, HCSDK5.ZIP). Developers with appropriate access rights may also download this file from Library 6. These thunked header files allow developers to write 32-bit OS/2 applications using the 16-bit NetWare Client SDK.

Directory Service Update (NLM SDK v3.0)

Directory Service updates are available for NetWare 4.01 in Novell's NOVLIB forum on CompuServe (Library 1, DSPAT.EXE). These updates should be applied whenever any Directory Services or bindery issues are encountered under NetWare 4.01.

General Protection Faults in WIN-OS2 (NetWare Client SDK v1.0e)

An IPX/SPX application running in a WIN-OS/2 session using the NetWare OS/2 Requester v2.01 (or earlier) may encounter General Protection Faults (GPFs) when using Event Service Routines (ESRs) for transport function signals. A common example of ESR use is queuing up incoming ECBs on a receive. To access this queue in order to process the data, interrupts are disabled to avoid access violations. In a WIN-OS/2 session, the interrupt disable fails, causing a GPF when the queue is accessed while an ESR is in process.

As a temporary solution, avoid using ESRs in a Windows application to signal IPX/SPX function completion. Otherwise, incorporate the queues so they are not accessed while transport is active.

Missing Memory Managing Prototypes in ADVANCED.H (NLM SDK v3.0)

The NLM SDK v3.0 header ADVANCED.H no longer prototypes the functions AllocNonMovableCacheMemory() and FreeNonMovableCacheMemory(). The documentation lists these functions as being available, the link does not fail, and they are defined in CLIB as imports.

These methods of manipulating memory are no longer encouraged. Use the standard C language mechanisms, malloc() and free(), instead.

Status 95 & NetWare SFT III (NetWare Btrieve (NLM) v6.10x)

When the primary NetWare SFT III server is disabled and resynchronization is taking place, Btrieve may return a status 95 (Session not valid) while NetWare SQL may return status 2103 (NetWare SQL is not active on the requested server).

To prevent these status messages, increase the "IPX Retry Count" parameter in NET.CFG to a value of 40 or more. Raising this parameter prevents workstations from timing out and NetWare from terminating their IPX connections. In addition, always use the latest VLM drivers, (see "Current Shell and Requester Versions).

UFileFmtRead() with Format String (AppWare Foundation for Windows v1.70)

Using the AppWare Foundation function, UFileFmtRead() with a "%s" format specifier results in an application error. The following code segment reproduces this error:
nstr        aBuff[500];
:
nNumBytes = UFileFmtRead(pAccess,
                         idInFile,
                         "%s",
                         (pnstr)aBuff);
:
To avoid the application error, use UFileRead() and then scan the resulting buffer for strings using UDSscanf(). UDSscanf() returns a string up to the first white space character. However, when UDSscanf() encounters the new line characters ("\r\n"), the line feed ('\n') is returned in the output buffer for this function. For a workaround, see "UDSscanf() & White Space" later in this section.

Null Key Path & Status 44 (NetWare Btrieve (NLM) v6.1x)

With pre-6.x versions of Btrieve, the record manager returns a status 82 (Lost Postioning) when you attempt to perform a Get Direct (23) operation on a key with a null value in the record at the provided position. NetWare Btrieve v6.10b and v6.10c may return a status 44 (Null Key Path), instead.

Status 44 can occur when you define the key attribute to be manual or null ("all-segment" and "any-segment"). If your existing Btrieve application checks for status 82, consider rewriting your Btrieve application to check for status 44, as well.

AppWare Foundation and List Components (AppWare Foundation (all platforms))

There is currently no way to remove all items from a list with a single function call. An enhancement request to provide a suitable call has been submitted to Novell, but this function call is not available yet.

In the meantime, there are two ways to remove all items from a list box:

  1. Loop with a UMSG_REMOVE List Component message until all items are deleted (see Figure 10, Method 1).
  2. Destroy and recreate the List Instance (see Figure 10, Method 2). This method is not recommended due to application side affects, but included here as a possible solution.
FIGURE 10: Two methods to remove all items from a non-multi selection list instance
Method 1
:
{
    nint32  lCount = UMsgSend( pAccess, idList, UMSG_GET_COUNT, 0, 0 );
    for ( ; lCount > 0; lCount-- )
        UMsgSend( pAccess, idList, UMSG_REMOVE, UMSG_LOC_END, 0 );
}

:

Method 2
:
UInstDestroy(&Access, idList, UINST_DEFERRED);
idList = ListCreate(idWnd);
:
END of FIGURE 10

UDSscanf() & White Space (AppWare Foundation for Windows v1.70)

The UDSscanf() function scans 'nstr' buffers that may contain white space (spaces, tabs, line feeds and carriage returns). The function retrieves data from the buffer until it encounters white space characters. It skips the white space characters, according to the format string specified.

When UDSscanf() encounters new line characters ("\r\n"), the line feed ('\n') is returned in the output buffer. For example:

:
UDSscanf(pAccess,
         pnstrBuff,
         "%s",
         N_NULL,
         (pnstr)strPath);
:
'strPath' will contain the line feed '\n' character as the last character.

As a workaround, overwrite the '\n' character with a N_NULL constant. The line feed is in the last character position of the resulting buffer, so the following code sample will work:

nlen = UDStrLen(&Access,
                strPath,
                N_NULL) - 1;
strPath[nlen] = N_NULL;

SPXInitialize() Documentation Error (NetWare Client SDK v1.0d)

According to the documentation for Windows SPXInitialize(), both the 0x00 and 0xFF return codes indicate that SPX is not installed.

The return code of 0x00 is correctly documented, but the documentation for the 0xFF return code is in error. When SPX is not installed, zero is returned. SPXInitialize() returns 0xFF to indicate that SPX is installed, so 0xFF is the value returned if the function succeeds.

Drivers, DLLs & NetWare APIs (NetWare Client SDK v1.0e)

If a Windows application makes calls to NWNETAPI.DLL (from the NetWare C Interface for Windows SDK) or to NWCALLS.DLL (from the NetWare Client SDK) and NETWARE.DRV is not loaded, Windows returns the error:

Cannot find NETWARE.DLL

Windows also returns this error when the Program Manager is replaced with an application that makes NetWare API calls (with shell= in the [boot] section of SYSTEM.INI).

To prevent this error message, install the latest version of NWCALLS.DLL from the NetWare Client SDK v1.0e. If NETX is not loaded before Windows, or if NETWARE.DRV is unavailable for any reason, NWCallsInit() returns a status 0x88FF. This status replaces the message about NETWARE.DLL. Also, if you have replaced the Program Manager with an application that makes NetWare API calls, the new version of NWCALLS.DLL implicitly loads NETWARE.DRV, so no errors are returned.

API Produces Trap D in NWCALLS (NetWare Client SDK v1.0e)

NWGetPathFromDirEntry() under OS/2 causes (SYS3175, trap D) access violation, in NWCALLS. NWGetPathFromDirEntry() is required to parse data returned from NWScanFilesByConn2(). Using the parameters listed in the documentation, this API causes an OS/2 access violation (SYS3175, trap D) in NWCALLS.DLL.

There is no workaround at this time. Novell is investigating the cause.

UFileCreatePath() & the '\' Delimiter (AppWare Foundation for Windows 1.70)

The file component function UFileCreatePath() returns an error when the input path string does not end with the '\' character (Windows/DOS-specific path delimiter).

The code segment in Figure 11 appends '\' to the end of the path modifier to resolve this error. (NOTE: this workaround applies only to the Windows platform).

FIGURE 11: Appending '\' character to end of path modifier

nstr              astrPath[100];
:
UDStrCat(pAccess, astrPath, "\\", N_NULL);
idChildDir = UFileCreatePath(pAccess, idDir, astrPath);

:
END of FIGURE 11

Abend: Link Handle Returns Error (NLM SDK v3.0)

An NLM running on a server with a heavy load and a lot of sharable open files, may cause a server abend with the message:

Link handle returned an error

This situation has been reported, but there is no solution at this time. One workaround is to semaphore around all file opens in your NLM for your sharable files. However, this workaround may degrade performance.

New Btrieve Configuration Option (NetWare Btrieve (NLM) v6.10)

NetWare Btrieve v6.10x includes a new configuration option: "Perform Index Balancing." Index balancing results in Btrieve files that have more entries on individual key pages, increasing access time. However, it may decrease performance on Insert, Update and Delete operations due to the extra work required to balance the indexes.

The NetWare Btrieve v6.10 Setup Utility (BSETUP.NLM) allows you to set this option if you want all newly created files to have balanced indexes.

However, the Btrieve configuration option of the NetWare SQL Setup Utility (NDBSETUP.NLM) does not include this new option. NetWare SQL should use BSETUP to configure Btrieve rather than NDBSETUP to enable the Index Balancing option.

NetBIOS Abend Error Messages (NetBIOS for DOS v3.14)

Following is a list of the most common NetBIOS abend messages, and their explanations:
  • NetBIOS ABEND - IPX block already on free list.
    This message returns when IPX calls the NetBIOS Event Service Routine (ESR) more than once for a single Event Control Block (ECB). This error is fatal due to the contention over the memory resource (the ECB).
  • NetBIOS ABEND - Internal stack corruption.
    The amount of stack space used by applications is limited. Usually, this error is caused by an application that is attempting to interface with NetBIOS. The application is not switching stacks when it is called by the NetBIOS POST routine.
  • NetBIOS ABEND - FreeIPXBlock already on free list
    This error is caused by a somewhat common problem in LAN drivers that Novell NetBIOS identifies as a fatal "FreeIPXBlock" error message.
NetBIOS has a local pool of IPX ECBs for sending data, and another pool of ECBs and attached data buffers (DOS only) for receiving data. The ECBs from the receive pool are sometimes used to echo replies and packet acknowledgments; otherwise they only receive packets. ECBs from the send pool are either attached to a Network Control Block (NCB) or are kept on a linked list of available send ECBs.

A NetBIOS routine called FreeIPXBlock places newly available send ECBs back onto the list of available send ECBs. The routine checks to see if a previously submitted NCB was unable to locate an ECB, and performs consistency checks on the ECB address, including a check to see if the ECB is on the available list.

When IPX cancels a packet in the process of being sent, the ESR for the ECB must not be called, and IPX depends on the LAN driver to not call IPXHoldEvent. Unfortunately, some LAN drivers always call IPXHoldEvent on a transmit complete interrupt when an ECB is at the head of its send queue. If a second ECB is on a send queue when the transmit complete interrupt occurs for a cancelled ECB, the second ECB's ESR is called prematurely, and then called a second time when the second ECB's send had completed.

Set a flag when canceling an ECB that has a transmit complete interrupt pending, and test for the absence of that flag before deciding to call IPXHoldEvent in the transmit complete interrupt service routine.

New CLIB.NLM Posted on NDEVREL (CLIB.NLM for NetWare 3.x and 4.x)

An update to CLIB.NLM for both NetWare 3.x and NetWare 4.x is available on Novell's NDEVREL forum on CompuServe (Library 7, LIBUP1.EXE). The latest version of AFTER311.NLM is also included.

Configuring Btrieve for Windows (Btrieve for Windows v5.10)

Any configurations or initialization parameters for WBTRCALL.DLL v5.10 and WBTRLOCL.DLL must be set in WIN.INI. Although NOVDB.INI file contains a section for Btrieve, this configuration is never used by Btrieve for Windows.

Simulating SDF Files with the Report Option (Xtrieve PLUS v4.11)

The Standard Data Format (SDF) used by the Xtrieve PLUS Translate option consists of one line per record. The fields of each record are separated by commas, and optionally, double quotes can be placed around string fields. Each line ends with a carriage return/line feed (hex 0D 0A), and an end-of-file marker (hex 1A) must be after the last line.

This format is automatically generated when using the "Translate - to SDF" option. However, an Xtrieve PLUS Report can be designed to simulate SDF format. Doing so allows the user to utilize groups and summaries in the resulting output. However, the report option does not put an end-of-file marker in the resulting output file. As a result, translating in such a file produces the error:

Translate File Not in Recognized Format

after translating in all the data. In addition, if there is more data than will fit on one page, the report option will put a form feed character (hex 0C) between pages of the output. This character will abort the "Translate" procedure.

To make the report output compatible with the "Translate - from SDF" option, add a report summary constant of "@hex1A" to the report. Doing so places the end-of-file marker after all the data. Also, set the "Switches/Form Feed" option to "No" to avoid the page break characters.

This switch may cause blank lines to be printed to the file at the end of the report to fill out the last page, but the lines will be after the summary constant, and will be ignored by the Xtrieve PLUS "Translate" option.

Login to Print Server API Causes GPF if Called Repeatedly (NetWare Client SDK v1.0d)

NWPSComLoginToPrintServer() causes a General Protection Fault (GPF) in NWPSRV.DLL if the function is called repeatedly.If NWPSComAttachToPrintServer(), NWPSComLoginToPrintServer(), and NWPSComDetachFromPrintServer() are called repeatedly in a loop in a Windows application, NWPSComLoginToPrintServer() will cause a GPF in NWPSRV.DLL. The number of iterations required to cause the GPF is random, ranging from 100 to 16,000 in preliminary testing. This problem exists with the NWPSRV.DLL from the NetWare Client SDK v1.0d (5-14-93).

Engineering is investigating the cause, but there is no solution at this time.

Error 3 from DosOpen() Named Pipe with NETX.EXE (NetWare Client SDK v1.0e)

Under OS/2, a private Virtual DOS Machine (VDM) requires that NETX.EXE be loaded. If the current working directory is a network drive, NETX is unable to parse the UNC name of the Named Pipe and will cause DosOpen() to return an error code 3:

ERROR_PATH_NOT_FOUND

When a local drive is used, or the VDM has global network resources, the call will be successful.

There is no solution at time time. Engineering is investing the cause.

Invalid iCount Parameter with xDescribe (NetWare SQL v3.00e)

The NetWare SQL v3.00e patches address a situation in which invalid status codes are returned by the relational primitives xOrder, xDDField, xDDIndex and xDDView if an invalid iCount of (-1) is specified. After you apply the v3.00e patches, NetWare SQL returns a status 354 (Invalid iCount Parameter)in these cases.

However, the relational primitive, xDescribe, also has an iCount parameter, and (-1) is a legal value for this primitive, indicating that as many field descriptions as will fit in the data buffer should be returned. With the v3.00e patches applied, if you attempt to call xDescribe with:

iCount = -1

the NetWare SQL requester (NSREQ[S].EXE for DOS and Windows, XQLCALLS.DLL for OS/2) will erroneously return status 354. To avoid the status 354 with xDescribe, use the requesters from the 3.00d patch release.

Invalid Cursor Error & Stored Statements (NetWare SQL v3.00e)

Executing the following stored statement two times causes NetWare SQL to return a status 202 (Invalid Cursor) on the second execution:
CREATE PROCEDURE testsp AS
START TRANSACTION
UPDATE 
  SET f1 = f1 + 1
SELECT * FROM 
COMMIT WORK
NetWare SQL can return this status whenever the first statement in a stored statement is not a SELECT, INSERT, UPDATE, or DELETE operation. This situation will be resolved in the next quarterly patch release.

Documentation Error: Status 849 (NetWare SQL v3.00e)

The NetWare SQL v3.00 documentation for status 849 erroneously states:

"If the problem persists, contact Novell by phone, fax, or NetWire on CompuServe (as instructed in "Where to Get Help" in "About This Manual") regarding a possible patch to increase the size of the buffer."

This instruction was for the previous version of NetWare SQL, v2.11. No patch is available for v3.00x. If you are receiving this error, contact Novell Developer Support with an example of the statement causing the error.

Using Visual Basic Controls with Btrieve (Btrieve for Windows v5.10)

When using data-aware controls in a Visual Basic application with Btrieve for Windows, Visual Basic uses a file called BTRV110.DLL. A section of the VB.INI file tells Visual Basic where to find this file, for example:
[Installable ISAMs]
btrieve=c:\windows\system\btrv110.dll
This section in the VB.INI file is only used when running the application in the Visual Basic development environment. When compiling the application into an executable file and running it outside the Visual Basic environment, the following error may be returned:

Couldn't find installable ISAM

When running the executable, an .INI file with the same name as the executable must exist in the Windows directory, and it must contain a section pointing to the BTRV110.DLL, just like the entry in VB.INI. For example, if the application is called BTRDATA.EXE, a BTRDATA.INI file must exist in the Windows directory with the appropriate [Installable ISAMs] section.

Apply Patches to NetWare SQL v3.00 (NetWare SQL v3.00e)

If you load an unpatched copy of NetWare SQL v3.00 on a NetWare 4.01 server, the server will abend. This compatibility problem is solved by upgrading NetWare SQL v3.00 to the latest revision (v3.00e) by applying patches.

Patches are available in Novell's NOVLIB forum on CompuServe (Library 7, SQL30.EXE).

Update in Stored Statements (NetWare SQL v3.00e)

Executing the following statement produces a status 221 (Invalid Syntax for Expression or Restriction):
CREATE PROCEDURE test AS
UPDATE  SET f1 = (f1 + 1)
SELECT * FROM 
Any update statement within a stored statement that ends with a parenthesis will fail during the CREATE procedure attempt. As a workaround, add an additional operand to the end. For example: (f1 + 1) + 0.

The problem has been reported and a fix is scheduled for the next patch release of NetWare SQL.

Data Buffer Length & Get Next Extended (NetWare Btrieve (NLM) v6.x)

The documentation for NetWare Btrieve v6.x states that the length of the Data Buffer should be set to:
max(sizeof(in-going structure),
    sizeof(out-going structure))
This description refers to the Data Buffer Length parameter sent on the Btrieve call, not the first two bytes of the descriptor in the Data Buffer.

Set the first two bytes of the descriptor in the Data Buffer to the exact length of the in-going structure. Set the Data Buffer Length parameter to the larger of the in-going structure length and the out-going structure length.

Xtrieve PLUS v4.01a Reports Cannot Be Recalled by v4.11x (Xtrieve PLUS v4.11x)

Xtrieve PLUS 4.01a allowed different views to use the same report layout. The only prerequisite was the same field names, same data types, and data lengths. This caused problem for views that had the same field names but not the same data types. To avoid confusion, Xtrieve PLUS v4.11 enforces the rule "one view to one layout." Because of this rule, some Xtrieve PLUS v4.01a reports cannot be recalled in v4.11

Before converting to Xtrieve PLUS v4.11 from v4.01a, examine your reports to make sure that all reports follow the "one view to one layout" rule. If a layout is used with multiple views, it should be recalled with each view and then stored individually with a new report name.


NIBBLES AND BITS

Fast Answers to Common Questions

NetWare

TIP: Patches for the NetWare v3.11 operating system are available on Novell's NOVFILES forum on CompuServe (file: 311PTD.EXE). Each of these patches are designed to resolve a very specific problem. However, these patches are not tested as a complete set. Therefore, when you try to install a patch to NetWare, select only the specific patch for your problem and do not indiscriminately install all of the patches in 311PTD.EXE. Doing so may cause new problems for your operating system.

Q - How can I get the latest release of the VLM driver?

A - VLM v1.10 is available on Novell's NOVFILES forum on CompuServe (file: DOSUP9.EXE), along with NETX and the latest ODI drivers.

NetWare Client SDK

TIP: The NetWare Client API for Assembly documentation is now available. You can obtain a copy if:
  • You buy the NetWare Client SDK
  • You buy an upgrade to the NetWare Client SDK from the NetWare C Interface for (DOS, MS Windows, OS/2, or System Calls for DOS, or
  • You already own a copy of the NetWare Client SDK (a free upgrade will be mailed to you).
Q - Where can I find the latest updates for TLI?

A - The latest updates for TLI, including new STREAMS, TLI, IPXS and SPXS NLMs, can be found on Novell's NOVLIB forum on CompuServe (Library 1, STRTL2.EXE). Also included is an update to the SPXFIX1.NLM called SPXFIX2.NLM.

NetWare C Interface for Windows

Q - What might cause IPXInitialize()to return an error 240 under MS Windows?

A - Error 240 from IPXInitialize() indicates that IPX is not installed. Under MS Windows, this problem can take two forms. In the first case, no network activity is possible under either DOS or MS Windows. This is usually due to the IPX or IPXODI TSR not being loaded. In the second case, the user can access network functions from DOS, but not in MS Windows. In this case, the problem is with Windows applications not finding VIPX.386 (MS Windows in enhanced mode) or TBMI2.COM was not loaded before starting MS Windows in standard mode.

If you are running MS Windows in enhanced mode, do not load TBMI2.COM. In addition, the network= line in the [386enh] section of the SYSTEM.INI file should include VIPX.386. Finally, VIPX.386 should be present in the MS Windows \SYSTEM subdirectory.

When running MS Windows in standard mode, load TBMI2.COM before starting MS Windows.

NetBIOS for DOS v3.14

Q - How many sockets does the NetBIOS emulator open and which ones are used?

A - NetBIOS only opens one socket (455h) and uses this socket for all NetBIOS traffic.

NetWare SQL

Q - How do I use single quotes in a string field? After creating a simple table:
     create table test
       (f1 int , f2 char(10))
and attempting to insert a record:
     insert (3,'a'bc')
NetWare SQL returned the error "Unmatched quotes."
A    The following insert statements all work correctly:

     insert into test values
       (1,'O"Leary')
     insert into test values
       (2,'o'hara')
     insert into test values
       (3,'a''bc')
The following records result from these insert statements:
     1,O"Leary
     2,o`hara
     3,a'bc
The following select statement will retrieve the last record:
     select * from test
       where f2 = 'a''bc'
The following select statement will retrieve the first record:
     select * from test
       where f2 = 'O"Leary'
The trick is to precede the first single quote with another single quote. With the apostrophe and double quote, there are no problems.

NetWare Btrieve (NLM)

Q - If BTRIEVE.NLM v6.1x is configured with the -d option to force Btrieve to create files in v5.x format, what would happen if v6.1x file flags like:
  • Index Balanced File
  • Duplicate Pointers
  • Key Number Specified
  • VATs used in File

are set at creation time?

A - These bits are ignored if you load NetWare Btrieve v6.1x with -d. No errors will be returned. For more information about these new file creation options, see the Btrieve Programmer's Manual included with the Btrieve Developer's Kit Supplement.

Q - How much real memory is allocated by WBTRCALL.DLL v6.10x to communicate with the Btrieve DOS requester, BREQUEST.EXE?

A - WBTRCALL.DLL is a DOS Protected Mode Interface (DPMI) and allocates real mode memory according to the following formula:

      DOSPARMBLK
    + maxDataLen
    + POSBLK_SIZE
    + KEYBUF_SIZE
    + 2 bytes
where:
  • DOSPARMBLK is 28 bytes
  • maxDataLen is defined by /d switch specified on the BREQUEST.EXE command line
  • POSBLK_SIZE is 128 bytes
  • KEYBUF_SIZE is 255
Q - NetWare Btrieve returns a status 12 (File Not Found) on an Open call when using NETX under NetWare v4.x. What should I do?

A - NETX is causing the wrong path to be passed to BREQUEST. Use VLMs instead of NETX under the NetWare v4.x operating system.

Q - NetWare Btrieve returns a status 94 (Permission Error) when I try to access the record manager on a NetWare Runtime Server. BREQUEST is loaded with /C:1, SUPERVISOR,SUPERVISOR_PW. What should I do?

A - When accessing Btrieve on a Netware Runtime Server, the user must have a username other than SUPERVISOR. The SUPERVISOR username and password cannot be used on this server to access NetWare Btrieve.

Load BREQUEST with /C:1,USERNAME,PASSWORD

Q - Why doesn't BREBUILD rebuild NetWare Btrieve v6.x files?

A - You should use BREBUILD in cases where you are converting data files from v5.x format to a v6.x format. Once the files are in v6.x format, they are considered to be "rebuilt." If the file shows signs of data corruption, reload the data into a new file. Steps for reloading data are described in the NetWare Btrieve 6.10c README file.

Q - What does the error "BSPXCOM -Bad Connection ID on send" mean?

A - It means that Btrieve has sent a message to a workstation that has been timed out by the NetWare Watchdog. To rectify the problem, increase the SPX timing parameters on both the server and the workstation. Specifically, increase the SPX WATCHDOG ABORT TIMEOUT, SPX ACK WAIT TIMEOUT, and SPX WATCHDOG VERIFY TIMEOUT parameters on the server where BSPXCOM.NLM is loaded. On the workstation, raise the SPX ABORT TIMEOUT, SPX LISTEN TIMEOUT, and SPX VERIFY TIMEOUT parameters in the NET.CFG file.

Q - How can I direct output to a text file from an NLM (such as BUTIL.NLM) running at the server console?

A - To direct output to a text file from an NLM, enter the command:

     LOAD BUTIL -STAT BTRFILE
      (CLIB_OPT)/>sys:\output.txt
This command is case-sensitive with no spaces.

ODI Protocol Stack Developer's Kit

TIP: The Protocol Stack Developer's Kit and all other DeveloperNet Labs documentation is available via anonymous FTP to site FTP.NOVELL.COM (130.57.11.140). A directory off the root called \DEV_DOCS contains sub-directories for each SDK. The Protocol Stack Developer's Kit is in the sub-directory, \PSTACKS. To obtain a copy of The ODI Protocol Stack Developer's Kit:
  • Connect via FTP to FTP.NOVELL.COM (130.57.11.140)
  • Login as user ANONYMOUS, password (your email id... e.g., jdoe@xyz.com)
  • Change directory to DEV_DOCS/PSTACKS
  • Copy (get) the documentation to a local directory
  • Print the documentation (PostScript format)

MAD'S COLUMN

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

It seems like the January issue of every magazine, periodical or news-letter takes one of two angles: the year in review or next year's forecast. While both serve as a point of reference, I wonder about their necessity.

I know I personally do not care how much Oprah weighs, has weighed or will weigh in 1994. On the other hand, I care very much about the outcome of the Cowboys vs "Unknown Contender" in the 1994 Superbowl game. Predictions on who the contender is or what the point spread will be are non-essential. I guess I like to know the players but determine my own outcome.

I think the world of developers is much the same. There are a lot of good teams out there. Some have better offense. Some better defense. Some a very skilled "special" team. Yet, even in these teams we tend to forget the somewhat overlooked team of sidepeople: coaches, recruiters, physical therapists, equipment managers, travel arrangers. Each with a unique skill at doing their specific job well.

To underrate any one job is to imagine the Dolphins playing Thanksgiving Day in Dallas in typical Floridian clothing. Brrrrr.

For my New Year's column I'd just like to thank you, Novell's developers. I hope that we have been as good a team for you a you have been for us. So, it's a quick glimpse over my right shoulder as I and the rest of the Novell Developer Support group charge into the future.

Mad Poarch
Director
Developer Support/Services


DEVELOPER EDUCATION:

Available Novell Developer Education Courses

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

CURRENT PATCHES FOR NOVELL DEVELOPMENT TOOLS

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

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

Novell Professional Developers' Program members can obtain updated NetWare API SDK components from Novell's NOVDEV forum on CompuServe. For more information on Novell developer programs contact Novell at 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588.

Novell Developer Relations Automated Fax System

A document describing available patches and other files and their location on CompuServe is available through Novell Developer Relations Automated Fax System (AFS). This system can provide you other useful information as well.

To use the AFS, call 1-800-RED-WORD (1-800-733-9673) or 512-794-1796 from a 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
Articles: Matt Pinsonneault

Contributors: Gaurang Amin, Linda Anderson, Vitek Boruvka, Belinda Brock, Neda Eslami, Kumar Gaddam, Jack Gumaer, Laura Heater, Geert Lingier, Ken Lowrie, Clint McVey, Jeff Nelson, Chris Ojeda, Matt Pinsonneault, Jose Pruneda, Vicki L. Smith, Michael A. Spano, Glenn Stephens, John E. Stewart, Shiva E. Waldecker, Brenda Wallace, and Hans Wieser

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, DR DOS, Btrieve, XQL and LANalyzer are registered trademarks; LAN WorkShop, NetWare SFT III, NetWare Loadable Module, NLM, Global MHS, NetWare MHS, NetWare System Calls for DOS, NetWare Runtime, NetWare SQL, NetWare Btrieve, Report Executive, NetWare Asynchronous Services Interface (NASI), NetWare Management System, Xtrieve PLUS, DeveloperNet Labs, UnixWare, AppWare, AppWare Foundation, ALM, Visual AppBuilder, IPX, and MacIPX are trademarks; and NetWire and Professional Developers' Program are service marks of Novell, Inc. IBM and OS/2 are registered trademarks, and NetBIOS and SAA are trademarks of International Business Machines Corporation. Microsoft is a registered trademark and Windows and Visual Basic are trademarks of Microsoft Corporation. Macintosh is a registered trademark of Apple Computer, Inc. CompuServe is a registered trademark of CompuServe Corporation. NFS is a registered trademark of Sun Microsystems, Inc. UNIX is a trademark of UNIX Systems Laboratories, Inc. in the USA and other countries. UNIX Systems Laboratories is a wholly-owned subsidiary of Novell, Inc. WATCOM is a registered trademarks of WATCOM Systems, Inc.


NOVELL OFFICES

Novell, Inc.
Corporate Headquarters
122 East 1700 South
Provo, Utah 84606-6194 USA
Tel +1-801-429-7000
FAX +1-801-429-3944


Novell Australia
Level 2, 2 Help Street
Chatswood NSW 2067
AUSTRALIA
Tel +61-2-413-3077
FAX +61-2-413-3116
Novell Benelux
Excelsiorlaan 13
B-1930 Zaventem
BELGIUM
Tel +32-2-725-0200
FAX +32-2-725-0311
Novell Brazil
Av. Ribererao Preto 13012
Sa Paulo
BRAZIL
Tel +55-11-284-4866
Novell Canada
3100 Steeles Avenue E.
Suite 500
Markham, ONT L3R 8T3 CANADA
Tel +1-416-940-2670
Novell France
Tour Anjou
33 Quai De Dion-Bouton
F-92814 Puteaux Cedex
FRANCE
Tel +33-1-4775-0909
FAX +33-1-4778-9472
Novell Germany
Willst tter Strasse 13
D-4000 D sseldorf 11
GERMANY
Tel +49-211-59730
FAX +49-211-5973-250
Novell Hong Kong
China Resources Bldg.
#4601-5
26 Harbour Rd.
Wanchai
HONG KONG
Tel +852-8-272223
FAX +852-8-276555
Novell India
Onward Novell Software (I) P. Ltd.
Kriston House,
Saki-Vihar Rd.
Saki-Naka,
Bombay 400 072
INDIA
Tel +91-22-836-2097
FAX +91-22-832-3623
Novell Italy
Via San Vittore 40
20123 Milan
ITALY
Tel +39-2-4801-3554
FAX +39-2-4801-3594
Novell Japan
Toei Mishuku Bldg.3F
1-13-1 Mishuku
Setagaya-ku, Tokyo 154
JAPAN
Tel +81-3-5481-1161
FAX +81-3-5481-1855
Novell Korea
Donghwa Building 13F-5
25-5, Youido-dong
Youngdeungpa-Ku
Seoul
KOREA
Tel +82-2-786-1141
FAX +82-2-786-1140
Novell Mexico
Insurgentes Sur 1160
4­Piso, Col. Del Valle
Mexico D.F. 03100
MEXICO
Tel +52-5-559-1566
FAX +52-5-575-6578
Novell South Africa
P.O. Box 1840
Rivonia 2128
SOUTH AFRICA
Tel +27-11-884-4404
FAX +27-11-884-4472
Novell Singapore
Level 36, Hong Leong Bldg.
16 Raffles Quay
Singapore 0104
SINGAPORE
Tel +65-322-8503
FAX +65-321-8966
Novell Spain
Paseo Castellana, 40bis
E-28046 Madrid
SPAIN
Tel +34-1-577-4941
FAX +34-1-577-9053
Novell Sweden
Farogaten 7
16440 Kista
SWEDEN
Tel +46-8-703-2350
FAX +46-8-703-9434
Novell Switzerland
vor Ort 21
CH-8104 Weiningen-Zurich
SWITZERLAND
Tel +41-1-750-0504
FAX +41-1-750-0957
Novell Taiwan
2F2 383 Jen Al Road
Section 4, Taipei
TAIWAN, R.O.C.
Tel +886-2775-3183
FAX +886-2731-2284
Novell United Kingdom
Novell House
London Road
Bracknell, Berkshire
RG12 2UY
UNITED KINGDOM
Tel +44-344-724-000
FAX +44-344-724-001