*********************************************
*********************************************
Professional Development Series
B  U  L  L  E  T  S
*********************************************
April 1992
Volume 4, Number 4
*********************************************
*********************************************


*********************************************
*********************************************
MAD'S COLUMN
*********************************************
*********************************************

Hello and welcome to the April 1992 issue of Bullets!

Last month, I found it interesting that within one week two
trade magazines stated that NLM development is difficult. A
little later, a Novell VP asked me if writing an NLM was
hard. Two questions popped into my head. "How do you define
'hard?'" and "Is this a trick question?" I mean, NetWare is
the best platform for running high-performance applications,
a good compiler and excellent documentation are available,
and Novell offers specialized training for NLM development.

I posed the question to several folks in Developer Support
with varying levels of NLM experience. During that same week,
our Education Department was presenting the "Developing NLMs"
class on site. At the end of the course, I asked the students
(still new to NLM development) to comment on the statement:
"Writing an NLM is easy!"

The answers were not as varied as you might think. There were
two predominant answers:

1.   Writing a simple NLM is easy.

2.   Writing all multithreaded applications takes a certain
     mindset, but it is comparable to writing a Windows or
     OS/2 multithreaded program.

And one common concern:

*    Resolve the compatibility issues between NetWare
     versions and API sets.

The two-part article in this and next month's issues offer
our observations and commentary on this subject.

Happy_Programming!

Mad Poarch

Director
Developer Support/Service



*********************************************
*********************************************
ARTICLES:
NLMs: From "Hello World" to World-Class Computing
(Part I)
*********************************************
*********************************************

NetWare 3.x is a 32-bit operating system designed with an
open architecture that allows third-party developers to add
specialized enhancements to the operating system by writing
NetWare Loadable Modules (NLMs) and distributed applications.
NetWare 3.x was designed with NLM technology in mind, but
many developers still do not take full advantage of the
architecture, believing that NLMs are difficult to design.
This two-part article compares the procedures and strategies
for designing DOS applications with those for designing NLMs
and discusses multithreading issues. It also uses a working
distributed application to explain special considerations
associated with NLM development.

Comparing Environments

Most compilers include the familiar example program, "Hello
World." Below is a version of "Hello World" that works with
nearly any C language compiler:

  #include <stdio.h>
  main()
  {
    printf("Hello World");
  }

Next is a version of "Hello World" that will run as an NLM.

  #include <stdio.h>
  main()
  {
    printf("Hello World");
  }

If you see a difference between the two examples, it is
probably a typo!

Compiling an NLM is very straight-forward; in fact, the
process is identical to compiling applications for DOS, OS/2
and Windows. The WATCOM C/386 compile line for the "Hello
World" example for NLMs and an explanation of each parameter
is displayed below:

   wcc386 /3s /Zp1 /d2 hello.c

/3s  Use stack-based parameter passing instead of
     register-based
/Zp1 Byte-align structures
/d2  Include full debug information

To produce an executable load module, you would issue the
command:

   wlink @hello.lnk

HELLO.LNK is the ASCII file that contains the linker
definition file. Linker definition files contain directives
for the linker and provide everything needed to produce a
load module for a particular environment.

Since WATCOM C/386 also supports Extended-DOS and OS/2 v2.0,
and both environments use the flat memory model, you could
link HELLO.OBJ into an NLM, a protected-mode DOS application,
or an OS/2 v2.0 application! The WATCOM Linker, WLINK, is the
tool that creates the load module for each environment. For
the "Hello World" NLM, you would use the linker definition
file displayed in Figure 1. The end result of this process is
an NLM that can be loaded and run on the server with the
command, "load hello."

*********************************************
Figure 1: Linker definition file for "Hello World"

   form    novell nlm 'Hello World'
   name    hello
   option  caseexact, nod, stack=8k, map
   debug all debug novell
   file prelude, test
   module clib
   option screenname 'Hello World Screen'
   option threadname 'Hello World '
   import @clib.imp

End of Figure 1
*********************************************

Adding Functionality

