OCTOBER/NOVEMBER 1993 VOLUME 5 NUMBER 10
INDEX
Distributed Applications: NCP Extensions & The NetWare Client SDK
Last year, Novell Professional Developer Bullets presented a series of articles discussing
distributed application design. These articles used a sample distributed application built on
Novell's IPX interface called DAX (Distributed Application eXample) to illustrate specific
design strategies.
The DAX example consists of an NLM providing a calculator service to NetWare clients running
on the DOS, NLM and Microsoft Windows platforms. The DOS and Windows portions of DAX
were written to the APIs in the NetWare C Interface for DOS and NetWare C Interface for
Windows SDKs, respectively. The NLM server and client components were written using the
Network C for NLMs SDK.
Since DAX was written, Novell has released new SDKs for both the client and server platforms.
The NetWare Client SDK v1.0d is latest version of the SDK that replaces the NetWare C
Interface for DOS and NetWare C Interface for Windows SDKs. The NetWare Client SDK
supports the DOS, Windows and OS/2 platforms.On the server side, the NLM SDK v3.0 has
replaced the Network C for NLMs SDK and the NLM SDK for NetWare 4.0. The NLM SDK
supports both the NetWare 3.x and NetWare 4.x server platforms.
One of the new API subsets in the NetWare Client SDK and the NLM SDK exposes a
powerful and flexible client/server communication mechanism known as NetWare Core Protocol
Extensions (NCPE). The NCPE API allows you to "piggy-back" custom requests on an existing
NCP session to a service provider NLM that is running on your NetWare server. As you will
soon discover by reviewing the example code, developing distributed applications using NCPE
drastically reduces development time.
Recapping DAX
Before discussing the new example, a quick recap of the DAX example is in order. DAX
is a distributed application using IPX as its transport. This application is divided into four pieces:
- The server application
- The client application
- The distributed application protocol (DAP) layer
- The communication protocol (CP) layer
The CP layer houses all the logic for exchanging messages between the client and server
portions of the application. The DAP layer contains the logic for the protocol used by the client
and server components of the application.
The client calls an API in the DAP layer to perform a math operation. The DAP API formats a
protocol packet with a request code and the operands for the request, and calls an API in the CP
layer to send the request. On the server side, the CP layer receives the request, extracts the DAP
data, and calls an API to enqueue the request to the server application. The request processing
thread in the DAP layer decodes the request and calls the API to service the request. A reply
packet is formatted by the server application and sent back to the client by a dedicated service
reply thread in the CP layer.
Back on the client side, the CP layer receives the reply, and passes the reply data back to the
DAP layer. The DAP layer then extracts the results, and passes them back to the client making
the request.
For more detailed information on the DAX example, refer to the following issues of Bullets:
April 1992, May 1992 and August/September 1992. These articles are also available on the new
Bullets InfoBase on Novell's NOVDEV developer forum on CompuServe. The complete source
code for the DAX example is also available on CompuServe in the NOVLIB (Library 7,
DAX1.ZIP).
BMV: New Example Application
The example discussed in this article is a Bit Map Viewer (BMV) distributed application,
based on the original DAX code. This version of BMV consists of a service provider NLM and a
Windows client. The client requests bitmap information for each of the bitmaps that the NLM
knows about. A list box is created containing the titles of the bitmaps. When a bitmap is selected
from the list box, the client requests the corresponding bitmap data from the NLM. The client
then sizes the bitmap to fit inside a predefined window and displays it. The code for sizing the
bitmap comes from Charles Petzold's, Programming Windows 3.1 (Microsoft Press, 1992, Third
Edition).
There are two implementations of the communication protocol layer of BMV: one is based on
the IPX CP layer from the DAX example, and the other is based on Novell's NCPE interface. For
the IPX-based CP layer, the only changes made were on the client side, all of which were
required to support the new NetWare Client SDK.
For the NCPE implementation, the CP layer was eliminated altogether and the DAP layer was
modified to call the NCPE APIs instead of those that existed in the original CP layer. Not only
does this result in much less code to maintain, it also provides a substantial performance boost
and a number of other features not available in the original CP layer. The section on NCPE later
in this article discusses these enhancements in more detail.
Porting to the NetWare Client SDK
Since the DAX example uses only a handful of APIs, porting the existing client code to
the NetWare Client SDK required only a few trivial changes. The transport interfaces in the
NetWare Client SDK did not change, so the main concern was with the Bindery and Connection
services calls. These calls implement the name-to-address resolution portion of the client
application. As far as the environment is concerned, the NetWare Client SDK replaced most of
the DLLs in the NetWare C Interface for Windows with a single DLL, called NWCALLS.DLL.
The IPX/SPX calls remain separate in a DLL called NWIPXSPX.DLL.
The most notable changes in the NetWare Client SDK with respect to porting from the NetWare
C Interface products are:
- The addition of the NW prefix to all API calls
- A required connection handle on most APIs
- A set of abstracted data type names for the function parameters.
- The addition of the API NWCallsInit(), a call that initializes the library for use. This call
is not required in the Windows environment. However, in the DOS environment, the libraries
will not work if you forget to make this call.
- Finally, you must define one of three constants, NWDOS, NWWIN or NWOS2, before
including the header files for the NetWare Client SDK.
To take advantage of these changes to the API sets, the DAX code was altered in several
ways to support the NetWare Client SDK. First, in the header file CPC.H, the NWWIN constant
was defined before including any of the NetWare Client SDK headers. Then, necessary include
statements were added to obtain prototype information for the APIs used in the CP layer.
Second, the module CPINIT.C (where the name to address resolution takes place) required two
alterations:
- A call to obtain the connection handle for the default server
- A call to perform an integer swap on our object type before passing it to
NWReadPropertyValue()
The connection handle must be obtained, since the APIs in the NetWare Client SDK
require this parameter to identify the target server that will receive the request. Remember that
the NetWare C Interface products used the concept of a preferred server to identify the target of a
given request. NWGetDefaultConnectionID() obtains the connection handle of the default server.
The other change made was to perform an integer swap on the object type passed to
NWReadPropertyValue(). This API expects object types to be in "hi-lo" format, rather than the
native Intel "lo-hi" format. You would only need to make this change in cases in which
Novell-defined manifest constants are not used. In other words, if you pass any of the Novell
defined constants, e.g., OT_USER, as the object type parameter in NWReadPropertyValue(),
your source code need not be changed, since the NetWare Client SDK defines OT_USER in
swapped form.
On the server side, CPIPX.NLM required no changes. While porting BMV to the NetWare Client
SDK, there was no need to recompile the NLM. Later, after enhancing the maximum packet size
macros in the header files, a recompile was necessary. All in all, the changes in the CP layers for
this distributed application were fairly minor; the real work started with the modifications to the
DAP layer.
DAP Layer Changes in BMV
Because BMV is an entirely new application, it required a new application-specific
protocol for communicating between the client and server portions of the application. BMV
needed the following five protocol packets:
- Login to service provider
- Logout from service provider
- Get the number of bitmaps
- Obtain bitmap information
- Get the bitmap data
Apart from the standard simple request/ reply protocol requests like login and logout,
BMV required two new request types not used in the DAX example.
First, an iterative request type, Get BitMap Info was required, which illustrates how to
implement a distributed request requiring context from a previous call. Second, a large
request/reply type, i.e., one that does not fit in a single reply packet, was needed. Although these
request types seem very similar, their implementation is quite different.
The iterative request type is implemented as a simple request/reply that is called one or more
times and requires context information from the previous call. The large request is implemented
transparently to the application, and is performed inside the DAP API itself.
So, to quickly review what was changed to support the NetWare Client SDK:
The only module containing references to APIs in the Client SDK is DAP001.C. This module
uses NWScanObject() to check for the availability of the service. Like NWReadPropertyValue(),
NWScanObject() requires a connection handle as its first parameter, and to obtain this handle, it
calls NWGetDefaultConnectionID(). Once again, the object type of our server must be swapped
before calling NWScanObject(); this step was not necessary with the old NetWare C Interface
libraries. In addition to these source changes, the constant NWWIN was defined, and the
appropriate header files for function prototyping were included. These steps completed process
of porting to the NetWare Client SDK.
As you may have guessed, the Login and Logout protocol packets from DAX were reused
without any changes. The remaining protocol requests from DAX were dropped and three new
requests were added:
- A request to retrieve the total number of bitmaps available from the NLM
- A request to retrieve bitmap information such as an ID, a title, and the bitmap size
- A request to retrieve the actual bitmap data
New DAP Requests for BMV
The request to retrieve bitmap information is stored in the source file DAP012.C. This
request returns information about a single bitmap, including its ID, size and title. It is an iterative
request the client application calls multiple times to get information on all of the bitmaps. The
only input parameter for the request is a bitmap ID, used to indicate the last bitmap for which
information was returned. BMV passes (-1) for the initial call. Subsequent calls use the ID
returned to the caller. The request and reply structures used by this protocol packet are shown in
Figure 1.
FIGURE 1: Request/reply structures for ListBitMaps DAP (BMV)
typedef struct{ // list bitmaps request pkt
UINT32 bitmapid; // (-1) to start search
}LBRequest;
typedef struct{ // list bitmaps reply pkt
UINT32 bitmapid; // bitmap id of bitmap
UINT32 bitmapsz; // length of bitmap
UINT8 title[DAPMAXTITLE]; // title string ASCIIZ
}LBReply;
END of FIGURE 1
Another new request was added to read the data for a bitmap. In this request, the client
passes the ID of the bitmap whose data is required, a buffer large enough to hold the data, and
calls the API DAPGetBitMap(). A major difference between this request and all the others is that
the bitmap data will not fit in a single reply packet. Rather than forcing the client application to
read the data one chunk at a time, this logic was implemented in the DAP API itself (see Figure
2).
FIGURE 2: Reading the data for a bitmap (BMV)
T_RC DAPGetBitMap(DAPDATA *DAPid,LONG bitmapid, char *buffer)
{
T_RC rc;
GBRequest *request = (GBRequest *)DAPid->dapRequest.data;
GBReply *reply = (GBReply *)DAPid->dapReply.data;
//
// fill in the request structure
//
request->bitmapid = bitmapid;
request->offset = 0; // zero to start this off
//
// Send the request
//
while( (rc = DAPSendRequest(DAPid,DAPGETBITMAP)) == 0){
memcpy(buffer,reply->bitmap,reply->bitmapsz);
//
// Done when number returned less than max size
//
if( reply->bitmapsz < DAPMAXBITMAP ) break; // done!
//
// Setup to get next chunk
//
buffer += reply->bitmapsz;
request->offset += reply->bitmapsz;
}
return rc;
}
END of FIGURE 2
Using NCP Extensions
The other, very different implementation of the CP layer for the BMV example application
is based on Novell's NCP Extensions (NCPE) API. This API is supported by NetWare 3.11 and
later versions, and requires the NetWare Client SDK to create DOS, Windows or OS/2 client
applications which use it. On the server, CLib v3.11d and later support the NCPE API set.
The are many distinct advantages in using NCPE:
- They are easy to use.
- They use an existing connection with a server.
- They allow the use of arbitrary message sizes.
- They deliver high-performance, reliable packet transfer.
- They provide built-in error detection & retries.
- They allow you to benefit from packet signing and other security-related features of NCP.
- When Novell adds new features to NCP, these features are automatically available to you.
NLMs, Windows applications and OS/2 applications do not even need to be re-linked.
In the case of the BMV example application, taking advantage of NCPE substantially
reduces the code base. First, NCPE entirely eliminates the CP layer, since NCPE is a
client/server protocol. So, CPIPX.NLM is no longer needed on the server side, and CPAPI.LIB
can be eliminated on the client side. As far as the DAP layer is concerned, NCPE dramatically
simplifies the DAPSendRequest() API used in the IPX-based implementation. Furthermore, the
NCPE implementation offers more functionality than the IPX version as well. Figure 3 shows the
new DAPSendRequest() API for the NCPE version of the DAP layer.
FIGURE 3: New DAPSendRequest() API for the NCPE version of
the DAP layer (BMV)
T_RC DAPSendRequest(DAPDATA *DAPid, UINT16 requestCode)
{
UINT16 replylen = sizeof DAPid->dapReply;
//
// Init the common DAP fields
//
DAPid->dapRequest.requestCode = requestCode;
//
// Send the request, wait for a reply
//
if( NWNCPExtensionRequest(DAPid->hconn,
DAPid->serviceID,
&DAPid->dapRequest,
sizeof DAPid->dapRequest,
&DAPid->dapReply,
&replylen) ){
return DAP_SEND_FAILURE;
}
END of FIGURE 3
The remainder of the protocol request code for the DAP layer remains unchanged on the
client side.
On the server side, a few other changes were necessary. First, the DAPSEND.C and
DAPRECV.C modules were eliminated since they were no longer needed. In DAX,
DAPSEND.C contained the logic to run the service reply thread (the code that processes queued
up replies to be sent back to the client). With NCPE, this logic is unnecessary because NetWare
sends back the reply for you. DAPRECV.C contained the logic to run the service request thread
(the code that processed queued up requests from the clients). With NCPE, this module is also
unneeded, since NetWare calls the extensions handler when it detects a new request has been
received. Eliminating these two modules subtantially reduces the code for the NLM
implementation of the DAP layer.
A new module called DAPNCPE.C contains all of the logic needed to provide an NLM service
based on NCPE. This includes the initialization logic, the actual NCPE Handler API (the API
called when an NCPE request is received by NetWare), and a connection down handler.
The connection down handler is called when specific events occur on any NetWare connection.
This design allows your NLM to clean up client resources, in case a given connection logs out, is
restarted, or is cleared by the NetWare connection watchdog.
Finally, NCPE eliminates the need for the application protocol request to obtain the number of
bitmaps available from the NLM. Now, this information is stored in a 32-byte field allocated by
CLIB.NLM and associated with the NCP Service. The data stored in this field is returned to a
client, whenever it calls one of the NCPE service information APIs, namely
NWGetNCPExtensionInfo(), NWGetNCPExtensionInfoByName() or NWScanNCPExtensions().
When you compare the two implementations of BMV, you will have a much better
understanding of how easy it is to implement distributed applications using NCPE, rather than a
lower-level transport protocol such as IPX or SPX.
After you examine the design differences needed to support the NetWare Client SDK and take
advantage of its features, you should be able to port other distributed applications with similar
designs with a minimum of difficulty. The full source code for BMV is available on Novell's
NOVLIB CompuServe forum (Library 7, BMV0.EXE).
The NetWare Client SDK and the NLM SDK are available to members of the Novell
Professional Developers' Program. For more information, call Novell at 1-800-NETWARE
(1-800-638- 9273) or 1-801-429-5588 if you are in the USA or Canada. Customers in other
countries should contact their local Novell office.
Maintaining Server Connections... Automatically!
Some situations require applications to run 24 hours a day, seven days a week. Often these
applications must run without supervision. The only need for human interaction may be to enter
a keyboard character to answer the "(A)bort, (R)etry" message the NETX Shell returns when it
detects a problem with a network connection. Connections can go down if a file server loses
power or if someone accidentally turns it off. Ideally, the application should run without user
intervention and most importantly, without having to exit the mission critical application.
This article describes an application named RELOG.C that was designed to be added to existing
applications. RELOG.C enables users to automatically log back in to NetWare 3.x servers after
connections are lost and regained, and to remap the workstation's drives. The addition of this
functionality allows applications to run continuously without human intervention.
RELOG.C employs only one of many design variations envisioned when the code was written.
Other situations will require you to modify the code to suit particular applications or needs.
RELOG.C is only one example program to demonstrate the measures required to accomplish the
task.
This article provides an overview of RELOG.C and addresses four basic tasks performed by the
application:
- Collecting workstation information
- Establishing when a file server has gone down
- Cleaning the Shell Table and implementing a fail within the INT 24h handler
- Determining when a file server has returned
- Reconnecting to a file server
Collecting Workstation Information
Before you can tell that a file server is down, you must collect certain vital information
about the workstation. RELOG.C records which connection IDs are in use, all file servers to
which the workstation is connected, what drives are in use and to which file servers these drives
are mapped. The information kept in the Server Connection Table - the Server Name Table,
Drive Flag Table, Drive Connection Table, and Drive Handle Table - are retrieved via the
NetWare System Calls (see Figure 4). These calls will return far pointers to the tables. Also,
RELOG.C was created using the Large Memory Model due to the ease of working with far
pointers to the Shell tables.
FIGURE 4: Getting server information (RELOG.C)
void GetServerInfo ( void )
{
BYTE compare;
int entries = 1;
union REGS inregs, outregs;
struct SREGS segregs;
//
memset ( serverInfo, 0, sizeof ( serverInfo ) );
// Server Connection Table
segread(&segregs);
inregs.h.ah = 0xEF;
inregs.h.al = 0x03;
intdosx(&inregs,&outregs,&segregs);
idNamePtr = MK_FP(segregs.es,outregs.x.si);
// Server Name Table
inregs.x.ax = 0xEF04;
intdosx (&inregs,&outregs,&segregs);
fsNamePtr = MK_FP(segregs.es,outregs.x.si);
//Drive Flag Table
inregs.x.ax = 0xEF01;
intdosx (&inregs,&outregs,&segregs);
driveFlagPtr = MK_FP(segregs.es,outregs.x.si);
//Drive Connection Table
inregs.x.ax = 0xEF02;
intdosx (&inregs,&outregs,&segregs);
driveConnIDPtr = MK_FP(segregs.es,outregs.x.si);
//Drive Handle Table
inregs.x.ax = 0xEF00;
intdosx (&inregs,&outregs,&segregs);
driveHndlPtr = MK_FP(segregs.es,outregs.x.si);
/* copy info from Shell into serverInfo[] */
while ( entries < 9 )
{
compare = *idNamePtr;
/* copy info only if Slot In Use is set in shell's
* Connection ID Table
*/
if ( compare == 0xFF )
{
memmove ( serverInfo[entries].fileServerName,fsNamePtr,48 );
memmove ( serverInfo[entries].network,idNamePtr+2,4 );
memmove ( serverInfo[entries].node,idNamePtr+6, 6);
memmove ( serverInfo[entries].socket,idNamePtr+12,2 );
serverInfo[entries].connID = entries;
}
entries ++;
/* advance pointers */
fsNamePtr = fsNamePtr +48;
idNamePtr = idNamePtr +32;
}
/* reset pointers to the beginning of the tables */
fsNamePtr = fsNamePtr -384;
idNamePtr = idNamePtr -256;
} /* end GetServerInfo () */
END of FIGURE 4
Information from the Server Connection Table and Server Name Table is stored in the
serverInfo structure. This structure allows RELOG.C to mimic the Shell information tables by
keeping the Server Name, Server Address, the Server Connection ID, and an extra byte for a flag
indicating whether or not the Server is down, without having to read it each time a change is
made. The code only maintains connections to those servers to which the workstation is
connected when the application starts. RELOG.C does not update the serverInfo structure if
another server is added after the application has been started.
The application requires this serverInfo structure because, when more than one server goes down
at a time, the Shell uses the available space in the Server Connection and Server Name Tables.
Thus, the original ordering of file servers within the Shell may be rearranged.
For example, if you originally start with five servers and servers #4 and #2 go down, if server #4
comes back first, the information for server #4 may occupy the slot previously held by server #2.
When server #2 comes back, it will occupy the next available slot (the slot previously held by
server #4). Therefore, the original ordering has been rearranged within the Server Connection
and Server Name Tables.
The returning servers pick those slots because the Slot In Use flag in the Server Connection
Table is reset from "0xFF" to "0x00" to let the Shell know that those slots are available.
RELOG.C also needs the serverInfo structure to determine which file servers are down and to
keep addresses of the server in order to "ping" or identify them later.
The drive mappings also must be saved into a static variable so they can be restored once file
servers return. This section of RELOG.C was taken from another application, MAPIT.C, as
presented and described in a previous Bullets article entitled, "Saving and Restoring Drive
Mappings," (February 1992, Volume 4, Number 2).
As a final step, an INT 24h handler must be installed to intercept the critical error that occurs
when a workstation tries to access a drive mapped to a file server to which it no longer has a
valid connection.
Establishing When a File Server has Gone Down
In order to detect when a file server has gone down, RELOG.C attempts to access every
network drive using the chdir() function. If a file server connection is no longer active, accessing
a mapped drive to that file server will trigger an INT 24h.
Cleaning the Shell Table & Implementing a "Fail"
As mentioned above, when RELOG.C fails to access a drive, its own INT 24 handler is
invoked (see Figure 5).
FIGURE 5: INT 24h critical error handler (RELOG.C)
int Handler24 ( int errval, int ax, int bp,int si )
{
BYTE componentList[54], majorRevisionNumber,
minorRevisionNumber;
int drive, entries, fsNameLen, retval, i;
int errorno;
WORD
SPXconnectionID,tempSocket,maxConnections,availableConnections;
static char msg[80];
unsigned di;
//
/* error number that is returned from DOS */
di = _DI;
if ( ax < 0 )
{
ErrorWin ( "Device error" );
hardretn ( ABORT );
}
/* information concerning which drive letter failed will be */
/* returned in the BH register */
asm { /* must place bracket here for inline assembly to work */
xor bl,bl
xchg bh,bl
mov drive,bx
}
/* check for General Failure and Network drive */
if ( ( ( di && 0xC ) == 0x01 ) && ( drv > LASTDOSDRIVE ) )
{
entries = 1;
while ( entries < 9 )
{
fsNameLen = strlen ( serverInfo[entries].fileServerName );
/* look for fileserver name that has gone down */
retval = strncmp ( serverInfo[entries].fileServerName,
maps.drive[drive].path,
fsNameLen );
if ( retval == 0 )
break; /* found */
entries++;
}
CleanShell ( serverInfo[entries].connID );
serverInfo[entries].down = 1; /* set server down flag */
hardretn(ABORT);
}
else
.
.
.
} /* end Handler24 */
END of FIGURE 5
The handler examines the BH register to find which drive number (0=A, 1=B...) has
triggered the INT 24h. Then, it checks the DI register to see which error code DOS passes to the
handler. With this information, RELOG.C determines if the operation is a "General Failure" on a
network drive. It identifies which server is associated with that drive by comparing every server
name saved within the serverInfo structure to the path parameter kept within the searchDrives
structure. Once it finds a match, it calls CleanShell().
When a Connection ID is in use, the Slot In Use flag within the Server Connection Table is set to
"0xFF" to signify this Connection ID is currently allocated. The CleanShell() routine resets the
Slot In Use flag in the Server Connection Table to "0x00" to let the Shell know that the file
server is no longer on-line. The Connection ID is passed as a parameter into this function to find
the offset within the Server Connection Table. The Shell now knows that this slot is empty and
available for reuse. It disregards any information currently stored within this slot.
Once this flag is reset, RELOG.C passes the Connection ID to the function, DeleteMapDrives().
This function deletes information concerning the mapped drives from the Drive Handle Table,
the Drive Flag Table, and the Drive Connection ID Table. Since multiple drives may be mapped
to a file server, you should probably remove all the drive references associated with that file
server. These tables must be cleared, since the NetWare Shell will not clear them in this type of
event. As far as the workstation is concerned, it still has a valid connection to the file server, so
RELOG.C must implement the mechanism to clean the appropriate tables within the Shell when
necessary. This allows the Shell to reuse these slots (see Figure 6).
FIGURE 6: Cleaning the shell (RELOG.C)
/***********************************************************************
** Reset the Slot In Use flag in the Connection ID Table
***********************************************************************/
void CleanShell ( int connID )
{
char far *tempPtr;
int i, chkStr;
//
tempPtr = idNamePtr;
/* increment pointer size of table entry */
idNamePtr = idNamePtr + ( ( connID - 1 ) * 32 );
/* put 0 in the Slot In Use flag for that entry */
*idNamePtr = 0;
idNamePtr = tempPtr;
DeleteMapDrives ( connID );
} /* end CleanShell () */
/***********************************************************************
** Delete entries from the Drive Handle Table, the Drive Flag Table,
** and the Drive Connection ID Table
***********************************************************************/
void DeleteMapDrives ( int connID )
{
int drv, sdrv, dummy;
char drvl, *pntr, chkStr;
BYTE temp;
//
/* delete all drive references to the downed fileserver */
for ( drv = LASTDOSDRIVE; drv < MAXMAPPINGS; drv++ )
{
temp = *driveFlagPtr; /* Clear Drive Flag table */
if ( ( temp != 0x00) && ( maps.drive[drv].connID == connID ) )
*driveFlagPtr = 0x00;
driveFlagPtr = driveFlagPtr + 1;
temp = *driveConnIDPtr; /* Clear Connection ID table */
if ( ( temp != 0x00) && ( maps.drive[drv].connID == connID ) )
*driveConnIDPtr = 0x00;
driveConnIDPtr = driveConnIDPtr + 1;
temp = *driveHndlPtr; /* Clear Connection Handle table */
if ( ( temp != 0x00) && ( maps.drive[drv].connID == connID ) )
*driveHndlPtr = 0x00;
driveHndlPtr = driveHndlPtr + 1;
}
/* reset pointers */
driveFlagPtr = driveFlagPtr - ( MAXMAPPINGS );
driveConnIDPtr = driveConnIDPtr - ( MAXMAPPINGS );
driveHndlPtr = driveHndlPtr - ( MAXMAPPINGS );
} /* end DeleteMapDrives () */
END of FIGURE 6
Once the Shell is cleaned, RELOG.C must implement a fail and return from the INT 24h
Handler back to the application. This procedure is accomplished via the hardretn() function. This
function restores the BP and SP registers to the values they contained before the error handler
was invoked.
Determining When a File Server Has Returned
RELOG.C determines when a file server has returned within the PingServers() routine.
This routine is called after RELOG.C tests every drive to determine if a file server is down.
The actual "pinging" of the server is accomplished by calling PingNode(). PingNode() sends a
packet on socket "0x0456" to the address taken from the Server Information Table. (The
complete source code for PingNode() is included in RELOG1.EXE.) This packet asks the node at
that address to return a packet to the function with its SPX diagnostic socket.
If the requested node does not respond within four seconds, the function assumes that the node is
unable to respond and returns a status 252. (PingNode() only works if diagnostics is supported
for that node, and all NetWare 3.x file servers support diagnostics.) In the example program, the
serverInfo structure keeps track of what servers are down and only those servers are "pinged"
(see Figure 7).
FIGURE 7: "Pinging" servers with PingNode() (RELOG.C)
void PingServers ( void )
{
int entries;
BYTE majorRevisionNumber, minorRevisionNumber,
componentList[54];
WORD maxConnections,availableConnections,
SPXconnectionID;
WORD tempSocket;
cCode = SPXInitialize( &majorRevisionNumber,
&minorRevisionNumber,
&maxConnections,
&availableConnections);
tempSocket = 0x00;
cCode = IPXOpenSocket ( (BYTE *)&tempSocket, 0 );
*(WORD *)destination.socket = (WORD)IntSwap ( 0x0456 );
for ( entries = 1; entries < 9; entries++ )
{
/* search only for those servers that are down */
if ( serverInfo[entries].down == 1 )
{
/* get the server address */
memmove (destination.network,
serverInfo[entries].network,4);
memmove (destination.node,
serverInfo[entries].node,6);
/* call to ping a particular server */
cCode = PingNode ( &destination );
if ( cCode == 0 )
{
printf ( "Server %s is up\n",
serverInfo[entries].fileServerName);
ReConnectServer ( entries );
}
}
}
IPXCloseSocket ( tempSocket );
} /* end PingServers () */
END of FIGURE 7
Reconnecting to a File Server
Once RELOG.C determines that a downed server has returned, it reads the server
information in the serverInfo structure and attaches the workstation to that file server with the
AttachToFileServerWithAddress() function. If successful, it calls the LoginToFileServer()
function and updates the serverInfo structure.
Note: RELOG.C allows you to enter the user name and the password via the keyboard.
However, different applications require different solutions for this situations. It is up to you to
implement an efficient method of accessing user names and passwords for logging into the
server.
As mentioned in the beginning of the article, a file server's information may not
reoccupy the same slot in the Shell table, particularly if more than one file server goes down at a
time. Thus, the connID field in the serverInfo structure is updated with the Connection ID
returned earlier from the AttachToFileServerWithAddress() function call. The down field is also
reset to zero and it is safe to remap the drives back to the file server once again.
Although ResetDriveMappings() is fully explained in the February 1992 issue of Bullets, some
additional explanation is in order since the original code was modified for RELOG.C. First, only
those mapped drives associated with the particular file server are remapped. RELOG.C does not
remap every drive again. Second, the searchDrives structure was updated as follows:
map.drive[drv].connID = newConnID;.
This modification associates the drive with its new Connection ID returned from
AttachToFileServerWithAddress(). Otherwise, the code for ResetDriveMappings() operates
essentially as it did when it was originally presented in previous issues of Bullets.
Although this article explains the basic operation of RELOG.C, the code can be tailored to meet
the demands of existing applications. RELOG.C is designed to run with NETX.EXE. It will be
tested with VLM.EXE in the future, and the results will be included in the README file
attached to RELOG1.EXE. The code was tested with multiple servers, but it does not take into
account all possible events that may occur. Therefore, it is up to you to initiate appropriate error
routines where necessary.
The complete source for RELOG.C is available on CompuServe on Novell's NOVLIB forum.
The self-extracting file named RELOG1.EXE will be posted to Library 1, and moved to library 7
after 30 days. If you have additional questions about any of the issues raised in this article, call
1-800-NETWARE (1-800-638-9273) or 1-801-429-5588 if you are in the USA or Canada. In
other countries, contact your local Novell office.
Creating ALMs
Novell's Visual AppBuilder is a visually-oriented 5GL development environment in which
users connect objects and functions together to create custom applications. The objects and their
associated functions are known as AppWare Loadable Modules (ALMs).
The ALM SDK allows you to create new ALMs. Through the creation of ALMs, developers can
add new objects and functions to the development environment. These additions to the object
library appear as if they were original components. In fact, architecturally speaking, they are just
the same as the original components.
But Novell does not stop there because Novell is committed to making the AppWare
development environment an open development architecture. In support of its commitment,
Novell also provides an open interface to AppWare that allows third-party developers to create
their own 5GL development tools for working with ALMs.
The Novell Toolmaker SDK provides the interface for development of 5GL tools for the
AppWare environment. This SDK will be available in the first quarter of 1994.
AppWare's open development environment distinguishes it from virtually all other development
systems, and makes it the most expandable application builder today. Novell believes that
providing a wide range of ALMs, as well as a wide range of 5GL tools for the AppWare
environment will ensure the success of AppWare as well as its customers.
Introducing the AppWare Bus
The AppWare Bus allows you to create new ALMs that can be added to the Visual
AppBuilder Object & Function Palette (or any 5GL tool created with the Novell ToolMaker
SDK). You are given access to the AppWare Bus at a number of very strategic points, so that
virtually any imaginable functionality is within your grasp.
The architecture of the AppWare Bus makes it possible for the AppWare Bus components to
communicate with each other. The architecture also defines where and how you may alter
components or introduce new ones.
ALMs consist of the following components. (Notice that some components are provided by
Novell, others are created by the developer as components of the ALM, and still others are
provided by the user via Visual AppBuilder.)
- Application Shell - provided by Novell
- Methods (event handlers) - created by the developer
- Events - created by the developer
- Objects - used in Visual AppBuilder by the user
- Function Chains - used in Visual AppBuilder by the user
The following discussion of the application shell, methods and events, objects, and
function chains is specific to creating ALMs for use in Visual AppBuilder.
The Application Shell
At the core of any ALM is a runtime engine called the shell. The shell is responsible for:
- Launching the application
- Loading and unloading code routines
- Storing and loading objects
- Managing event transmissions between objects.
When you call the AppWare Bus utility routine, you are instructing the shell to perform
one of these actions.
The shell performs these actions transparently; you don't need to know anything more about it
than to assume it performs these basic tasks. When an application is compiled in Visual
AppBuilder, the shell is built into the application automatically.
Events & Methods (Event Handlers)
The event is the runtime communication vehicle for the AppWare Bus. Events act as
messengers for instructions and information. Object types "listen" for specific events, and
respond in appropriate ways. With few exceptions, the event mechanism operates at runtime
only. Events are not commonly used at design time.
Methods (a.k.a. event handlers, in Windows) are responsible for actual code implementation of
application functionality. Methods respond to events from the shell, which receives events from
the OS and other methods. In the Macintosh environment, methods are known as just that,
methods. In the Windows environment, methods are known as event handlers. In either
environment, their basic function is the same: to excecute some low-level routine in response to
an event from the shell.
For example, the shell receives operating system events, such as "mouse down" and "update"
events, queues them, and later sends them to Window methods (event handlers), among others.
You attach methods (or event handlers) to objects via their object type. Each object type -
Window, Menu, Database - has a set of method-to-event (event handler) connections.
Objects
Objects are manipulated at runtime by methods (event handlers) that are invoked from
AppWare Bus events, developer-defined events, or under user control by function events. Object
data is set up at design time in Visual AppBuilder. Internally, objects contain one ore more
developer-defined object data blocks to contain such user- selected information.
Function Chains
Visual AppBuilder users connect functions in a sequence to form function chains. A
function chain tells the shell the order in which to invoke functions' methods (event handlers) at
runtime, in response to a particular signal event. Signal events come only from objects.
ALMs & the AppWare Bus
The AppWare Bus is one of the first commercially available software engines for
managing intelligent software components. The AppWare Bus does for applications what the
hardware bus did for personal computers -it manages and coordinates the interaction of ALMs.
The Appware Bus provides two main functions: 1) it enables developers to create ALMs, and 2)
it provides third-party developers with open access to the AppWare Bus API. Third party
developers can not only create ALMs, they can also create their own 5GL development tools,
similar in function to Novell's Visual AppBuilder.
The AppWare Bus provides an interface for each of these functions:
- AppWare Bus Module Interface (ABMI) - used by developers to create ALMs.
Provided in the ALM SDK, ABMI consists of the ALM Management Routines.
- AppWare Bus Tool Interface (ABTI) - used by developers to create 5GL development
tools for the AppWare environment. Provided in the Toolmaker SDK, ABTI consists of the
Project Management and Compiler Routines.
The ALM Management, Project Management, and Compiler Routines are the routines that
make up the AppWare Bus API.
ALM Management Routines
ALM Management Routines allow you to query the bus to determine the presence of
objects and functions, to instantiate objects (create instances of objects), to invoke attribute
editors of objects, and to manage and coordinate runtime interaction among ALMs.
Querying routines can be used to describe the number and types of objects and functions that
have been instantiated. Instantiation routines support the capability to "drag and drop" new
objects directly into the layout. These object instantiation routines operate at design time and at
runtime.
Routines are also provided to invoke the attribute editor for another object. These routines allow
you to invoke another editor from within the original editor. An object only needs to use these
routines if it references other objects. These routines operate at design time.
Routines that control interactions among ALMs operate at runtime only and determine how
objects respond to events. For example, the AppWare Bus includes a start-up event. When this
event is sent to an object, the object responds by invoking its methods. For example, when the
Window object receives the startup event, it responds by opening any window instances that the
developer designated to be opened at startup.
Project Management Routines
Project Management Routines allow the developer to determine the format of AppWare
projects and be able to read and write AppWare project files. These routines allow third-party
developers to create their own AppWare application projects that work side-by-side with other
application projects created with Visual AppBuilder and other third-party development tools.
Compiler Routines
The compiler routines are provided to allow you to compile objects and functions you
have created into applications. These routines provide third-party developers with open access to
the AppWare compiler routines.
Constructing an ALM
To create ALMs using the ALM SDK, you must have a thorough understanding of the
operating environment for which you are building the ALM. The following are the requirements
for developers building ALMs for the Macintosh and Windows environments:
- For Windows, you must be familiar with Windows from an end user's perspective;
have a good understanding of the Windows SDK; have a working understanding of Pascal, C,
C++, or Assembly; and be familiar with the process of writing and compiling a DLL.
- For the Macintosh environment, you must be thoroughly familiar with the Macintosh
from an end user's perspective; have a good understanding of the Macintosh Toolbox and
operating system (as described in Apple Computer's Inside Macintosh); have a working
understanding of Pascal, C, or Assembly; and be familiar with the process of writing and
compiling a code resource, such as CDEF, WDEF, or MDEF.
In the AppWare Bus, you create objects, functions, and methods (event handlers) by
writing and compiling code routines, then adding them to the palette of components presented to
the user in the Visual AppBuilder Object & Function Palette. One unique feature of the AppWare
Bus is that you may write your additions in whichever language you prefer as long as your code
meets the requirements for your operating environment as follows:
- In Windows, the language must be suitable to create a DLL.
- In the Macintosh environment, your development system must accept an MPS .o library
file. (This file contains about three dozen utility routines required to access the AppWare Bus.)
Your system must have the ability to compile and save a code resource.
In general, the steps required to create ALMs are as follows:
- Obtain a Component ID.
Every component must have a unique four-character ID. Contact Novell Developer Support
to obtain an ID for the component you are creating.
- Write and compile the code.
In the Macintosh environment, you must collect the individual resources that build the
component, and add them to the resource fork of a file. In Microsoft Windows, all of the code
and resources for all of the functions and events associated with your object type can be placed in
one DLL, simplifying the organization of the DLLs required to run a compiled application.
- Load and configure the component.
You load and configure components through the Configuration Editor.
Distributing Your ALM
You do not need to understand conventional object oriented programming to build the
AppWare Bus objects and functions. To develop objects and functions in the Macintosh
environment, you must be reasonably proficient in using any typical Macintosh development
system, like THINK Pascal or C, or MPW Pascal, C or Assembly. For Windows, you must be
proficient in Windows development.
The ALM SDK and the AppWare Bus handle most object orientation automatically, leaving you
free to develop objects and functions with more functionality and in a fraction of the time.
Ordering the ALM SDK
To order the ALM SDK, call 1-800-NETWARE (1-800-638-9273) or 1-801-429-5588 in
the USA and Canada. In all other countries, please contact your local Novell office.
Companies Make Plans for AppWare
As a developer, you know it is important to determine the direction that the industry is
heading early so that you can make your own corresponding changes in product direction and
focus. Bullets would like to provide you with a brief glimpse into how some industry leaders are
making plans to use AppWare and AppWare Loadable Modules (ALMs) to make their network
application development faster and more efficient, while enabling it to run on more platforms
transparently.
Gupta to Design Database ALMs
At BrainShare Dallas '93, Gupta announced it will build an ALM version of its best selling
SQLBase database engine and a Quest ALM for use in Visual AppBuilder, as well as deliever an
AppWare version of its SQLWindows development tool. Gupta announced it will also be
incorporating the AppWare Foundation in the next generation of all of its SQLWindows and
Quest products. The announcement means that in the near future developers will be provided
with tools that will make them more productive and effective in producing network applications.
The Gupta ALMs will provide for development of full-featured multi-database applications.
Gupta's standalone SQLBase ALM will be a bundled component of every Visual AppBuilder.
The embedded SQL engine has a five megabyte capacity. The bundling agreement gives Visual
AppBuilder developers access to over 10,000 corporate developers. The SQLBase ALM is
scheduled for completion in January of 1994.
Gupta also announced plans to release a Quest ALM. Quest is a graphics data access and
reporting tool that provides corporate and in-house developers with query, form, report, and
catalog functions. Gupta plans to convert these functions into ALM components. Using Visual
AppBuilder, developers will have access to a full-featured database application by quickly
implementing one or more of the Quest components in their own applications.
And for developers, the news gets even better because Gupta will be implementing the core
technologies of AppWare (the AppWare Bus and ALMs) in its SQLWindows development
environment. Specifically, SQLWindows will be able to take advantage of the ALMs from
Novell and third-party developers of ALMs. Already designed for ease in programming (by
circumventing C and the Microsoft Windows Tookit), SQLWindows immediately becomes an
even more desirable development environment because developers are able to construct complete
applications by linking ALMs.
Gupta plans delivery of the SQLBase ALM by June 1994 and the Quest ALM during the third
quarter.
By developing all of its next generation development tools to the AppWare Foundation, Gupta
SQLWindows will be be available on both Macintosh and UNIX, in addition to the Microsoft
Windows platform for which it was originally written and it will gain additional portability as
new platforms are added to the AppWare Foundation.
Borland, WordPerfect Announce Development Plans for AppWare
This month, Borland International, Inc. announced that it will incorporate Novell's
AppWare Foundation into its ObjectWindows Library (OWL) technology to provide developers
with comprehensive C++ based cross-platform development library. ObjectWindows is an
application framework that provides a robust set of pre-fabricated, reusable classes for
developing object-oriented Microsoft Windows applications.
With over 300,000 users, it is the most popular C++ framework for developing applications for
Microsoft Windows in C++. The AppWare Foundation will provide a set of C++ libraries that
give developers cross-platform functionality, regardless of operating system, graphical user
interface, or network service. Developers write to a single API and then simply recompile for
different operating environments.
As a leading cross-platform developer, WordPerfect followed with the announcement that it will
be using Novell's AppWare Foundation as a standard development platform in WordPerfect's
Core Technologies department. This department is responsible for developing core code and
functionality that is product- and platform-independent. The core code is then incorporated into
all of WordPerfect's products.
Because it is so time-consuming and resource-intensive to produce cross-platform code,
WordPerfect was looking for a way to shorten the time it takes to bring its products to market
across multiple platforms. The AppWare Foundation will be the key element in allowing the
WordPerfect developers to bring their products (running on multiple platforms) to market in a
fraction of the time required before.
NetWare API Call Fails with 0x8801 (NetWare Client SDK v1.00d)
The programming example on pp 256-257 of the Netware Programmer's Guide for C
(Version 1.0, June 1993 ed.) fails on NWGetNextConnectionID() with a return code of
"0x8801." Several valid values were tried as the parameter to this function call, but all caused the
function to fail with 0x8801.
To make the example run successfully, make the changes outlined in Figure 8.
FIGURE 8: Necessary Changes to example code with NWGetNextConnectionID()
memset (connListBuffer, 0, 8);
cCode = NWGetConnectionList (0, connListBuffer, 8, &numberOfConnections);
connHandle = connNum= 0;
do {
if (cCode = NWDSGetConnectionInfo (connListBuffer[connNum],
NULL, &connType, NULL, serverName,
NULL, NULL, NULL, NULL, NULL))
printf ("\nNWNDSGetConnectionInfo failed with %04X.", cCode);
else
{
printf ("\n\n%d\tID = %04X", ++connNum, connListBuffer[connNum]);
printf ("\nServer Name = %s", serverName);
printf ("\nConnection Type = ");
if (connType & NWNDS_CONNECTION)
{
printf ("NDS");
if (connType & NWNDS_AUTHENTICATED)
printf (" (Auth)");
else
printf (" (Not Auth)");
}
else
{
printf ("Bindery");
if (connType & NWNDS_AUTHENTICATED)
printf (" (Logged In)");
}
}
} while (connNum
CreateScreen() And NetWare 4.01 (NLM SDK v3.00)
Some NLMs developed under NetWare 3.1x that access the System Console screen
receive messages from the NetWare 4.01 Operating System regarding unreleased memory
resources when the NLM terminates.
This situation is apparent in NetWare 4.01 because CreateScreen() now returns a screen handle to
each screen for each NLM calling CreateScreen(). To remove the unreleased memory resources
warning message, call DestroyScreen() before terminating the NLM.
Btrieve NLM Allows Duplicate Records (NetWare Btrieve (NLM) v6.10b)
Btrieve NLM v6.10b will insert duplicate records into a Btrieve v5.x format file under the
following circumstances:
- If each page holds only one record
- If the Btrieve file is in v5.x format
- If an Insert operation returns a status 5 (Duplicate Key Value), and then a subsequent
Insert is successful. In this case, the successful record as well as a data page with the record that
failed is written to the file.
If a key path is always used to retrieve data, then the "bad record" (with the duplicate
value) will never be seen. However, if STEP operations are used, Btrieve will return the
duplicate records that were written to the data pages. Thus, a BUTIL -RECOVER followed by a
BUTIL -LOAD will produce duplicate errors.
To avoid this situation, rebuild files in Btrieve v6.x format or use a page size that can hold more
than one record.
Documentation For xConvert and XQLConvert (NetWare SQL v3.0)
The documentation for the NetWare SQL functions xConvert and XQLConvert describes
the sRetVal parameter for Option 0 as follows: You must initialize sRetVal so that it is at least as
large as iDSize. If iDSize is smaller than the default mask or the mask you specify, NetWare
SQL returns the number of bytes specified in iDSize and a non-zero status.
In past versions of NetWare SQL, if iDSize was smaller than the mask, but the data would still
fit into that size of a buffer, the data was returned. In NetWare SQL v3.0, the size checking is
done first, and if the iDSize parameter is not large enough for the mask, the buffer is filled with
the "*" character.
For xConvert and XQLConvert to properly convert NetWare SQL data, the iDSize parameter
should be set to a value at least as large as the size of the mask, and the sRetVal buffer should be
allocated to at least that size.
Alternatively, the application can pass in a shorter mask.
NetWare Btrieve in Primary I/O Engine (NetWare Btrieve (NLM) v6.10)
With Btrieve v6.10b, BROUTER and BTRVSTUB.NLM are provided to allow NetWare
SFTIII users to run Btrieve from the I/O engine. These components do not work if run from the
Primary I/O engine. However, they do work if they are run in the Secondary I/O engine. Only
run Brouter/Btrvstub in the Secondary I/O engine.
AIOCOMX.NLM & NLM SDK v3.0 (NLM SDK v3.0)
The AIOCOMX.NLM dated June 3, 1993, that comes with the NLM SDK v3.0, will not
properly load. It returns with the error message:
Loader cannot find public symbol: AIORegisterDriverA
An incorrect version of AIOCOMX.NLM shipped with the NLM SDK v3.0. Continue using the
older version of AIOCOMX.NLM.
New Default NDBTIMEOUT (NetWare SQL v3.0)
After applying the v3.00d patches to NetWare SQL, the OS/2 default NDBTIMEOUT
value is (-1). This timeout value tells NetWare SQL to wait indefinitely for a response from the
file server. When run with the NetWare OS/2 Requester v2.01, NetWare SQL processes can wait
for an indefinite period.
The timeout value should not be set to wait indefinitely. When a server has gone down the
NetWare SQL OS/2 Requester should be able to time out. Always set the NDBTIMEOUT to a
specific value using the following syntax:
SET NDBTIMEOUT=
This statement can be executed from the workstation's CONFIG.SYS file, or from the command
line before the first NetWare SQL application is started (i.e., before NDBCOMM.DLL loads).
The timeout value is measured in milliseconds, so an example setting is:
SET NDBTIMEOUT=900000 (NDBCOMM will wait 15 minutes for a reply)
A number of NetWare SQL queries may cause NetWare SQL to build one or more temporary
sort files. When tables with many records are involved, this process may take some time, in
which case you may need to set this parameter to a high value.
Reentrant NLMs & _Prelude (NLM SDK v3.00)
When writing reentrant NLMs, be sure to call _Prelude from within the NLM that is being
loaded. This method is the standard way of writing reentrant NLMs. However, some developers
have attempted to write library NLMs which store common functions for other NLMs and are
also defined as reentrant. These library NLMs then call _Prelude for all of their other reentrant
NLMs. This method tricks CLIB into thinking the main function is being executed for the library
NLM, not the NLM that was actually being loaded.
To avoid problems, always call _Prelude from the NLM that you are loading.
Fields Required To Submit Queue Job (NetWare Client SDK v1.0d)
The documentation for the NetWare API NWCreateQueueFile2() in the NetWare Client
SDK implies that the function will fill out the job structure. It does not mention that several
fields in the job structure must be filled out before it is called.
The targetServerID, jobControlFlags and targetExecutionTime fields of the job structure must be
filled in before the function will work. The targetServerID field is usually set to "0xFFFFFFFF"
so that any server can service the job. The targetExecutionTime field will normally be filled with
six bytes of "0xFFs" for immediate execution. Finally, jobControlFlags is usually set to
"QF_AUTO_START."
Inconsistent SPX Header Fields (NLM SDK v3.0)
The documentation for the NLM SDK v3.0 incorrectly states that, in the SPX header, "The
allocNumber minus the ackNumber equals the number of posted listens outstanding on the
connection socket." Actually, the allocNumber and ackNumber are always the same regardless of
how many outstanding listens are posted on the connection socket.
The documentation will be corrected in the next release of the SDK.
NetWare 4.0x & "???SERV" NLMs (NLM SDK v3.0)
The NOVSERV, PARSERV, and SERSERV NLMs from the WATCOM C Compiler
v9.01 will abend NetWare 4.0x servers at load time.
To prevent this abend, contact the WATCOM BBS at 1-519-884- 2103 and download
NLMDEBUG.ZIP from library 17. This file contains ???SERV4 NLMs. However, since
WATCOM no longer supports v9.01, you may wish to upgrade to v9.5 instead.
When Does Btrieve Delete Delta Files? (NetWare Btrieve (NLM) v6.10b)
With Btrieve NLM 6.10b, Delta files are deleted as soon as the End Continuous
Operations command is executed. Upon executing this operation, Btrieve writes the updates from
the Delta files to the corresponding Btrieve files and deletes the Delta files.
Versions of Btrieve before v6.10b delete Delta files created during continuous operations after
the last user closes the corresponding Btrieve files. When End Continuous Operations is
executed, updates are made to the Btrieve files and the size of the Delta files is changed to zero.
However, the Delta files are not deleted until the last user closes the actual Btrieve files.
Mismatched Quotes Generates Status 298 (NetWare SQL v3.00d)
With NetWare SQL v3.00d, using the EXISTS statement with a SELECT statement
generates a status 298 (Mismatched Quotes). Figure 9 contains an example illustrating this
sequence of calls. Adding the extra parentheses around the first EXISTS statement resolves this
status code.
FIGURE 9: EXISTS statement requiring extra parentheses
SELECT RegionCd, CanTrack, 'DAL', '1993', '005000', 'CDITTM01',
'', '', '', 'N', 'N', 'E', '', CanRecvd
FROM CanSkill A
WHERE SkillCd = ' 858' AND
SkillYrs >= 5 AND
CanRecvd >= '05/17/93' AND
CanRecvd <= '06/15/93'
AND
(EXISTS (SELECT SkillCd from CanSkill B
WHERE (B.CanTrack = a.Cantrack AND
B.RegionCd = A.RegionCd) AND
SkillCd = ' 397' AND SkillYrs >= 3))
AND
EXISTS (SELECT CanTrack FROM Candidat C
WHERE A.CanTrack = c.CanTrack AND
A.RegionCd = C.RegionCd AND CanStatus = 'Y' )
END of FIGURE 9
Dictionary Files for NetWare SQL (NetWare SQL v3.00)
When creating a new dictionary with NetWare SQL (or XQL) v2.x, FIELD.DDF is
created with four indexes and INDEX.DDF is created with two indexes. With NetWare SQL
v3.0, each of these files is created with an additional index. When NetWare SQL attempts to
access a set of dictionaries created with a prior version, it automatically adds the extra index to
both files when it opens the dictionary. If these indexes are added incorrectly, a status 6 (Invalid
Key Number) may occur during later processing.
For example, a customer had a set of dictionaries that had become corrupt, and the attempt to add
the new index to INDEX.DDF produced a status 5 (Duplicate Key Value). When attempting to
access these dictionary files with Xtrieve PLUS, the failed attempt to create the index was not
reported to the user, but a later attempt to bring up a file in a view produced the status 6 as a
result of the missing index.
The process of adding the new indexes should be transparent to the user, and will be performed
the first time the dictionary is used with NetWare SQL v3.0. If the dictionary has become
corrupt, it will have to be rebuilt before NetWare SQL v3.0 will be able to use it. Refer to the
January 1993 issue of Bullets for more information on rebuilding corrupt dictionaries.
NCONTROL Parameter Options (NetWare NCONTROL v2.6)
The documentation for NCONTROL states that, to create error and status log files, you
should pass a "/E" and a "/L" parameter. However, these parameters must be issued in lower
case, as follows:
MYTEST /e=MYTEST.ERR /l=MYTEST.LOG
If you issue the command with upper case parameters (i.e., /E and /L), the application will
execute, but the log files will not be created.
Setting Volume Space Limit (NetWare C Interface for DOS v1.20)
The SYSCON utility allows you to restrict volume disk space for an object by setting the
Limit Volume Space flag. According to the NetWare C Interface for DOS manual, you can
remove this restriction programatically by setting the restriction parameter to zero in
SetVolRestriction(). However, after passing this parameter, NetWare returns the error message,
"Insufficient Disk Space," when you try to create a file.
Passing zero in the restriction parameter clears the Volume Space Limit, but it does not reset the
Limit Volume Space flag. To clear both, pass the value "0x7FFFFFFF" in the parameter.
GetSpecificCapture-Flags() & VLM.EXE v1.03 (NetWare C Interface for DOS v1.2)
After a EndSpecificLPTCapture() call is performed on a specific LPT,
GetSpecificCaptureFlags() does not return the capture flags that were previously set for that LPT
under VLM.EXE v1.03. This call works under NETX v3.32 and earlier.
This call is not supported under VLM.EXE v1.03. After EndSpecificLPTCapture() is called, the
status of the capture flags for that LPT is undetermined. For the application to recapture the LPT
with the same flags, the application must perform a GetSpecificCaptureFlags() and save the flags
to a static variable or a file, and then retrieve that information before the next
StartSpecificLPTCapture().
Fast Answers to Common Questions
NetWare
Q - Is there any way to specify the "hold" option at capture time?
A - You can't actually specify the "hold" option at capture time. There is no flag in the
CAPTURE command allowing you to hold a job. Technically, it is not possible with the current
implementation of the shell, since the HOLD flag is an attribute of the job in a print queue. At
capture time, the job does not yet exist; it is created with the first byte that you send to the
captured port.
There are, however, two ways to put a "hold" on the print job:
- Specify a non-existing form number. Doing so will leave the job untouched until
you change its form number (e.g. in PCONSOLE).
- Use the CAPTURE TI=0 NoAuto command to leave the job in the queue until you
explicitly run another CAPTURE or ENDCAP. This solution has the disadvantage that some
NetWare-aware applications internally send their own ENDCAP signal to the server, which
causes the job to be printed.
NLM SDK v3.0
Q - Can I obtain the NetWare serial number without being logged in as Supervisor
equivalence?
A - If you are logged in you can use "SYSCON/File Server Information" to retrieve
the serial numbers of any server that you are attached to as Supervisor or "SV" equivalence.
If you do not have "SV" equivalence, SYSCON will not display the serial numbers.
The NetWare APIs do not have this restriction. Use SERIAL.ZIP on CompuServe/NovUser
containing two tools that allow you to retrieve the serial numbers of servers from an NLM or
from a DOS client without even being logged in.
Q - The documentation for NWGetBroadcastMessage() and
NWSendBroadcastMessage() and the hints in the Netware Programmer's Guide for C mention
the option of exchanging messages of more that 58 bytes. It states, "For NetWare v3.11c and
above, the message can be from 1 to 254 bytes including a null terminator".
I have the most recent version of NetWare 3.x (v3.11). but can only exchange a maximum of
58 bytes. Why?
A - You can send messages with more than 58 bytes, but the NCP call
GetBroadcastMessage (Fct E1 01) returns up to 58 bytes This has been tested and verified with
VLMs on NetWare v3.11 and CLIB v3.11d.
NetWare 4.0x behaves differently. If you send a broadcast message to a connection on a
NetWare 4.0x file server you will be able to retrieve the message in several fragments with a
maximum of 55 bytes each. For example, if someone sends a 200- bytes broadcast message to
you via a NetWare 4.0x server, you must submit four separate NCPs to retrieve the info in four
segments of 55, 55, 55, and 35 bytes.
Q - But, what about buffering in the server? A file server will only store one broadcast
message per connection--does this long 200-byte message count as 1 or 4 messages?
A - The 200-byte message counts as one message.
Q - Does ScanTrustees() have any specific return codes, or does it return a specific
value in one of its parameters if it cannot find any more trustees? The manual is not clear.
A - This API returns decimal 156 (0x9C ERR_NO_MORE_TRUSTEES) as a return
code if it cannot find any trustees for the specified path.
Tip The MSGLIB.EXE which ships with the NLM SDK 3.00 causes a
memory exception/machine hang/machine reboot. An updated version of IBM$RUN.OVL is
required which allows MSGLIB.EXE to to handle long messages. This file is available on
Novell's NDEVREL forum (Library 7, IBMRUN.ZIP).
NetWare Client SDK
Q - What do I need to do to my program to make it compatible with Novell's
VERSION.EXE utility? That is, what C code needs to be in the program so that VERSION.EXE
will display the version?
A - Include the following global declaration in the source code:
char *VERSION="VeRsIoN=x.x";
where "x.x" is the version number.
NDEBUG.NLM
Tip NDEBUG fails to release some resources (e.g., short term memory allocations)
when unloaded. Also, from NDEBUG, if you issue the following command:
#process load xxxx
to load xxxx.NLM to debug, the display box reports an error even though the NLM loads
successfully. Currently, there is no workaround for this situation.
NetWare SQL
Tip With NetWare SQL v3.00d, the FETCH call will always return at least
one record, with an aggregate value of zero for SUM, AVG, and COUNT; and a null value for
MIN and MAX, which will depend on the type and size of the field used in these aggregates. The
data returned from a v3.00d aggregate function complies with the ANSI SQL Standard
definition.
In versions of NetWare SQL before v3.00d, aggregate functions may or may not have
returned a record. For example, the aggregate function, SUM, would not return a record if there
were no records to sum according to the restrictions placed on the view. Thus, a FETCH call
would yield a record count equal to zero.
Q - When I load NSREQ with "/w" set to two and the "Tasks" variable in
NOVDB.INI also set to two, I can only run two Windows NetWare SQL applications. The third
application receives a status 2007 (Invalid Parameter) on XQLLogin. Also, if the maximum
number of sessions has been reached, this status code may be returned. Why does NetWare SQL
return this status code?
A - Usually, if NetWare SQL reaches the maximum number of sessions, it returns a
status 266 (Number of Sessions Logged in Exceeds Maximum). However, the application may
receive status 2007 instead of 266. For example, if NetWare SQL five-user version is loaded at
the server, when the sixth application tries to login to the database, NetWare SQL will return
different status codes depending on the values specified for "/w" and "Tasks." In this situation, if
"/w" and "Tasks" are set to five, status 2007 is returned; if "/w" and "Tasks" are set to six, status
266 is returned.
Be sure to specify appropriate values for "/w" (on the NSREQ command line) and "Tasks"
(in the NOVDB.INI file).
Q - When I use XQLI to execute a CREATE TABLE statement such as:
CREATE TABLE tablename
USING filename
(Code CHAR(3), Name CHAR(15))
WITH INDEX ( Code UNIQUE )
The table has an index, but I can't drop it later via the DROP INDEX statement. How can an
index that is not named be dropped from a table in NetWare SQL?
A - To drop a non-named index, it must be dropped at the Btrieve level. That is, the
BUTIL -DROP command must be used. Next, use Xtrieve PLUS to change the
DDFs. To do this operation, use the DICTIONARY\REORGANIZE options. Select the "Yes"
option when the REPLACE window pops up. When you come to the Index section, use the
ESCAPE key to bring up the menu and select the REMOVE option. Delete the index definition.
Finally, select the FINISH - DON'T CREATE option. Now the definitions within the DDFs
match the Btrieve file. To add an index, use the CREATE INDEX statement to add an index with
an index name.
NetWare Btrieve
Tip Delaying Service Advertising Protocol (SAP) packets for more than one
minute causes all file servers on the other opposite side of a CISCO router from the Btrieve NLM
to delete the NLM from the bindery, producing a status 20 or a status 95.
CISCO routers can be configured to delay SAP packets by setting the NOVELL
OUT-SAP-DELAY parameter in the port configuration setup. The LENGTH
parameter is measured in milliseconds. To prevent the Btrieve NLM from being deleted from the
bindery, be sure to set this parameter to a value that will not delay SAP packets too long.
Tip Btrieve 6.x files that have a page size of 512K cannot exceed two
gigabytes in file size. This limit results from the way Btrieve 6.x files use PAT pages to access
the pages of the Btrieve file and is calculated as follows:
128 (# of pages that a PAT can reference)
* 32K (# of PAT pages a Btrieve file can contain)
* 512 (the physical size of the Btrieve page)
----------------------------------------------------
2 Gigabytes total file size
If you need to make a larger file, use a larger page size. Files with any other page size can grow
up to four gigabytes in size.
Q - I am using NetWare Btrieve v6.0, but sometimes I need to be able to switch back
to a NetWare Btrieve 5.x system. How can I do this?
A - If your files are still in NetWare Btrieve v5.x format, you can load Btrieve v6.x
with the -d parameter, forcing new files to be generated in 5.x format. Otherwise, the only way to
switch back to Btrieve v5.x is to save the contents of your v6.x format file, then generate a v5.x
clone and load the data into the v5.x file.
Q - When running BREQUEST in an OS/2 DOS box, I receive a status 12 when I try
to open a file that I know exists. Why can't I open the file?
A - This status code can be returned when running BREQUEST with v2.00 of the
NetWare OS/2 Requester. Make sure to update your requester to v2.01.
Tip The following error messages may be displayed when running the SAVE
or RECOVER options of BUTIL.NLM v6.10x:
BUTIL-6.10-53: Btrieve error 59 occurred for file or command butiltmp.btr.
BUTIL-6.10-72: BUTIL has recovered 0 records.
BUTIL-6.10-9: The command did not complete due to an unrecoverable error.
These messages result whenever BUTIL tries to create a file called BUTILTMP.BTR in the same
directory as the Btrieve file to be saved or recovered, and this file already exists in the directory.
To avoid these messages, delete or rename the BUTILTMP.BTR file before performing the
BUTIL -SAVE or BUTIL -RECOVER. BUTILTMP.BTR is a temporary file created by BUTIL
so that it can check if the current Btrieve engine running on the server supports "chunk"
operations.
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.
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.
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.
Publisher: Mad Poarch
Editor: Kirk R. Humphries
Design: Creative Services, Provo
Articles: Ken Lowrie, Drue Reeves & Michael Spano
News: Holly Roff
Contributors: Linda Anderson, Neda Eslami, Kumar Gaddam, Laura Heater, Clint McVey,
Chris Ojeda, Matt Pinsonneault, Bill Prentice, Bob Quinlan, Drue Reeves, Wolfgang Schreiber,
Michael A. Spano & Aslam Tejani
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.
1993 Novell, Inc. All rights reserved. Novell, the N design, NetWare, Btrieve, XQL and
LANalyzer are registered trademarks; LAN WorlShop, NetWare SFT III, NetWare Loadable
Module, NLM, Global MHS, NetWare MHS, NetWare System Calls for DOS, NetWare SQL,
NetWare Btrieve, NetWare C Interface for DOS, Report Executive, NetWare Asynchronous
Services Interface (NASI), NetWare Management System, Xtrieve PLUS, DeveloperNet Labs,
UnixWare, AppWare, AppWare Foundation, AppWare Loadable Module, ALM, AppWare Bus,
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 is a trademark of Microsoft Corporation. Apple and
Macintosh are registered trademarks of Apple Computer, Inc. CompuServe is a registered
trademark of CompuServe Corporation. Sun Microsystems and NFS are registered trademarks 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. WordPerfect is a registered
trademark of WordPerfect Corporation. SQLBase and SQLWindows are registered trademarks,
and Gupta and Quest are trademarks of Gupta Technologies, Inc.
|