Obviously, creating a NetWare-Aware application requires much
more than a simple printf call. The NetWare 3.x platform
provides an extensive set of APIs that you can use to create
NetWare-Aware applications. First, you must understand the
differences between DOS applications and NLM applications
which use the NetWare APIs. BINDSCAN, a utility provided with
the Network C for NLMs SDK (Software Developer's Kit), is a
useful example for demonstrating these differences. BINDSCAN
scans the bindery and displays objects, their properties, and
associated property values. A quick examination of the source
code for BINDSCAN reveals three APIs that are not supported
in the DOS environment:

*    PressAnyKeyToContinue()
     Displays message and waits for a key
*    HideInputCursor()
     Turns off the cursor
*    DisplayInputCursor()
     Turns on the cursor

Correspondingly, to alter BINDSCAN to run under both DOS and
NetWare, you would make the changes listed in Figure 2.

*********************************************
Figure 2: Required changes for BINDSCAN

#if !defined(__386__)
       #define PressAnyKeyToContinue()                   \
               {                                         \
                printf("\nPress any key to continue\r"); \
                getch();                                 \
               }
       #define HideInputCursor()
       #define DisplayInputCursor()
#endif

End of Figure 2
*********************************************

To build an NLM version, run the WMAKE utility using the
original  makefile. Everything you need to build a
NetWare-Aware, 16-bit DOS application is included with
Novell's Network C for DOS product. To build the DOS version,
use the following command line:

   wcl /zp1 /d2 bindscan.c snit.lib

The WCL utility compiles the BINDSCAN program and then
invokes WLINK to link the resulting .OBJ file into an
executable load module. If you perform each of these tasks
and run the DOS and NLM versions against your own object name
on the same server, the DOS and NLM versions will produce
identical output.

In the discussion on building the DOS version of BINDSCAN,
the example linked in a static library called SNIT.LIB. This
library contains all of the NetWare APIs for the DOS
environment. In fact, the DOS version also requires that you
link it with another static library, CLIBS.LIB. This library
contains APIs for WATCOM's implementation of the standard C
library.

In the NLM environment, a dynamic library called CLIB.NLM is
provided with NetWare 3.x. This library provides most of the
APIs available to NLM developers.  (See sidebar: The NetWare
C Runtime Library NLM.) This is not to say that
statically-linked libraries can not be used in the NLM
environment, because they can. A utility called WLIB, an
object librarian included with the Network C for NLMs  SDK,
allows you to create static library files which can be linked
in with WLINK.

*********************************************
Sidebar:  Novell's C Runtime Library NLM

Novell's C Runtime Library NLM (CLib) is included with
NetWare 3.x and contains all of the functions used by NLMs
created with the Network C for NLMs SDK. This NLM library
exports over 600 fully-reentrant APIs that can be used by
many NLMs at once. CLib contains an ANSI-compliant API set,
as well as several other groups of APIs including NetWare
APIs, an execution thread API, a library API and an
implementation of the POSIX APIs. Following is a table of
selected APIs, showing which APIs are supported in each
environment:

API                 DOS       NLM       OS2

printf              X         X         X
open                X         X         X
fopen               X         X         X
signal              X         X         X
exit                X         X         X
sprintf             X         X         X
getch               X         X         X
strcmp              X         X         X
malloc              X         X         X
BeginThread         na        X         1
SuspendThread       na        X         2
EnterCritSec        na        X         3
CreateBinderyObject X         X         4
ScanProperty        X         X         5

1   Function called '_beginthread' in OS/2 C Library.
2   Function called 'DosSuspendThread' in OS/2 C Library.
3   Function called 'DosEnterCritSec' in OS/2 C Library.
4   Function called 'NWCreateBinderyObject'
5   Function called 'NWScanProperty'

Most of the API calls are the same, regardless of
environment. The thread APIs (not supported under DOS) are
very similar for both OS/2 and NetWare (the only difference
is API name). Another difference between the current
implementations of the NetWare APIs is that the OS/2 APIs are
prefixed with 'NW', and may have different types for the
parameters.

End of Sidebar
*********************************************

Multithreaded Applications

Each execution path through the application code is referred
to as a thread. Under DOS, you are usually concerned with
only a single thread of execution. Some single-threaded
applications are certainly viable NLM candidates. However, as
network computing becomes more prevalent, many developers are
interested in creating more complex applications containing
multiple threads of execution and requiring communication
between workstation applications and a server application.

Both OS/2 and NetWare provide the capability to create
multithreaded applications. Developing multithreaded
applications for either of these environments poses similar
challenges. Some differences between these platforms surface
when programming for factors like preemption. Preemption
requires you to lock down data structures, since a thread may
be suspended at any time. If the update of one or more data
structures must be performed as a canonical operation, you
must provide synchronization to prevent corruption of the
data. For example, if a linked list of data structures is
shared by all threads of execution and you need to remove a
link from the list, you must "lock" the list while removing
the link to prevent another thread from trying to traverse it
during this process.

Even in a non-preemptive environment such as NetWare 3.x,
there will be situations where multiple threads compete for
some type of resource requiring serialized access. If one
thread is accessing such a resource and gives up control
(perhaps implicitly), another thread may begin to use it
which may cause problems. In situations like this one, you
must synchronize threads.

There are many ways to synchronize threads, but the easiest
is by using local, in-memory semaphores. Both OS/2 and
NetWare provide this type of mechanism, with the main
difference being only in the API names. Another option for
thread synchronization is accomplished by disabling CPU
interrupts. If the work you are doing is very short, like
removing a link from a linked list, disabling interrupts is
usually easier, and carries less overhead. Of course,
disabling interrupts is not always an option. If the
operating system supports Intel processor ring protection,
applications that are not running at the IOPL priviledge
level are not allowed to disable interrupts.

To illustrate a method for performing thread synchronization,
an example program named DBLWIN.C has been included with this
article's source listings (see "DAX (Distributed Application
Example") for instructions on obtaining the source). DBLWIN.C
illustrates the use of local semaphores to serialize access
to the local screen's current cursor position. In addition,
it creates a debug screen for debug messages, and
synchronization to the current screen is also performed using
local semaphores. The NLM divides the main screen into two
logical windows, then creates two threads, each one being
responsible for keeping the time accurate in its assigned
window.

Two Multithread Design Strategies

When creating a multithreaded application for any
environment, a question that comes to mind is, "Should I
create worker threads dynamically, or should I use a pool of
threads and distribute the work among them?" Both design
strategies have advantages and disadvantages.

In the "dynamic worker thread" strategy, each time a request
is received by the server, a thread is started to service the
request. This approach is easy to implement, as it requires
that you simply spawn a new thread for each new request. On
the other hand, this method can consume large amounts of
resources and create sufficient overhead on the kernel's run
queue. Just considering stack space requirements, a normal
thread usually takes about 8K of RAM for its local stack. If
you wanted to support 250 clients simultaneously, you would
consume two megabytes of RAM just for the thread stack! You
must also consider that 250 threads competing for the CPU
would increase the amount of time that all threads must wait
before regaining CPU control.

In the alternate "pool of threads" approach, a number of
worker threads are started when the server application
begins, then, as work comes in, a thread is taken from the
pool to service it. This prevents the situations listed above
from occurring, however it adds the additional overhead of
queuing requests in situations where all threads in the pool
are already busy.

Which strategy is best for your application? Maybe the first,
maybe the second, and maybe a combination of both. It really
depends on your application, and you must apply the
characteristics of your program to the designs, to determine
the best strategy for you.

DAX (Distributed Application Example)

DAX is a working application that demonstrates the
fundamentals of distributed computing. This application is an
implementation of a client-server calculator. Although DAX is
not an ideal distributed application, it allows you to plug
in your own code easily. DAX can be downloaded from the
NetWire forum on CompuServe (NOVLIB forum, LIB 1, filename:
DAXn.ZIP, where "n" is the version). The remainder of this
article provides an overview of the components of a
distributed application and discusses the communication
protocol layer. Part II of this article in the May issue of
Bullets will cover distributed application protocol (DAP) and
the client and server applications.

The software portion of any distributed application can be
broken down into four major components:

*    Communication protocol
*    Distributed application protocol (DAP)
*    Client application
*    Server application

A client application sends requests to the server application
using the DAP, a language both applications understand. The
messages which make up the DAP are transported back and forth
via a communication protocol.
Steve Holbrook presents an analogy of this process in his
article "Designing Distributed Applications for NetWare,"
(Oct. 1988 NetWare Technical Journal):

     "In the real world, you see client-server relationships
     in almost every aspect of life. More often, people play
     the role of client. For instance, when Charlie wants to
     buy something from a mail-order house, Charlie is the
     client; the mail-order house is the server; the order
     form that Charlie fills out is the client-server
     protocol, speaking in a request/reply language which the
     order form provides.

     "The mail service used to send and receive the order
     form is the communication protocol (this includes the
     type of envelope, the addressing scheme, and the method
     of delivery). The carrier (US Mail, Federal Express, or
     whatever) is the communication media."

In order to isolate the communication protocol (e.g., IPX or
TCP/IP) from the DAP, the example application contains a
layer of software and a generic API that separates one from
the other. This allows you to change the communication
protocol (CP) layer, without changing any of the layers
above, including the DAP as well as the client and server
applications.

The current version of the example program supports both DOS
and NLM clients. To isolate the CP layer from those above,
the example application uses a static library containing
object modules for both DOS and NLM implementations. The
communication protocol used in this example is IPX. The
source code can be compiled for either supported environment
by defining one of two constants: "DOSCLIENT" or "NLMCLIENT."
To compensate for differences between DOS and NLM
implementations of the IPX API, a special header file called
"HELPER.H" is used to define some macros that produce the
illusion of an identical IPX API set.

On the server side, the CP layer is designed as a standalone
NLM which exports several APIs to provide its services to the
other application (the server part of the distributed
application). The CP layer could have been implemented as a
static library, but if you were to add support for other
protocols, a static library would force you to rebuild the
entire server application, rather than just the underlying
communication protocol layer NLM.

DAX is very modular in nature and uses identical file names
for the client and server modules to make it easy to match up
the pieces. The CP layer is broken into two logical pieces,
the client side and the server side. The two sides share a
common header file, CP.H, which defines the layout of the
data exchanged between the two nodes on the network. The type
declaration below displays the structure of the packet
defined in CP.H.

typedef struct {
        CPHEADER   cphdr;
        UINT8      msg[CPMAXMSG];
}CPMESSAGE;

The "msg" member is simply defined as an array of characters.
Although you could define the layout of this data, you might
be tempted to utilize it from code in the CP layer, and you
should resist this temptation. If the CP layer "knows"
nothing about the data it is transmitting across the network,
applications can can achieve a very modular design, allowing
you to add different protocols with relative ease.

The "cphdr" member contains the information that the CP layer
uses to maintain communications between the nodes. In DAX,
"cphdr" consists of a signature (for authentication
purposes), a server ID for identifying the client node to the
server application, and some reserved bytes which could be
used for implementing things like large packet support or
flow control on connectionless-oriented protocols. Figure 3
contains the structure of the packet header defined in the
CP.H structure.

*********************************************
Figure 3: Structure of the packet header defined in CP.H

typedef struct {
        UINT32  signature; // signature for packet CPPKTSIG
        UINT32  serverID;  // server ID for this session
        UINT8   reserved[6]; // keep six bytes for later
}CPHEADER;

End of Figure 3
*********************************************

Software Modules

The communication protocol (CP) layer on both the client and
server sides consists of four main modules:

*    CPINIT
*    CPCONN
*    CPSEND
*    CPRECV

Each of these modules contains the necessary support for
implementing a single part of the CP layer.  Some routines in
each of these modules contain no code. The entire layer is
designed to be very generic, and it can be adapted to almost
any underlying network protocol. For example, the
CPDeInitializeSendLogic API contains no code (in this
implementation, nothing is required to deinitialize send
logic). The server side contains one extra module, CPIO, and
this module contains support for printing messages under
certain error conditions.

CPINIT Module

This module fully initializes the CP layer, preparing it to
connect and send and receive messages. CPINIT contains two
APIs, CPInitialize and CPDeInitialize. The DAP layer calls
the CPDeInitialize API to shut down the CP layer when you no
longer require any services from the application server.
These two APIs are called by the DAPInitialize and
DAPDeInitialize APIs which reside in the DAP layer. Each
layer can only communicate with the layer directly below it.
This design creates a very modular application, and allows
you to replace each layer with a minimum of difficulty.
The server side performs the same functions listed for the
client side and, in addition, handles service advertising
support. After successfully initializing, we begin
advertising our service to the network.

CPCONN Module

On the client side, this module contains the support code for
connecting to and disconnecting from an application server.
The example application uses IPX, which is a
connectionless-oriented protocol, so these APIs merely set
the flags in the CP control structure that indicate whether
a connection exists or not. This module also contains two
empty APIs that are not needed for this design but are used
as place-holders for future versions.

On the server side, this module contains the routines that
accept new sessions with the application server and maintain
the array containing client information. Because this version
of DAX is connectionless, it accepts new connections
dynamically as they are received. On receipt of a client
request, DAX uses the sessionID from the CP header to index
the client data array. If the network address of the new
request does not match the address in that element, a new
slot is assigned for the client.

CPSEND Module

CPSEND contains the APIs used to send requests. The API is
synchronous -it does not return until it sends the message to
the server or an error occurs. The module also contains code
to "timeout" the loop, and return an error condition.
Finally, CPSEND contains initialization and deinitialization
routines.

CPRECV Module

This module contains the code for receiving messages from the
application server. Unlike the send API, this API is
asynchronous -it does not wait for a reply, but instead
checks to see if one has been received, and returns the data
if one was. This implementation of CPRECV also contains some
low-level authentication support (packet signature only).
This module's error handling mechanism for received packets
is minimal and could be improved. If a transport error
occurs, it returns a "TRANSPORT" error, without reposting the
ECB. As an exercise, try implementing an intelligent error
handling mechanism.

On the server, this module handles incoming requests from
client applications. This module is perhaps the most complex
of all server-side CP modules. Like the other modules, it has
both initialization and deinitialization routines. It also
has an independent thread of execution which handles incoming
requests. As new requests are received, this thread
identifies the requester, and then calls an API in the DAP
layer to process the request. To avoid overloading the
receiving thread, the API in the DAP layer queues the request
for later processing. This design allows the server
application to repost the ECB to listen for new requests.

In May, Bullets will examine the DAP layer and the client and
server applications that use it. Next month's issue will also
discuss how to port the example application so that you can
create your own distributed application for NetWare 3.x. So,
stay tuned next month for Part Two of "NLMs: from 'Hello
World' to World-Class Computing."




*********************************************
*********************************************
TECHNICAL INSIGHTS:
Btrieve DATE Data Type & Microsoft BASIC
(Btrieve (All versions))
*********************************************
*********************************************

When developing Btrieve applications with Microsoft BASIC PDS
7.X or Visual Basic v1.0, the Btrieve DATE data type is
required to sort on a date field. The DATE data type field is
stored internally as a four-byte value. The day and month are
each stored in one-byte binary format. The year is stored as
a two-byte integer value. The day is in the first byte, the
month is in the second byte, and the year is a two-byte
integer following the month.

To efficiently sort on a date field, create a structure using
the user-defined TYPE and END TYPE statements for the key
buffer.

   TYPE Date
       Day        AS STRING * 1
       Month      AS STRING * 1
       Year       AS INTEGER
   END TYPE

Then, name the structure using the DIM statement for BASIC
PDS 7.X:

   DIM Birthdate AS Date

Or, name the structure using the Globalstatement for Visual
Basic v1.0:

   Global Birthdate AS Date

Next, assign values to these variables using the MKI$ or the
CHR$ functions. (Visual Basic v1.0 does not support the MKI$
function, so you must use the CHR$ function instead.) Since
the day and month variables need to be stored as a one-byte
string, the integer values must be converted to string values
using the MKI$ or CHR$ function as shown below.

   Birthdate.Day   = MKI$(20)
   Birthdate.Month = MKI$(6)
   Birthdate.Year  = 1999

OR

   Birthdate.Day   = CHR$(20)
   Birthdate.Month = CHR$(6)
   Birthdate.Year  = 1999

The MKI$ function converts a two-byte integer to a two-byte
string. The CHR$ function converts a decimal value to its
equivalent ASCII  character. Since the day and month
variables will never exceed 255, only the low-order byte is
being manipulated. Either function will store the same value.


Once these values have been inserted into the Btrieve file,
the same birthdate structure can be used to retrieve data
with a GET operation. Once the record is returned into the
birthdate structure, convert the day and month variables back
to their numeric values.

(For BASIC PDS v7.x)

CALL BTRVFAR(GETFIRST%,
             PosBlk$,
             VARPTR(Birthdate),
             VARSEG(Birthdate),
             _BufLen%,
             KeyBuf$,
             KeyNum%)

(For Visual Basic v1.0)

Status%=BTRCALL(GETFIRST%,
                PosBlk$,
                Birthdate,
                BufLen%,
                KeyBuf$,
                KeyBufLen%,
                KeyNum%)

The conversion can be accomplished with the ASC function
which returns the numeric value of the equivalent ASCII
character.

Day%   = ASC(Birthdate.Day)
Month% = ASC(Birthdate.Month)
Year%  = Birthdate.Year



*********************************************
*********************************************
TECHNICAL INSIGHTS:
Preventing NLMs from Unloading
*********************************************
*********************************************

In the March 1992 issue of Bullets (Volume 4, Number 3), the
"Technical Insights" section contained a routine that can be
used to prevent NetWare Loadable Modules from unloading by
"pushing" characters to the console screen using "ungetch"
("n"). One API call (DestroyScreen) was inadvertently omitted
and should be included in the routine.

Insert the following API call before the "return" statement
at the end of the routine:

  DestroyScreen(NewScrID);



*********************************************
*********************************************
TECHNICAL INSIGHTS:
Specifying Server Name/Volume Name in BLOG.CFG
(NetWare Btrieve (NLM) v5.15)
*********************************************
*********************************************

If the file, BLOG.CFG, uses ServerName or VolumeName to
specify the path to the BROLLFWD log file, BROLLFWD will
return the error message, "Cannot find log file." However, if
a drive letter is specified instead of ServerName and
VolumeName, BROLLFWD will work correctly.

To ensure that BROLLFWD functions properly, use a drive
letter to specify the path to the log file.



*********************************************
*********************************************
TECHNICAL INSIGHTS:
maxECBs in Windows IPXInitialize()
(NetWare C Interface for Windows v1.22)
*********************************************
*********************************************

In Windows Enhanced mode, passing zero for maxECBs in the
IPXInitialize() function, and then managing the allocation of
ECBs in low memory results in an unrecoverable application
error.

In this mode, passing zero for maxECBs is allowed only for
compatibility with the Standard mode The zero setting for
maxECBs will be ignored and VIPX will manage ECB allocation,
so applications should allow VIPX to perform this task.
However, in Standard mode, applications can pass zero for
maxECBs and then then manage their own ECB allocation.



*********************************************
*********************************************
TECHNICAL INSIGHTS:
GetBroadcastMessage API Update
(NetWare C Interface for DOS v1.2)
*********************************************
*********************************************

In the NetWare C Interface for DOS v1.2, the
GetBroadcastMessage API is designed to expect messages of 55
bytes or less to be returned. However, broadcast messages of
up to 58 bytes may be returned from the server console. A
long message (over 55 bytes) corrupts system memory and may
cause a workstation hang. To avoid problems, modify the
source code to the GetBroadcastMessage API in the BRODCAST.C
source files as shown in Figure 4.

*********************************************
Figure 4:      Necessary modifications to BRODCAST.C
          (Changes marked with "<---")

int GetBroadcastMessage(messageBuffer)
char *messageBuffer;
{
    char sendBuf[3], replyBuf[61];      <---
    int len, ccode;

    *((int *)sendBuf) = 1;
    sendBuf[2] = (char) 1;
    *((int *)replyBuf) = 59;            <---
    replyBuf[2] = (char)58;             <---
    ccode = _ShellRequest ((BYTE)0xE1, (BYTE *)sendBuf,
                          (BYTE *)replyBuf);
  if (ccode)
    return (ccode);
    len = (int)replyBuf[2];
    memmove(messageBuffer, replyBuf + 3, len);
    messageBuffer[len] = 0;
    return (0);
}
End of Figure 4
*********************************************



*********************************************
*********************************************
TECHNICAL INSIGHTS:
Brequest Hangs If No Network Connection
(NetWare Btrieve (NLM) v5.15)
*********************************************
*********************************************

Attempting to load BREQUEST.EXE v5.16 on a workstation that
does not have a network connection will hang the workstation.
Make sure the NetWare shell is loaded before attempting to
load Brequest. If you load Brequest from the AUTOEXEC.BAT
file, check the DOS ERRORLEVEL after loading the network
shell. If ERRORLEVEL equals one, do not load Brequest. Add
the following code to your AUTOEXEC.BAT to test for this
condition.

SET B_LOAD=YES
IPX
NETX
IF ERRORLEVEL 1 SET B_LOAD=NO
...
IF %B_LOAD% == YES BREQUEST /D:8192
SET B_LOAD=
...



*********************************************
*********************************************
TECHNICAL INSIGHTS:
xRestrict & Views with Restrictions
(XQL (all versions))
*********************************************
*********************************************

In XQL v2.11, placing a new restriction on a recalled view
with a previously defined restriction results in a number of
situations, depending on the level of the XQL call. For
example, if you create a view with the following restriction:

  CREATE VIEW REST AS
    SELECT * FROM PATIENTS
    WHERE ZIP = "78759"

Then, with XQL Manager level calls, the statement:

  SELECT * FROM REST
    WHERE Last^Name BEGINS WITH "A"

will result in the new restriction being appended to the
existing restriction with an "AND" operator.  Then, records
will be retrieved that satisfy both restrictions (ZIP =
"78759" AND Last^Name begins with  "A").

Using XQL Primitives, an application would perform an xRecall
of the VIEW "REST" and then an xRestrict ("Last^Name BEGINS
WITH "A"). However, the overall restriction on the VIEW will
be determined by which iOption is specified on the xRestrict
call .

If you set the iOption parameter specified in the xRestrict
call to one, the new restriction will replace the previously
defined restriction. If you set iOption to zero, the new
restriction will be appended to the previous restriction with
an "AND" operator. You can also set iOption to zero and
precede the restriction statement with the "OR" operator
(||  Last^Name BEGINS WITH "A"). Then, XQL will append the
new restriction to the previous restriction with an "OR"
operator.



*********************************************
*********************************************
TECHNICAL INSIGHTS:
Loading DLLs Explicitly in Windows
(NetWare C Interface for Windows v1.22)
*********************************************
*********************************************

If a Windows program makes a call to any NetWare C Interface
for Windows Dynamic Link Libraries (DLLs), the DLL is loaded
implicitly (automatically) by Windows at runtime. All of
these DLLs except NWIPXSPX.DLL require access to functions in
the DLL, NETWARE.DRV. NETWARE.DRV is not loaded unless the
NetWare shell is loaded when you start Windows.

To avoid this situation, load the DLLs explicitly instead of
implicitly. To load the DLLs, follow the steps outlined in
Figure 5.

*********************************************
Figure 5: Steps for loading DLLs explicitly in Windows v3.0

A)   Determine if the NETWARE.DRV is loaded:

   HANDLE hNetWare;

   hNetWare = GetModuleHandle("NETWARE.DRV");
   if (hNetWare == NULL)
     // not loaded
   else
     // loaded!

B)   Try to load the DLL (in this example, NWBIND.DLL):

   HANDLE hDLL;

   hDLL = LoadLibrary("NWBIND.DLL");
   if (hDLL < 32)
     // error returned (file not found = 2)
   else
     // loaded!

C)   Make functions point to their location(s) in the DLL:

// This method uses the function string name
// (very memory hungry; pointers + strings, slow load time)

   GetBinderyObjectID =
     (WORD (FAR PASCAL *)()) GetProcAddress(hDLL,
"GetBinderyObjectID");

   // This method uses function ordinal number
      (in this example, 14)
   // (little memory; just pointers, very fast)

   GetBinderyObjectID =
   (WORD (FAR PASCAL *)()) GetProcAddress(hDLL, (LPSTR)14);

End of Figure 5
*********************************************

These three steps also require you to modify the prototypes
so that the function names are pointers to functions. For
example, to modify the prototype for GetBinderyObjectID(),
change the line in the NWBINDRY.H file as shown in Figure 6.
*********************************************
Figure 6:      Modification to GetBinderyObject() required
               when loading DLLs explicitly

Old:

extern WORD FAR PASCAL
             GetBinderyObjectID(char   far *objectName,
                                WORD   objectType,
                                DWORD  far *objectID );

New:

WORD (FAR PASCAL
            *GetBinderyObjectID)(char   far *objectName,
                                 WORD   objectType,
                                 DWORD  far *objectID );

End of Figure 6
*********************************************

Do not import the functions from the DLLs you explicitly
load. The actual calls to the functions do not have to be
changed once all the above steps are taken.




*********************************************
*********************************************
TECHNICAL INSIGHTS:
Relocation of Source Code for Bullets Articles
*********************************************
*********************************************

The source code for CAPIT. C referenced in "Capturing with
the NetWare Print Services" (March 1992 Bullets) can now be
downloaded from NOVLIB, LIB 7, filename:CAPITx.ZIP (where "x"
is revision number). The source file, MAPIT.C, referenced in
"Saving & Restoring Drive Mappings" (February 1992 Bullets)
is now located in NOVLIB, LIB 7, filename: MAPIT.ZIP.



*********************************************
*********************************************
COMING EVENTS:
1992 APPLE DEVELOPER CONFERENCE
*********************************************
*********************************************

Novell Walnut Creek invites you to the 1992 Apple Developer
Conference, Wednesday, May 13 where we will demonstrate the
latest Novell solutions for the Macintosh developer and user.
Featured in the Enterprise Systems Expo at the San Jose,
California Convention Center, Novell will display Macintosh
connectivity solutions including NetWare v3.11 with NetWare
for Macintosh, related developer tools and a prototype of the
new IPX/SPX for the Macintosh.

This also will be your first opportunity to see DataClub from
Novell, the newest addition to Novell solutions for the
Macintosh. With DataClub, Macintosh users enjoy the high
performance of a dedicated file server with or without
dedicated server hardware.

Mark your calendar for May 13 and plan on visiting the
Enterprise Systems Expo, at the 1992 Apple Developer
Conference.



*********************************************
*********************************************
NIBBLES & BITS:
Fast answers to common questions
*********************************************
*********************************************

Btrieve

Q:   What is a status 1015?

A:   Status 1015 is returned by Btrieve for OS/2 if you have
     specified the following environment variable before
     starting your application:

     SET BTRPARMSCHK=Y

     By setting this environment variable, you can isolate
     errors caused by passing invalid pointers to Btrieve.
     When this variable is set, Btrieve validates the pointer
     parameters passed in for READ/ WRITE access over certain
     ranges. Btrieve validates the position block pointer
     over a range of 128 bytes; it validates the data length
     pointer over two bytes (data length only points to an
     integer); it validates the data buffer over the
     specified data length; and it validates the key buffer
     over 255 bytes.

Q:   Can I load the Btrieve/NetWare SQL NLMs manually from
     the console? What will happen if I use the NCF files to
     load them?

A:   If you load these NLMs with the manual 'Load <NLM name>'
     command at your server console or in your AUTOEXEC.NCF
     file you may experience the following problems:

*    If you fail to load the corresponding SPX communication
     NLM (BSPXCOM, or NSSPXCOM), you will receive errors when
     calling Btrieve or NetWare SQL from a workstation,
     another server, or when loading BCONSOLE.NLM.

*    If you manually load either BTRIEVE.NLM or NWSQL.NLM,
     you receive nonzero status codes when you exceed the
     default load parameters for the respective NLM. The load
     parameters that you set in BSETUP or NSSETUP are written
     to BSTART.NCF or NSSTART.NCF respectively, so if you do
     not load using the NCF file, you are loading the NLMs
     with default parameter values. You can also call the NCF
     files from the server's AUTOEXEC.NCF file to load the
     NLMs automatically with the correct parameters.


NetWare for SAA v1.2

Q:   Do you need a separate 5250 gateway to connect to an IBM
     miniframe AS/400?

A:   No, NetWare for SAA v1.2 supports both 5250 and 3270
     mainframe and miniframe connections.


Xtrieve PLUS for DOS v4.10

Q:   In Xtrieve PLUS v4.10, when I use the Suppress Blanks
     option and use the following layout:

     field1 field2 field3

     then, if field2 has no data, that data for field3 is
     placed where the data for field2 would have been. Is
     there any way to make the Suppress Blanks option work
     only "down the page" and not "across the page?"

A:   No. In this situation, you should not use the Suppress
     Blanks option.


NetWare C Interface      for DOS v1.2

Q:   Why is the source code to LoginToFileServer(),
     VerifyBinderyObjectPassword(), and
     ChangeBinderyObjectPassord() not included with the
     NetWare C Interface for DOS v1.2?

A:   The encryption algorithm is part of the login source
     code, and is not available to the public. You can,
     however, obtain a "generic" AsmLoginToFileServer() and
     related functions that can be called by any compiler
     that supports both a code and data segment and C-style
     parameter passing on the stack. Currently, there is no
     support for Turbo Pascal-based calls to these functions,
     as Turbo Pascal requires there to be no data segment.
     Contact the Developer Support Group at Novell Austin to
     request this set of object files.


VIPX.386 v1.10

TIP: When using the NetWare Windows driver, VIPX.386 v1.10,
     use the versions of IPX.OBJ/IPXODI.COM and NWIPXSPX.DLL
     that are supplied with the VIPX.ZIP file.


Network C for NLMs v2.0b

TIP: Have you ever received a message like, "Module did not
     release 1264 resources. Resource: Small memory
     allocations," and wondered how to track down exactly
     which memory you did not release? The following
     procedure identifies which pointers must be freed. It
     works with NetWare v3.11 with CLib v3.11 (with debug
     symbols).

1.   Drop into the Internal Debugger.
2.   Set a breakpoint exactly like this:

     b=malloc-4d+[dmalloc-9]

3.   Run your NLM.
4.   When the NLM exits, the debugger is entered once for
     each pointer. In the debugger, register EAX contains a
     pointer to unfreed memory.


OS/2 Developer's Kit v1.3a

     When using OS/2 version1.3 and NetWare, be sure to apply
     all the patches to the NetWare OS/2 requester. Unpatched
     requesters can produce unpredictable results in Btrieve
     and NetWare SQL. The current patches are on CompuServe
     (NOVLIB forum, LIB 5, filename NSD003.ZIP. This file is
     also available from the Developer Support Group at
     Novell Austin.



*********************************************
*********************************************
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

905 - Programming with Btrieve

     May 12-14      Austin, TX
     July 8-10      Sunnyvale, CA

906 - Programming with Btrieve: Advanced Features

     June 16-18          Austin, TX

907 - Xtrieve PLUS

     May 20-21      Sunnyvale, CA
     July 14-15          Dallas, TX

910 - Programming with XQL

     June 10-12          Austin, TX

920 - Programming with Network Communication Services

     June 15-16          Sunnyvale, CA

930 - Developing NetWare Loadable Modules (NLMs)

     May 13-15      Sunnyvale, CA
     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.   How many bits are in an "int" in NLM environment?

     A.   8
     B    16
     C.   24
     D.   32

2.   What CLIB.NLM function generates unique strings for use
     as a valid filename?

     A.   UniqueFileName()
     B.   tmpnam()
     C.   tmpfile()

3.   In the Netware C Interface for DOS v1.2, what is the
     name of the header file that contains the definitions
     for all the C structures needed for IPX and SPX?

     A.   nxt.h
     B.   ipxspx.h
     C.   nit.h

4.   In the Netware C Interface for DOS v1.2, what is the
     name of the function that initializes the ECB's
     immediate address field?

     A.   IPXGetLocalTarget()
     B.   IPXImmediate()
     C.   IPXInitialize()

5.   What are the two modes of services provided by TLI
     (Transport Layer Interface)?

     A.   Connection mode & Connectionless mode
     B.   Real mode & Standard mode
     C.   Connect mode & Disconnect mode

6.   In NetWare SQL, which of the following is not a valid
     scalar function for string manipulation?

     A.   LENGTH
     B.   REVERSE
     C.   RIGHT
     D.   UPPER

7.   If you use both XQLP and XQLM function calls, which
     Login function should you use?

     A.   xLogin
     B.   XQLLogin

8.   What is the predefined function key in Xtrieve PLUS to
     accelerate command file replay?

     A.   F6
     B.   F8
     C.   F2
     D.   F1

9.   Xtrieve PLUS v4.10 has a username called PUBLIC. What is
     the password for PUBLIC?

     A.   PUBLIC
     B.   PUB
     C.   There is no password
     D.   PUBLIC is not a valid username

10.  In Btrieve, what is the name of the file that contains
     the list of all Btrieve files to be logged?

     A.   BLOG.BTR
     B.   BLOG.CFG
     C.   BTRLOG.CFG

11.  In the NetWare 2.x environment, the bindery is composed
     of two files. What are the names of these two files?

     A.   NET$BIND.SYS and NET$PROP.SYS
     B.   NET$BIND.SYS and NET$OBJ.SYS
     C.   NET$BIND.SYS and NET$BVAL.SYS

*********************************************
ANSWERS:

1.   D
2.   C
3.   A
4.   A
5.   A
6.   B
7.   B
8.   C
9.   C
10.  B
11.  C
*********************************************



*********************************************
*********************************************
CURRENT VERSIONS OF NOVELL PRODUCTS
*********************************************
*********************************************

NetWare

     NetWare 3.x                             3.11
     NetWare 2.x                             2.2
     NetWare Lite                            1.0
     NetWare for VMS                         2.1

NetWare Services

     NetWare for Macintosh                   3.01
     NetWare NFS                             1.2
     NetWare FTAM                            1.2
     NetWare for SAA                         1.1
     NetWare RMS                             n/a
     NetWare NNS                             n/a

Communication Toolkits

     LAN WorkPlace Toolkit for DOS           4.01

NetWare System Interfaces

     NetWare C Interface for DOS             1.2
     NetWare System Calls for DOS            1.0
     NetWare System Interface
     Technical Overview                      1.2

Software Developer's Kits

     OS/2 Developer's Kit                    2.0
     NetWare C Interface for Windows         1.22
     NetWare C Interface for Macintosh       1.3
     NetWare Network Management Toolkit      1.0
     LAN WorkPlace Toolkit for OS/2          2.0
     Network C for NLMs                      2.0 c
     NetWare TIRPC for DOS and NLMs          1.0
     NetWare AppleTalk Interface for NLMs    1.0
     NetWare for SAA LU6.2 Tools             1.2
     NetWare 3270 Tools                      1.6

NetWare RPC

     NetWare RPC for DOS                     1.1
     NetWare RPC 386                         1.1

Compiler Toolkits

     Network C for DOS                       2.0

XQL

     XQL for DOS                             2.11
     XQL for OS/2                            2.11

NetWare SQL

     NetWare SQL (NLM)                       2.11a
     NetWare SQL (VAP)                       2.11

Btrieve

     NetWare Btrieve (NLM)                   5.15
     NetWare Btrieve (VAP)                   5.15
     Btrieve for DOS                         5.10a
     Btrieve for OS/2                        5.10
     Btrieve for Windows                     5.10

Xtrieve PLUS

     Xtrieve PLUS for DOS                    4.10
     Xtrieve PLUS for OS/2                   4.01

Report Executive

     Report Executive for DOS                4.01a
     Report Executive for OS/2               4.01a

For a complete list of the Novell product line contact Novell
Austin or your local Novell Authorized dealer.



*********************************************
*********************************************
CURRENT REQUESTER VERSIONS
*********************************************
*********************************************

NetWare Btrieve v5.15

     Requester for DOS                       5.16
     Requester for OS/2                      5.17a
     Requester Interface for Windows 3.0     5.16

NetWare SQL v2.11

     Requester for DOS                       2.12a
     Requester for OS/2                      2.11
     Requester Interface for Windows 3.0     2.13

NetWare Shells and Requesters

     DOS Shell                               3.22a
     IPX (DOS)                               3.10
     VIPX.386                                1.10
     NetWare Requester for OS/2              1.3
     NETWARE.DRV (Windows)                   1.03.7
     VNETWARE.386 (Windows)                  1.03.2



*********************************************
*********************************************
CONTACTING NOVELL AUSTIN
*********************************************
*********************************************

To obtain technical support, call 1-800-NETWARE
(1-800-638-9273), or 1-801-429-5588. Be prepared to give the
support operator your Direct Connect authorization number or
open incident reference number. Technical support questions
may also be sent by FAX to 1-512-794-1775. Novell provides a
wide range of support contracts designed to meet your needs.

If you have purchased a new Novell Development Product, you
are eligible for 30 days of free telephone support. Please be
prepared to give the support operator the product's serial
number.

Many international distributors provide technical support.
Please contact your distributor or local Novell office (see
list on back cover) for more information on international
support options.

Software patches may be obtained from the NetWire forum on
CompuServe, or by contacting the Developer Support Group and
specifying the patches you need by product name.

Novell Database and Development Products can be obtained
through Novell Authorized Resellers, or by calling
1-800-RED-WORD (1-800-733-9673) or 1-512-794-1796.

Software Developer's Kits (SDKs) are available only through
Novell's Professional Developers' Program. Call
1-800-RED-WORD (1-800-733-9673) or 1-512-794-1796.

For more information on Novell's Professional Developers'
Program, Novell Development Products, and Direct Connect
Support Contracts, call 1-800-RED-WORD (1-800-733-9673), or
1-512-794-1796, FAX 1-512-794-1770, or contact the nearest
Novell office.



*********************************************
*********************************************
ACKNOWLEDGEMENTS
*********************************************
*********************************************

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

Contributing authors:
          Linda Anderson
          Vitek Boruvka
          Neda Eslami
          David Harris
          Sudz Khawaja
          Ken Lowrie
          Rudy McNeese
          Clint McVey
          Mike Shoemaker
          John E. Stewart
          Aslam Tejani
          Maggie Walczynski
          Chip Webb

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.
*********************************************

Developer Support/Direct Connect:
1-800-NETWARE (1-800-638-9273)
Tel. (801) 429-5588
Fax  (512) 794-1775

International Customers please contact your local Novell
authorized dealer or nearest Novell office.

*********************************************

Novell, Inc.
Corporate Headquarters
122 East 1700 South
P.O. Box 5900
Provo, Utah 84606
USA
Tel.  (801) 429-7000

*********************************************

Novell International Operations
& Novell Latin America
890 Ross Drive
Sunnyvale, CA 94089
USA
Tel.  (408) 747-4000
FAX (408) 747-4033

*********************************************

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
1930 Zaventem
Belgium
Tel.  32 (2) 725-02-00
FAX 32 (2) 725-03-11

*********************************************

Novell France
Tour Anjou
33, Quai De Dion-Bouton
92814 Puteaux Cedex
France
Tel.  33 (1) 47.75.09.09
FAX 33 (1) 47.78.94.72

*********************************************

Novell Germany
Willsttter Strasse 13
4000 Dsseldorf 11
Germany
Tel.  49 (211) 5973-0
FAX 49 (211) 5973-250


*********************************************

Novell Hong Kong
China Resources Bldg.
Room 4601-5, 46th Floor
26 Harbour Rd.
Wanchai, Hong Kong
Tel.  852 8272223
FAX 852 8276555

*********************************************

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 Spain
Lexington. S.a.
Paseo Castellana, 141
Planta 18
28046 Madrid
Spain
Tel.  34 (1) 572-0360
FAX 34 (1) 570-7199

*********************************************

Novell Sweden
Kottbyjatan 7
16475 Kista
Sweden
Tel.  46 (8)-7032350
FAX 46 (8)-7039434

*********************************************

Novell Switzerland
Bahnstrasse 102
8105 Regensdorf
Switzerland
Tel.  41 (1) 870-0650
FAX 41 (1) 870-0628

*********************************************

Novell United Kingdom
Avon House, Sweetwell Road
Bracknell, Berkshire
RG12 1HH
United Kingdom
Tel.  44 (344) 860 400
FAX 44 (344) 860 353

*********************************************
Professional Development Series
B  U  L  L  E  T  S
April 1992
END OF FILE
*********************************************
