Novell is now a part of Micro Focus

Writing NetWare Applications with Borland Delphi

Articles and Tips: article

WOLFGANG SCHREIBER
Manager Developer Support
Corporate Developer Relations

01 Aug 1996


Borland's Delphi allows developers an extremely easy and efficient method to create object-oriented, event-controlled Windows applications with a minimum of coding. Therefore many programmers have switched to Delphi as their primary development platform. Typically Delphi makes Windows programming easier than other visual development platforms, while still allowing full access to all Windows events and direct source code. Delphi's component-based concept relieves the developer from much of the burden of creating a user interface and reacting to Windows events. This article shows how to write NetWare applications with 16-

Introduction

Borland's Delphi currently comes in two major flavors: The 16-bit version Delphi v1.0 allows creation of Windows v3.x applications; these 16-bit programs will usually run in other Windows environments (Win 95, Win NT), too. Delphi v2.0 provides the platform to create 32-bit applications for Win 95 and WinNT; additionally it comes with an updated release of the 16-bit compiler, so that you use it to create 16-bit Windows applications as well.

Key Delphi Terms Used in this Article

You should become familiar with the following Delphi terms used in this article.

Unit. Units in Pascal are binary files, comparable to LIB files in C- they are precompiled libraries that may contain functions, definitions, declarations, etc. They do not have to be recompiled unless the unit source code has changed. The unit's source code does not even have to be accessible during program generation or execution; the unit has to be present only at compile/link time to be linked into the executable file. In Delphi units have the extension DCU, while in Borland Pascal v7.x they will have the extension TPU (DOS real mode), TPP (DOS protected mode), or TPW (Pascal for Windows).

Import Files. Import files are text files that typically reference the function and procedure declarations to access external DLLs. Frequently they contain nothing but "external' statements. They are required at compile/link time. The typical extension is IMP.

Include Files. These ASCII files may contain any source code fragments and typically define variables and functions. Since it is easier and faster to use units, usage of include files is not widespread in Delphi. Include files may have any extension, but frequently use PAS or INC.

Procedures and Functions. While the concept of functions is well known to C programmers, the term procedure might be less familiar. Basically, procedures are equivalent to functions, but they do not have any return value; C programmers know the concept better as "void function."

Calling External DLLs from Delphi

Borland's Delphi allows developers an extremely easy and efficient method to create object-oriented, event-controlled Windows applications with a minimum of coding. Therefore many programmers have switched to Delphi as their primary development platform. Typically Delphi makes Windows programming easier than other visual development platforms, while still allowing full access to all Windows events and direct source code. Delphi's component-based concept relieves the developer from much of the burden of creating a user interface and reacting to Windows events.

This article shows how to write NetWare applications with 16-bit and 32-bit Delphi.

Calling external DLLs gives the developer several benefits:

  • It reduces the size of the executable program

  • It allows for shared access of multiple applications to the same shared code

  • It allows access to functionality of applications provided by 3rd-party vendors without requiring access to their source code.

To call DLL functions and procedures you will need to know the exact names of the functions as well as the number and parameters used by the function. If the manufacturers of the DLLs allow for third-party applications calling into their DLLs's routines, they will have to provide the applications with information on how to call into the DLLs.

This typically is done by either providing written documentation like in the function declarations of the online WinHelp or Dynatext documentation for the NetWare SDKs, or by providing compiler-specific libraries: C programmers might find header files or libraries (e.g., NetWin16.LIB or NWIPXSPX.LIB), while Pascal programmers might see include files or units (e.g., NetWin16.DCU or NWQMS.INC).

If the interface to the DLL is provided by libraries or units, the developer does not have to convert the written documentation into a program interface, but still has to follow the calling conventions as documented. If, however, the libraries are not or only partially provided, the interface has to be written by the developer. This might be partially the case for some Delphi applications; this will also apply to Visual Basic or MS Access developers who want to access NetWare DLLs.

You do not have to specify or know about the function algorithms, but only the format of the input and output parameters. The implementation of the used functions can be treated as black box. You do not even have to care about the programming language that has been used to write the DLLs: While most of the existing DLLs have been written in C, they may be accessed form other programming platforms like Delphi, Visual Basic, Paradox, or MS Access.

You should be aware, however, that while DLLs may contain function/procedure declarations as well as definitions of records/structures or types, they cannot export global variables.

The following paragraphs show how to write interface routines to NetWare DLLs in Delphi.

Basically there are two methods for accessing functions stored in a DLL:

  • Dynamic Imports: GetProcAddress and LoadLibrary

  • Static Imports: using "external" declarations

Dynamic Imports

The Windows function LoadLibrary allows your program to specify the name of external DLLs at run time, and the function GetProcAddress will determine the address of the DLL functions that you need. The combination of these two functions allows for dynamic access to DLLs and is frequently referred to as "dynamic import" or "explicit loading."

Using GetProcAddressand LoadLibrary (the two must be used in conjunction) to import a DLL gives your program control over what DLL file is actually loaded. With dynamic imports your application may continue to run, even if LoadLibrary fails to locate the DLL. Your application might, for example, check for the existence of NetWare DLLs and, if the access fails, continue with other program modules. If the application finds the function in the requested DLL it can directly call into the function address.

Static Imports

In static imports the external directive replaces the complete implementation of the called functions and procedures.

Example: Function NWCallsInit; external "NWCalls";

Declarations of DLL functions as "External" is most appropriate if you rely on the existence of the DLL function and your program should only execute if the DLL is accessible. In the NetWare programming environment it would frequently not make sense to run NetWare-specific applications if the client station does not have the NetWare client software with its DLLs installed.

The "external" declaration to perform a static DLL import causes the DLL to be loaded as your program starts executing. You cannot change the name of the DLL at run time, and your program will fail if it specifies a DLL that isn't available at run time. During compilation the compiler does not look for the DLL, so it need not be present.

"External" declarations typically import routines by name and/or by number, e.g.:

By Name: function NWCallsInit; external "CALWIN16";"
By number: function NWCallsInit; external "CALWIN16" index 377;"

In Delphi 32-bit you additionally specify the parameter passing convention, e.g.:

By number: function NWCallsInit; stdcall; external "CALWIN16" index 377;"

When your application accesses a function declared by name, Windows will browse the internal name table of the specified DLL and locate the address of the requested function at run time as you call it.

If you specify the ordinal number while importing a DLL routine, Windows will not have to scan the DLL name table. The access time to the function will be slightly reduced and general performance increased. Therefore you should specify the ordinal number if available. You may get the number either from the documentation, or by using tools to analyze DLLs (e.g., EXEHDR.EXE) that are available from compiler manufacturers or third parties.

Using Generic Windows Network APIs

Some networking functions may be accessed without calling any NetWare DLLs at all: since Windows provides some basic networking functions that can be called from third-party applications, you could simply build a network-aware Windows application using these network functions.

WnetGetConnection, WNetAddConnection and WNetGetUser belong to the more frequently used generic network Windows functions that can be accessed to retrieve mappings, printer redirection, and user names without requiring one of the NetWare SDKs. These Windows functions may be called from both, 16 and 32-bit Delphi applications.

Sample lines could look like this:

WnetGetConnection("F:", RemoteName, 255);       { Get Mapping }"
WNetGetConnection("LPT1:", RemoteName, 255);    { Get Printer redirection }"
WNetCancelConnection("F:", TRUE);               { Delete Mapping }"
WNetCancelConnection("LPT1:", TRUE);            { Cancel Capture }"
WNetAddConnection("F:", "", "\\FS1\VOL1\DATA"}  { Create Mapping / Attach }"
WNetAddConnection("LPT1:", TRUE);               { Cancel Capture }"
WNetGetUser("F:", UserName, 255);               { Get User name }"

In most cases, however, you will want to take use of the NetWare- specific APIs that give you access to all NetWare functions; this means you will want to access functions declared in one of the NetWare DLLs.

Using NetWare DLL Functions

As you develop Windows applications you have the choice between three groups of DLLs that you can access from within your application to call NetWare functions:

  • Legacy DLLs are the DLLs provided with the conventional Windows client for NetWare.

  • The new 16-bit DLLs are provided with the 32-bit Client for NetWare.

  • The 32-bit DLLs that come with the 32-bit Client for NetWare.

While you can use all three of them, Novell recommends to use only the latter two, because the legacy DLLs will probably no longer be maintained or supported. The following paragraphs discuss how and when to use the above mentioned DLLs.

Sometimes developers place declarations of imported functions directly in the program that imports and uses them. To facilitate easy access to the DLLs, however, you should combine the statements that interface with the DLLs and put them into a separate unit, an import unit, that contains declarations for all procedures and functions in a DLL, along with any required constants and types. To allow a program to call DLL function now simply requires putting the name of the import unit into the "uses" statement.

Using Legacy APIs (NWCALLS.DLL etc)

Prerequisites: Access to the Windows 3.x DLLs (NWCALLS, NWNET, etc.)

Target Platforms: Windows 3.x, Windows 95, Windows NT

The NetWare Client for DOS/Windows that has been available since a few years now contained a set of 16-bit DLLs to be accessed by Novell's and 3rd parties' Windows NetWare applications. The current version of these DLLs can be found on CompuServe, the WWW, or the Novell BBS in the NWOS area as NWDLL2.EXE. These DLLs included NWCALLS.DLL, NWIPXSPX.DLL, NWLOCALE.DLL, NWNET.DLL, NWGDI.DLL, NWPSRV.DLL, and PNW.DLL, and these have been installed on most existing NetWare client workstations in the field.

The Client SDK available on the previous volumes of the NetWare SDK CD set referred to these DLLs for all Windows v3.x application developers. C programmers would link their applications with libraries that in turn declared the functions as external in these DLLs.

The "legacy" Client SDK has been available on the SDK CDs up to volume 7; it is no longer provided from volume 8 on. Beginning with volume 6 it has been replaced by the "NetWare SDK" or "Cross-Platform SDK" using the new 16-bit DLLs (see below).

The legacy DLLs - just as all 16-bit DLLs -can be accessed from Delphi 16-bit applications, not from Delphi v2.x 32-bit programs. They can also be accessed from Visual Basic, MS Access, etc.

There is no Novell include file or unit available to access the old style ("legacy") NWCALLS.DLL; therefore, Delphi developers or any programmers who want to use other compilers than MS C or Borland C need to create their own declarations and interfaces to the DLLs.

The major part of this implementation involves converting the C type declarations of functions and types into Pascal equivalent syntax. To access the legacy DLL functions you will typically proceed in these steps:

  1. Find out what DLL contains the function that you want to use. You can usually find this information in the SDKDyna text documentation for the "legacy" Client SDK (Dynatext Book: "Client API for C"). In the section, "Syntax" you will typically find an "#include "xxx.h"" statement indicating the accessed DLL, e.g., "# include <nwcalls.h<<for NWCALLS.DLLfunctions. Most of the standard functions are contained in NWCALLS.DLL, while NDS functions can be found in NWNET.DLL, and IPX/SPX functions in NWIPXSPX.DLL.

  2. Find out the calling conventions and parameters of the APIs that you plan to access. Use the C function declaration as a starting point. If we take the declaration for NWGetConnectionNumber as an example it will look like this in the Dynatext documentation:

    NWCCODE NWAPI NWGetConnectionNumber(
    
      NWCONN_HANDLE     conn,
    
    NWCONN_NUM NWFAR   *connNumber);

    Typically you will see C or NetWare-specific types that have to be converted into Pascal types and syntax. Here you have two options to convert C types into Pascal types:

    Translate all C types into Pascal types. The function declaration above would then look like

    FUNCTION NWGetConnectionNumber(conn: WORD; VAR connNumber: WORD):  WORD;

    Alternatively, you may declare all required C types as the equivalent Pascal types and subsequently use only these in the function declarations:

    TYPE
    
      NWCONN_HANDLE   = WORD;
    
      NWCONN_NUM      = WORD;
    
      NWCCODE         = WORD;
    
    FUNCTION NWGetConnectionNumber(conn: NWCONN_HANDLE; VAR connNumber:
    
    NWCONN_NUM): NWCCODE;

    I strongly suggest using the second declaration method, because this usually makes the conversion easier and prevents type errors. On CompuServe, the WWW, and the BBS you will find the complex Delphi sample source XFER.EXE (containing the unit NWCALLS.PAS) that uses this declaration method. Far from being complete, NWCALLS.PAS includes about 124KB of function and type declarations for Delphi and Pascal for Windows programmers to access legacy APIs.

  3. Identify the functions that you want to use. If a function or type declaration is already included in the NWCALLS.PAS sample, you will simply have to include NWCalls into your "Uses" statement or copy the appropriate statements from that file. Otherwise you will have to convert the C function into the equivalent Pascal function and add it to NWCalls or to your own unit.

    If the function refers to types or records that are not yet included in NWCALLS.PAS, you will have to add them using the appropriate C to PAS conversion.

    The C-to-PAS conversion for functions, types, and records has to be performed very carefully and accurately since Windows will react with General Protection Faults on incorrect function declarations.

    If you are uncertain of the equivalent Pascal type for a given C type, you should take a look into the C header files, namely NWCALDEF.H in the Client\Include directory (up to SDK volume7) or NTYPES.H, in the INCLUDE directory of the NWSDK structure (beginning with SDK volume 6).

The clear advantage of using the legacy DLLs is that these are quite stable and reliable, and nearly every NetWare client station has a copy of these DLLs installed. Therefore developers will usually not have to provide the NetWare DLLs with their software. On the other hand, there is no further development of these DLLs and the available support is limited. Developers of 16-bit applications should use the approach described below and access the new 16-bit DLLs.

Using the New 16-bit DLLs

Prerequisites: Access to the new Windows 3.x DLLs (CALWIN16, NETWIN16, etc.)

Target Platforms: Windows 3.x, Windows 95, Windows NT

The new 32-bit Windows Client software -also known as "Client32"-contains not only the 32-bit versions of the new NetWare DLLs, but also the equivalent 16-bit versions of these DLLs. The Client32 software can be found in the Windows/Client areas of Novell's forums on CompuServe or on the WWW.

To use these 16-bit DLLs, install or copy them to the Windows/System directory of the target client station.

Access to these DLLs is much easier for Delphi developers than access to the legacy DLLs because Novell provided all units that are required to interface with these DLLs. These Delphi units can be found in the NWSDK directory on the NetWare SDK CDs Futures/NWSDK\Lib\Win\Delphi on volume 6-7, or NWSDK\Lib\Win\Delphi on volume 8.

To use the new DLLs from Delphi v1.0 applications you will have to follow these steps:

  1. Start Delphi 16-bit and include the path to the unit files in "Options" / "Environment" /"Library" / "Library Path." The resulting path might now look like

    "C:\DELPHI16\LIB;C:\sdkcd.7\futures\NWSDK\lib\win\Delphi" or "C:\DELPHI16\LIB;C:\sdkcd.8\NWSDK\lib\win\Delphi".

  2. Identify the functions that you want to use and include the appropriate unit in the "uses" statement of your application. You should not use include statements, and try to include one of the NetWare INC files, or your program may not compile. All that your application needs is contained in the provided units.

    Unluckily, the SDK documentation does not include the information of what unit contains what function, so you might either simply include all of the units in the "uses" statement of your application, or refer to the list in appendix of this article to include the correct unit.

    The following units are available on the SDK CD set:

    AUDWIN16, CALACT16, CALAFP16, CALBND16,
    
    CALCON16, CALFIL16, CALFSE16, CALMIG16,
    
    CALMIS16, CALMSG16, CALNAM16, CALNCP16,
    
    CALPRT16, CALQMS16, CALSRV16, CALSVM16, 
    
    CALSYN16, CALTTS16, CALVOL16, CLXWIN16, 
    
    LOCWIN16, NETCON16, NETNDS16

    In most cases the naming convention is so easy that a good guess will usually help: connection services functions are contained in CALCON16, while bindery services are covered in CALBND16. Most type and general structure declarations are stored in CALMIS16.

  3. Write your application, using the functions, types, and parameter definitions as documented in the function declaration. All the function declarations for the Windows client APIs can be found in the NWSDK online documentation. Many type declarations can also be found there, or in NTYPES.H (in the INCLUDE directory of the NWSDK).

    Example: The bindery function NWReadPropertyValueis declared in the documentation as follows.

    #include <nwbindry.inc<<
    Function NWReadPropertyValue
    
     (conn        : NWCONN_HANDLE;
    
     objName      : pnstr8;
    
     objType      : nuint16;
    
     propertyName : pnstr8;
    
     segmentNum   : nuint8;
    
     segmentData  : pnuint8;
    
     moreSegments : pnuint8;
    
     flags        : pnuint8
    
    ) : NWCCODE;

    Do not use the listed INCLUDE statement. Unless you are experienced with type casts you should always use the types as documented, or you may get compiler errors or Windows faults.

    The notation for the NetWare types looks unfamiliar but is quite easy (if in doubt, take another look at \NWSDK\include\NTYPES.H):types starting with "p" are pointers, and the number at the end of the type name indicates the number of bits for this type. "str" represents a string, "u" stands for unsigned, and "int" for an integer. "nuint16" therefore is an unsigned 16-bit integer-Pascal programers would refer to it as WORD. "pnstr8" is a pointer to an 8-bitcharacter/string, the equivalent to Pchar.

In most cases, VAR parameters are not used in the SDK functions for the 16-bit DLLs. The functions pass pointers to variables instead. The function above shows "moreSegments: pnuint8"; this is functionally equivalent to "VAR moreSegments: BYTE", but you should probably to pass it as pnuint8.

The main reason for using these new type declarations is that the application becomes platform and compiler independent -while an "Integer" might not be the same type on 16-bit or 32-bit Windows or on OS/2, the variable nuint16 will always be declared as 16-bit long. Using these types increases the portability of an application source.

While both code using the legacy or using the new 16-bit DLLs will run on all Windows platforms as long as the DLLs are accessible, using the new 16-bit DLLs should be the preferred method for developing 16-bit Windows applications. The advantage of this approach is the compatibility with current and future client versions, as well as with the 32-bit platforms (e.g., Win95, or WinNT).

Unlike the legacy DLLs the new 16-bit DLL will be maintained and fixed in the foreseeable future. The disadvantage is that not all current clients have these DLLs installed and you might have to provide the new DLLs with your application, or refer your customers to CompuServe to download the 32-bit NetWare Client.

Using the New 32-bit DLLs

Prerequisites: Access to the 32-bit Client DLLs (CALWIN32, NETWIN32, etc.)

Target Platforms: Windows 95, Windows NT

Delphi v2.0 allows creation of full 32-bit applications for Windows 95 or Windows NT. While the NetWare SDK Vol.8 contains a set of include and import files that can be used to access some 32-bit DLLs, there is an updated file on CompuServe/NDevSup and other locations that contains an updated and modified set of include files as well as an import unit allowing simple access to all NetWare APIs.

To create 32-bit NetWare applications with Delphi you will need to have the 32-bit client software installed, you need Borland's Delphi v2.0, and you should get the above mentioned set (or a more recent version) of include/import files from CompuServe.

Applications created in this environment will only run on Win95/WinNT target stations with the 32-bit client installed. The latest Client software can be found on CompuServe in the NWOS forum as DW32D1.EXE or as DW32N1.EXE

Follow these steps to setup your Delphi environment and to create 32-bit NetWare applications:

  1. Get the updated import/include files, and copy all files into an existing or new directory.

  2. Start Delphi v2.0 select "Project"/"Options"/"Directories/Conditionals";choose "Source Path" and add the directory where you copied the files to the end of the line.

  3. When creating a new project, add the file NWINC32.PAS to the project by selecting "File"/" Add To Project "and choosing NWINC32.PAS. This master import unit NWINC32.PASwill import all NetWare APIs for access by the application. You may specify the target platform in the head of this unit source or move this code part into your main program.

  4. Each Delphi source file that needs access to the types or functions from the SDK needs to add the unit "NWINC32" to the "uses" statement of the program. You do not have to add other files from the set of import/include files into any "uses" or "Include" statements.

While developing your application you will obviously need access to the NetWare SDK documentation, and you should use the same variable types as listed there in the section of the Pascal declarations. If you run into difficulties because the types that you chose result in compiler errors, you might also refer to the INC files to verify that you are using the correct types.

Again, initially the new type names in the SDK might be unfamiliar, but the naming conventions are easy and have significant advantages. For more details see the paragraphs in the discussion of the Delphi 16-bit implementation.

Sample Code Snippets

This section discusses GETRES, QLIST, and QLIST 32.

Code Using Generic Network Functions (GETRES)

The most frequently used Windows function will probably be WNetGetConnection(LocalName, RemoteName, MaxLen) where LocalName represents the name of a local resource (printer or redirected drive) like "LPT1:" or "F:" and RemoteName will return the network name of that resource, e.g., "FS-MAIL/PRINTQ1" or "\\\FS-TEST\SYS\PUBLIC".

The following code fragment from GETRES.EXE on NDevSup will return all redirected printers and drives for a workstation without calling any NetWare-specific functions:

procedure TForm1.ReadResources(Sender: TObject);

Const

  unmapped = ""unmapped"";"
VAR

  LocalName, RemoteName   : PChar;

  MaxLen                  : WORD;

  cCode                   : WORD;

  drvLetter               : Char;

begin

  MaxLen  := 255;

  ListBoxResources.Items.Clear;

  Case RadioGroupResourceType.ItemIndex of

     0: for drvLetter := "A" to "Z" do begin        { retrieve the defined mappings }"
            StrPCopy(LocalName, drvLetter+":");"
            MaxLen  := 255;

            cCode := WNetGetConnection(LocalName, RemoteName, @MaxLen);

            if (cCode=0)

               then ListBoxResources.Items.Add(StrPas(LocalName) + "=" + "
                         StrPas(RemoteName))

               else ListBoxResources.Items.Add(StrPas(LocalName) + "=" + unmapped);"
            end;

     1: for drvLetter := "1" to "9" do begin        { retrieve the network printers }"
            StrPCopy(LocalName, "LPT"+drvLetter+":");"
            MaxLen  := 255;

            cCode := WNetGetConnection(LocalName, RemoteName, @MaxLen);

            if (cCode=0)

               then ListBoxResources.Items.Add(StrPas(LocalName) + "=" +"
                        StrPas(RemoteName))

               else ListBoxResources.Items.Add(StrPas(LocalName) + "=" + unmapped);"
            end;

     end;

  

  (* retrieve the user name with 

     cCode := WNetGetUser(LocalName, RemoteName, MaxLen);

  *)

end;

Figure 1: Screen shot of GETRES.

Relying on these Windows networking functions alone, without calling NetWare specific APIs, will usually severely restrict the functionality of your application in NetWare environments. It may however be a valid approach for applications that require only basic networking capabilities and might be run by clients on other non-NetWare networking platforms.

Code Using Novell Units with 16-bit Delphi (QLIST)

Code using the Novell -provided units makes application development with Delphi much easier than having to provide the interface to the legacy APIs. As mentioned before, the units provide for all the function and type declarations, so that development can focus on the functionality.

To call a function just add the needed NetWare unit to the "uses" statement (see appendix); in the example we will need CALMIS16, CLXWIN16, and LOCWIN16.

The following code excerpt from the sample application QLIST.EXE on NDevSup shows a typical startup sequence for a Delphi 16-bit application; all functions referred to in this sample are defined in the units provided on the NetWare SDK.

unit Main;

interface

uses

 SysUtils, WinTypes, WinProcs,

Messages, Classes, Graphics, Controls,

 Forms, Dialogs, Menus, StdCtrls,

 CALMIS16, CLXWIN16, LOCWIN16.

[ ... ]

Procedure ErrorMessage(Error:

LongInt; Msg: String);

VAR SaveCursor : TCursor;

begin

  if Error=0 then Exit;

  SaveCursor    := Screen.Cursor;

  Screen.Cursor := crArrow;

  MessageDlg("Error "+IntToHex(Error, 8)+": "+Msg, mtWarning, [mbOK], 0);"
  Screen.Cursor := SaveCursor;

end;

procedure TForm1.FormCreate(Sender:

TObject);

VAR

  tmp          : nptr;

  connRef      : nuint32;

  openState    : nuint;

  reserved     : nuint;

  countryCode  : nint;

  codePage     : nint;

  local        : LCONV;

  cCode        : NWCCODE;

begin

  { Initialize the program }

  tmp         := Nil;

  cCode       := NWCallsInit(tmp, tmp);

  ErrorMessage(cCode, "NWCallsInit");"
  { Get primary connection reference }

  cCode       := NWCCGetPrimConnRef(@ConnRef); ErrorMessage(cCode, "NWCCGetPrimConnRef");"
  { Get primary connection handle }

  cCode       := NWCCOpenConnByRef(ConnRef, NWCC_OPEN_LICENSED, reserved, @connHandle);

  ErrorMessage(cCode, "NWCCOpenConnByRef");"
  { Get locale ANSI information }

  NWLlocaleconv(@local);

  { initialize Unicode tables }

  cCode       := NWInitUnicodeTables(local.country_ID, local.code_Page);

end;

[ ... ]

Code Using Novell Import/Include Files (QLIST32)

The following code sample is an excerpt from QLIST32 -a small sample program that performs some of the PCONSOLE functions. The full source can be found as QLIST32.EXE on the NDevSup forum. This code excerpt takes a queue name and puts the list of existing print jobs into a Delphi list box.

As can be seen from the sample, the syntax is exactly the same as in Delphi 16-bit, and in fact most of the code could be used in both environments. The only difference can be found in the "uses" statement, where the import unit NWINC32 is referenced. An equivalent sample code for 16-bit Delphi can be found as QLIST.EXE in the same CompuServe forum.

Looking into the source code of NWINC32.PAS shows that it merely contains "{$Include ..}" statements that, in turn, first load all the function declarations of the NetWare function groups (e.g., DS, QMS, TTS, etc.), then load all the "external" declarations. Therefore, NWINC32.PAS is a typical instance of an import unit with static declarations.

Taking an even closer look into the declarations, the code reveals the different behavior of Delphi 32 that has to be taken into account when writing your own import units. While Delphi 16 used to pass all parameters via the stack, Delphi 32 has four options for parameter passing conventions. In addition to the "pascal", "cdecl", and "stdcall" conventions used in Delphi 1.0, Delphi 2.0 adds a "register" convention that is a speedy hybrid of the Pascal and C calling conventions. Delphi 2.0 uses the register convention by default.

The register convention uses registers when possible to pass its parameters. The first three parameters that will fit into 32 bit registers are passed in the EAX, EDX, and ECX registers, in that order, while all remaining parameters follow the "Pascal" calling convention.

Since all NetWare DLLs use the stack to pass its parameters, you will find that all function declarations require and use the "stdcall" modifier.

uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, Buttons,

 StdCtrls, ExtCtrls, SysUtils,  

 NWInc32, Delphi_U, U_Vars, U_JobInf, U_QInfo;

[ ... ]

procedure TDlgQueueList.GetJobList(Sender:

TObject);

VAR queueStartPos : nuint32;

   jobList   : QueueJobListReply;

   jobIndex  : WORD;

   jobNumber : nuint32;

   job       : NWQueueJobStruct;

   sTemp     : String;

   objName   : String;

   objType   : nuint16;

begin

  ClearList(ListBoxJobs);

  EditJobInfo.Text := "";"
  { get the ID of the Queue }

  ccode := NWGetObjectID(connHandle, @QName[1], OT_PRINT_QUEUE, @QID);

  ErrorMessage(cCode, "NWGetObjectID");"
  if cCode>0 then exit;>
  queueStartPos := 0;

  { get the array of job numbers }

  cCode := NWGetQueueJobList2(connHandle, QID, queueStartPos, jobList);

  Case cCode of

     ERR_NO_Q_RIGHTS : ErrorMessage(cCode, "ERR_NO_Q_RIGHTS");"
     else     ErrorMessage(cCode, "NWGetQueueJobList2");"
     end;

  if cCode>0 then exit;>
  for jobIndex := 1 to jobList.replyQueueJobNumbers do begin

      jobNumber := jobList.jobNumberList[Pred(jobIndex)];

      { now retrieve the job details }

      cCode := NWReadQueueJobEntry2(connHandle, QID, jobNumber, job);

      if (cCode=0) then begin

         { get the NDS or bindery name of the user who submitted the job }

         cCode := GetObjNameFromID(connHandle, job.clientID, objName);

         if (cCode<<0) then objName := StrPas(@job.bannerNameField);<
         if (cCode<<0) then objName := StrPas(@job.bannerNameField);<
         sTemp := Format("%3d [%20.20s] %s (%8x)", [jobIndex, objName,"
                  StrPas(@job.jobDescription), jobNumber]);

         AddListEntry(Sender, ListBoxJobs, sTemp);

         end;

      end;

end;

Figure 2: Screen shot of QLIST32.

What Will You See Next?

On Novell's Net2000 JumpStart CD that was distributed to this year's BrainShare attendees, you will find more details about Novell's directions in exposing advanced network services through standard interfaces and higher level components, as well as sample components, and technical documents on Novell's direction in distributed objects and components.

On this JumpStart CD you can find several NetWare OCX, VBX, and VCL components to access NetWare Directory Services that can be linked into Visual Basic applications. These components expose such features as NDS schema, Object Attributes, Authentication, Volume, and list controls. They will be further developed to support Delphi v2.0.

The upcoming GroupWise SDK will contain Delphi v2.0 objects for easy access to GroupWise address books and other elements that facilitate development of email applications.

You will be able to modify the GroupWise information store and client interface with Custom Third Party Objects (C3POs) or OLE Custom Controls (OCXs) that plug in to Delphi. Find more detailed descriptions in the Jan/Feb/Mar 96 issues Developer Notes, or in the GroupWise section of the Dynatext SDK documentation.

Third-Party Offerings

Third-party offerings include the following:

Apiary

Apiary Developer's Suite for NetWare (Delphi Edition) contains the prototypes, constants, and error codes for NetWare versions up to 4.1. The suite also contains a Delphi class library that greatly simplifies NetWare programming. It allows programmers to create NetWare enabled client applications for Windows in Delphi. It provides 800+ NetWare client functions, and several class libraries.

You can find some sample Apiary Delphi applications on the NetWare "Net2000 JumpStart" CD.

Contact: Apiary, Inc. 501 221 3699 (fax 501 221 7412), http://www.apiary.com

NWLIB15.ZIP (Borland Delphi forum [DELPHI])

NWLib is a native VCL for Delphi 1.0, which provides a wrapper for Novell's Application Programming Interface (API) C language programming specification. Included in the library are over 100 NetWare specific Bindery, Connection, Print Management, Semaphore, Map, and Environmental functions.

The NetWare API is a very complex engine to access all aspects of the Novell environment. NWLib removes this complexity by digesting multiple API calls into single, simple calls. Most of NWLib's return values are easy to implement strings, boolean values, string lists, etc., rather than the more complex native values of the API. NWLib also condenses multiple nested API structures into easy to handle Delphi record structures.

NWLIB is shareware and Devont Software Inc. offer to license their complete source for a nominal fee.

Contact: Fax: (713)-370 4215; BBS: (713)-370 0841; http://www.wworks.com/~devont

NETWARE3.ZIP (Borland Delphi forum [DELPHI])

A set of NetWare VCLs for Delphi 16-bit that contain NetWare v4.x functions, IPX/SPX datagram protocols, semaphore functions, and several other components. The VCLs do not access the DLLs but create their NCP packets themselves.

Distributing Your Applications

If you plan to distribute the NetWare applications that you developed to your customers you will have to take into account that your applications might require the presence of one or more NetWare DLLs.

While most of the customers currently have the legacy DLLs installed, the 16-bit or 32-bit NetWare DLLs are not yet on all target workstations. At least you should not take for granted the presence of either of them.

There are two main options for the independent software vendors: They might either ask their customers to purchase the required DLLs or download the libraries from CompuServe or the WWW; or they can provide the DLLs together with their applications. In the latter case an installation routine might determine the presence of the requested DLLs and, if required, copy or update the DLLs. Precautions should be taken not to overwrite a more recent DLL with an older version. If necessary the customers might have to download a more recent DLL version.

If you are uncertain about what DLLs are actually required by your application at runtime, you may run tools like Borland's TDUMP.EXE that comes with Delphi or Borland C. This tool will list plenty of internal program information, including the runtime libraries.

Before distributing any Novell software with your applications you should take a look at the software license agreements that are usually displayed when extracting the compressed files. Here an excerpt:

You may, without charge, reproduce and distribute, within your organization only, copies of this FILE, and use copies of the SOFTWARE solely for their intended purpose of supporting legally obtained, commercially available Novell operating system software, provided: 1) you do not receive any direct payment, commercial benefit, or other consideration for the reproduction, distribution or use of the SOFTWARE or FILE, or distribute the FILE as part of or in combination with any other software or hardware product without the prior written consent of Novell, Inc.; and, 2) you do not change or omit any proprietary rights notices appearing on or in the SOFTWARE or FILE. If you are a reseller of Novell products, you may, subject to the forgoing, distribute the FILE outside your organization solely for maintenance and upgrade of SOFTWARE.

The NetWare SDK CD disk #2 contains the Client Redistribution Kit (RDK) in the subdirectory \NWCLIENT with the current versions of the DOS, Win 3.x, Win95, WinNT, Mac, and OS/2 clients.

Where to Find Other Useful Information

For more information, check the following:


Updatesand Info on CompuServe
Contents

NWOS/DW32D1.EXE(03 Jul 96)

DisketteInstall: Client 32 for DOS/Win 2.10

NWOS/DW32N1.EXE(03 Jul 96)

NetworkInstall: Client 32 for DOS/Win 2.10

NWOS/312PT8.EXE(03 Jul 96)

NetWare3.12 Operating System Updates

NWOS/C32FAQ.EXE(25-Jun-96)

NWClient 32 FAQ for Win 95

NWOS/NWVLM95.TXT(25 Jun 96)

Integratingthe NW Client (VLM) With Win95

NWOS/LIBUP8.EXE(12 Jun 96)

CLIBServer Library Update

NWOS/NWDLL2.EXE(25 Jun 96)

NovellWindows DLLs Update File

DELPHI/TI2558.ASC(03 Jun 96)

InstallingDelphi on a Network

DELPHI/TI2695.ASC(23 May 96)

NewLanguage Features in Delphi 2.0 32-bit

DELPHI32/DELPHI.ZIP

NewHelp Files for Delphi 2.0


OtherHelpful Sites
Location

BorlandDelphi News Groups

comp.lang.pascal.delphi.databases

comp.lang.pascal.delphi.components

comp.lang.pascal.delphi.misc

comp.sources.delphi

alt.lang.delphi

Borland's Home Page

http://www.borland.com/

DelphiDeveloper Support

http://www.borland.com/TechInfo/Delphi/index.html

CompuServe: GO DELPHI / GO BDELPHI32

OtherUseful Delphi Links

http://www.informant.com/Delphi/

http://sunsite.icm.edu.pl/~robert/Delphi/

http://SunSite.Informatik.RWTH Aachen.DE/Delphi/sites.html

Novell Developer Support

http://devsup.nsd.provo.novell.com/

http://netwire.novell.com/home/devsup/sample/all/

CompuServe: GO NDEVSUP

Accessing NetWare DLLs From Other Platforms

While the NetWare SDK CDs contain the necessary libraries and header files for Borland C and Microsoft C, you might want to use other Windows development platforms, but still need the interface to the NetWare DLLs. The Delphi predecessor, Borland Pascal for Windows, uses nearly identical declarations as Delphi 16-bit; therefore you can use the code sample above with only minor changes.

Visual Basic

Calling NetWare DLLs from Visual Basic is quite similar to calling the DLLs from Delphi: in both cases we need to provide the interface to the DLL APIs in the respective native compiler format. The interface concept for VB was outlined in the July 1993 issue of Novell Application Notes ("A NetWare Interface for Visual Basic") and in a previously published technical information (TID100228)- here is the key information:

Functions should usually be declared as integer in the declaration for NetWare API calls. In addition, the function parameters should match the parameters in the SDK function prototype.

For example, the C language function NWSampleFunc() is be prototyped as shown below.

NWCCODE NWAPI NWSampleFunc

 (NWCONN_HANDLE conn,

 char NWFAR *objectName,

 NWOBJ_ID NWFAR *objectID);

In Visual Basic the function would be declared:

Declare Function NWSampleFunc Lib "NWCALLS.DLL" (ByVal conn%, ByVal objectName$, objectID") As Integer"

In Visual Basic, the default parameter passing convention is by reference. To pass parameters by value, the ByVal keyword is used. The exception to this rule is that strings are passed by value and the ByVal keyword is used to specify a reference to the string. Figure 3 lists some common C language arguments and their Visual Basic equivalent declarations.

Figure 3: C language arguments and their Visual Basic equivalent declarations.

Using MS Access or Borland Paradox

Microsoft Access allows the programmer to write applications that access third-party DLLs just as other programming languages. To use functions of a third-party DLL, for example one of the NetWare DLLs, you will first have to declare these functions as external, just as you do with Delphi or VB. The "Declare" statement uses a similar syntax as the Basic examples above, and the MS Access manuals provide more details about the parameter passing and the argument types.

Borland's data base Paradox provides the option to use functions stored in external DLLs by defining with a "uses" statement in their ObjectPAL programming language.

The syntax scheme would look like

uses NWCalls       ; {or CalWin16, etc. }

  NWFunction (parameter list) CWORD 

endUses

After the declaration you may use the function in all methods attached to the object where the "uses" block is declared.

Appendix: Function and Unit Cross Reference (16-bit Delphi)

__NWGetCurNS; "CALNAM16"
__NWGetNWCallsState; "CALMIS16"
_NWConvert4ByteTo6ByteHandle; "CALMIS16"
_NWConvertHandle; "CALMIS16"
_NWDSGETCONNECTIONSLOT; "NETCON16"
_NWGetFileServerType; "CALSRV16"
_NWGetRequesterType; "CALMIS16"
_NWwsprintf; "LOCWIN16"
NWAbortServicingQueueJob2; "CALQMS16"
NWAbortServicingQueueJob; "CALQMS16"
NWADAppendExternalRecords; "AUDWIN16"
NWADChangeObjectProperty; "AUDWIN16"
NWADChangePassword; "AUDWIN16"
NWADCheckAccess; "AUDWIN16"
NWADCheckLevelTwoAccess; "AUDWIN16"
NWADClose; "AUDWIN16"
NWADCloseOldFile; "AUDWIN16"
NWADCloseRecordFile; "AUDWIN16"
NWADDeleteFile; "AUDWIN16"
NWADDeleteOldFile; "AUDWIN16"
NWADDisable; "AUDWIN16"
NWAddObjectToSet; "CALBND16"
NWAddTrustee; "CALFIL16"
NWAddTrusteeToDirectory; "CALFIL16"
NWADEnable; "AUDWIN16"
NWADGetFileList; "AUDWIN16"
NWADGetFlags; "AUDWIN16"
NWADGetStatus; "AUDWIN16"
NWADInitLevelTwoPassword; "AUDWIN16"
NWADIsObjectAudited; "AUDWIN16"
NWADLogin; "AUDWIN16"
NWADLogout; "AUDWIN16"
NWADOpen; "AUDWIN16"
NWADOpenRecordFile; "AUDWIN16"
NWADReadBitMap; "AUDWIN16"
NWADReadConfigHeader; "AUDWIN16"
NWADReadRecord; "AUDWIN16"
NWADResetFile; "AUDWIN16"
NWADRestartVolumeAuditing; "AUDWIN16"
NWADSetPassword; "AUDWIN16"
NWADWriteBitMap; "AUDWIN16"
NWADWriteConfigHeader; "AUDWIN16"
NWAFPAllocTemporaryDirHandle; "CALAFP16"
NWAFPASCIIZToLenStr; "CALAFP16"
NWAFPCreateDirectory; "CALAFP16"
NWAFPCreateFile; "CALAFP16"
NWAFPDelete; "CALAFP16"
NWAFPDirectoryEntry; "CALAFP16"
NWAFPGetEntryIDFromPathName; "CALAFP16"
NWAFPGetEntryIDFromHandle; "CALAFP16"
NWAFPGetEntryIDFromName; "CALAFP16"
NWAFPGetFileInformation; "CALAFP16"
NWAFPOpenFileFork; "CALAFP16"
NWAFPRename; "CALAFP16"
NWAFPScanFileInformation; "CALAFP16"
NWAFPSetFileInformation; "CALAFP16"
NWAFPSupported; "CALAFP16"
NWAllocPermanentDirectoryHandle; "CALFIL16"
NWAllocTempNSDirHandle; "CALNAM16"
NWAllocTempNSDirHandle2; "CALNAM16"
NWAllocTemporaryDirectoryHandle; "CALFIL16"
NWatoi; "LOCWIN16"
NWAttachQueueServerToQueue; "CALQMS16"
NWAttachToFileServer; "CALSRV16"
NWAttachToFileServerByConn; "CALSRV16"
NWBroadcastToConsole; "CALMSG16"
NWCallsInit; "CALMIS16"
NWCallsTerm; "CALMIS16"
NWCancelCapture; "CALPRT16"
NWCCCloseConn; "CLXWIN16"
NWCCGetAllConnInfo; "CLXWIN16"
NWCCGetAllConnRefInfo; "CLXWIN16"
NWCCGetCLXVersion; "CLXWIN16"
NWCCGetConnAddress; "CLXWIN16"
NWCCGetConnAddressLength; "CLXWIN16"
NWCCGetConnInfo; "CLXWIN16"
NWCCGetConnRef; "CLXWIN16"
NWCCGetConnRefAddressLength; "CLXWIN16"
NWCCGetConnRefAddress; "CLXWIN16"
NWCCGetConnRefInfo; "CLXWIN16"
NWCCGetPrefServerName; "CLXWIN16"
NWCCGetPrimConnRef; "CLXWIN16"
NWCCLicenseConn; "CLXWIN16"
NWCCMakeConnPermanent; "CLXWIN16"
NWCCOpenConnByAddr; "CLXWIN16"
NWCCOpenConnByName; "CLXWIN16"
NWCCOpenConnByRef; "CLXWIN16"
NWCCScanConnRefs; "CLXWIN16"
NWCCSetPrefServerName; "CLXWIN16"
NWCCSetPrimConn; "CLXWIN16"
NWCCSysCloseConnRef; "CLXWIN16"
NWCCUnlicenseConn; "CLXWIN16"
NWChangeObjectPassword; "CALBND16"
NWChangeObjectSecurity; "CALBND16"
NWChangePropertySecurity; "CALBND16"
NWChangeQueueJobEntry; "CALQMS16"
NWChangeQueueJobEntry2; "CALQMS16"
NWChangeQueueJobPosition; "CALQMS16"
NWChangeQueueJobPosition2; "CALQMS16"
NWChangeToClientRights2; "CALQMS16"
NWChangeToClientRights; "CALQMS16"
NWCharType; "LOCWIN16"
NWCharUpr; "LOCWIN16"
NWCharVal; "LOCWIN16"
NWCheckConsolePrivileges; "CALSRV16"
NWCheckNetWareVersion; "CALSRV16"
NWClearConnectionNumber; "CALCON16"
NWClearFileLock2; "CALFIL16"
NWClearFileLockSet; "CALFIL16"
NWClearLogicalRecordSet; "CALFIL16"
NWClearLogicalRecord; "CALFIL16"
NWClearPhysicalRecord; "CALFIL16"
NWClearPhysicalRecordSet; "CALFIL16"
NWCloseBindery; "CALBND16"
NWCloseConn; "CALCON16"
NWCloseEA; "CALNAM16"
NWCloseFile; "CALFIL16"
NWCloseFileAndAbortQueueJob; "CALQMS16"
NWCloseFileAndAbortQueueJob2; "CALQMS16"
NWCloseFileAndStartQueueJob2; "CALQMS16"
NWCloseFileAndStartQueueJob; "CALQMS16"
NWCloseSemaphore; "CALSYN16"
NWConvertDate; "CALMIS16"
NWConvertDateTime; "CALMIS16"
NWConvertFileHandleConnRef; "CALMIS16"
NWConvertFileHandle; "CALMIS16"
NWConvertHandle; "CALMIS16"
NWConvertPathToDirEntry; "CALMIS16"
NWConvertTime; "CALMIS16"
NWCreateDirectory; "CALFIL16"
NWCreateObject; "CALBND16"
NWCreateProperty; "CALBND16"
NWCreateQueue; "CALQMS16"
NWCreateQueueFile; "CALQMS16"
NWCreateQueueFile2; "CALQMS16"
NWCreateUNCPath; "CALFIL16"
NWDeallocateDirectoryHandle; "CALFIL16"
NWDeleteDirectory; "CALFIL16"
NWDeleteDriveBase; "CALFIL16"
NWDeleteObject; "CALBND16"
NWDeleteObjectFromSet; "CALBND16"
NWDeleteProperty; "CALBND16"
NWDeleteTrustee; "CALFIL16"
NWDeleteTrusteeFromDirectory; "CALFIL16"
NWDestroyQueue; "CALQMS16"
NWDetachFromFileServer; "CALSRV16"
NWDetachQueueServerFromQueue; "CALQMS16"
NWDisableBroadcasts; "CALMSG16"
NWDisableFileServerLogin; "CALSRV16"
NWDisableTTS; "CALTTS16"
NWDisallowObjectPassword; "CALBND16"
NWDownFileServer; "CALSRV16"
NWDSABBREVIATENAME; "NETNDS16"
NWDSABORTPARTITIONOPERATION; "NETNDS16"
NWDSADDFILTERTOKEN; "NETNDS16"
NWDSADDOBJECT; "NETNDS16"
NWDSADDPARTITION; "NETNDS16"
NWDSADDREPLICA; "NETNDS16"
NWDSADDSECURITYEQUIV; "NETNDS16"
NWDSALLOCBUF; "NETNDS16"
NWDSALLOCFILTER; "NETNDS16"
NWDSAUDITGETOBJECTID; "AUDWIN16"
NWDSAUDITGETOBJECTID; "NETNDS16"
NWDSAUTHENTICATE; "NETNDS16"
NWDSBACKUPOBJECT; "NETNDS16"
NWDSBEGINCLASSITEM; "NETNDS16"
NWDSCanDSAuthenticate; "NETNDS16"
NWDSCANONICALIZENAME; "NETNDS16"
NWDSCHANGEOBJECTPASSWORD; "NETNDS16"
NWDSCHANGEREPLICATYPE; "NETNDS16"
NWDSChangeResourceOnConnection; "NETCON16"
NWDSCISTRINGSMATCH; "NETNDS16"
NWDSCLOSEITERATION; "NETNDS16"
NWDSCOMPARE; "NETNDS16"
NWDSCOMPUTEATTRVALSIZE; "NETNDS16"
NWDSCONNECTTONDSSERVER; "NETNDS16"
NWDSCREATECONTEXT; "NETNDS16"
NWDSCREATECONTEXTHANDLE; "NETNDS16"
NWDSDEFINEATTR; "NETNDS16"
NWDSDEFINECLASS; "NETNDS16"
NWDSDELFILTERTOKEN; "NETNDS16"
NWDSDUPLICATECONTEXT; "NETNDS16"
NWDSDUPLICATECONTEXTHANDLE; "NETNDS16"
NWDSEXTSYNCLIST; "NETNDS16"
NWDSEXTSYNCREAD; "NETNDS16"
NWDSEXTSYNCSEARCH; "NETNDS16"
NWDSFREEBUF; "NETNDS16"
NWDSFREECONTEXT; "NETNDS16"
NWDSFREEFILTER; "NETNDS16"
NWDSGENERATEOBJECTKEYPAIR; "NETNDS16"
NWDSGETATTRCOUNT; "NETNDS16"
NWDSGETATTRDEF; "NETNDS16"
NWDSGETATTRNAME; "NETNDS16"
NWDSGETATTRVAL; "NETNDS16"
NWDSGETBINDERYCONTEXT; "NETNDS16"
NWDSGETCLASSDEF; "NETNDS16"
NWDSGETCLASSDEFCOUNT; "NETNDS16"
NWDSGETCLASSITEM; "NETNDS16"
NWDSGETCLASSITEMCOUNT; "NETNDS16"
NWDSGETCONNECTIONINFO; "NETCON16"
NWDSGETCONNECTIONSLOT; "NETCON16"
NWDSGETCONTEXT; "NETNDS16"
NWDSGETCOUNTBYCLASSANDNAME; "NETNDS16"
NWDSGETDSVERINFO; "NETNDS16"
NWDSGETEFFECTIVERIGHTS; "NETNDS16"
NWDSGETMONITOREDCONNECTION; "NETCON16"
NWDSGETOBJECTCOUNT; "NETNDS16"
NWDSGetObjectHostServerAddress; "NETNDS16"
NWDSGETOBJECTNAME; "NETNDS16"
NWDSGETPARTITIONINFO; "NETNDS16"
NWDSGETPARTITIONROOT; "NETNDS16"
NWDSGETSERVERADDRESSES; "NETNDS16"
NWDSGETSERVERDN; "NETNDS16"
NWDSGETSERVERNAME; "NETNDS16"
NWDSGETSYNTAXCOUNT; "NETNDS16"
NWDSGETSYNTAXDEF; "NETNDS16"
NWDSGETSYNTAXID; "NETNDS16"
NWDSINITBUF; "NETNDS16"
NWDSINSPECTENTRY; "NETNDS16"
NWDSJOINPARTITIONS; "NETNDS16"
NWDSLIST; "NETNDS16"
NWDSLISTATTRSEFFECTIVERIGHTS; "NETNDS16"
NWDSLISTBYCLASSANDNAME; "NETNDS16"
NWDSLISTCONTAINABLECLASSES; "NETNDS16"
NWDSLISTCONTAINERS; "NETNDS16"
NWDSLISTPARTITIONS; "NETNDS16"
NWDSLOCKCONNECTION; "NETCON16"
NWDSLOGIN; "NETNDS16"
NWDSLOGOUT; "NETNDS16"
NWDSMAPIDTONAME; "NETNDS16"
NWDSMAPNAMETOID; "NETNDS16"
NWDSMODIFYCLASSDEF; "NETNDS16"
NWDSMODIFYDN; "NETNDS16"
NWDSMODIFYOBJECT; "NETNDS16"
NWDSMODIFYRDN; "NETNDS16"
NWDSMOVEOBJECT; "NETNDS16"
NWDSOPENSTREAM; "NETNDS16"
NWDSPartitionReceiveAllUpDates; "NETNDS16"
NWDSPARTITIONSENDALLUPDATES; "NETNDS16"
NWDSPUTATTRNAME; "NETNDS16"
NWDSPUTATTRVAL; "NETNDS16"
NWDSPUTCHANGE; "NETNDS16"
NWDSPUTCLASSITEM; "NETNDS16"
NWDSPUTFILTER; "NETNDS16"
NWDSREAD; "NETNDS16"
NWDSREADATTRDEF; "NETNDS16"
NWDSREADCLASSDEF; "NETNDS16"
NWDSREADOBJECTINFO; "NETNDS16"
NWDSREADREFERENCES; "NETNDS16"
NWDSREADSYNTAXDEF; "NETNDS16"
NWDSREADSYNTAXES; "NETNDS16"
NWDSRELOADDS; "NETNDS16"
NWDSREMOVEALLTYPES; "NETNDS16"
NWDSREMOVEATTRDEF; "NETNDS16"
NWDSREMOVECLASSDEF; "NETNDS16"
NWDSREMOVEOBJECT; "NETNDS16"
NWDSREMOVEPARTITION; "NETNDS16"
NWDSREMOVEREPLICA; "NETNDS16"
NWDSREMSECURITYEQUIV; "NETNDS16"
NWDSREPAIRTIMESTAMPS; "NETNDS16"
NWDSREPLACEATTRNAMEABBREV; "NETNDS16"
NWDSRESOLVENAME; "NETNDS16"
NWDSRESTOREOBJECT; "NETNDS16"
NWDSSEARCH; "NETNDS16"
NWDSSETCONNECTIONINFO; "NETCON16"
NWDSSETCONTEXT; "NETNDS16"
NWDSSETMONITOREDCONNECTION; "NETCON16"
NWDSSPLITPARTITION; "NETNDS16"
NWDSSYNCPARTITION; "NETNDS16"
NWDSSYNCREPLICATOSERVER; "NETNDS16"
NWDSSyncSchema; "NETNDS16"
NWDSUNLOCKCONNECTION; "NETCON16"
NWDSVERIFYOBJECTPASSWORD; "NETNDS16"
NWDSWHOAMI; "NETNDS16"
NWEnableBroadcasts; "CALMSG16"
NWEnableFileServerLogin; "CALSRV16"
NWEnableTTS; "CALTTS16"
NWEndCapture; "CALPRT16"
NWEndOfJob; "CALMIS16"
NWExamineSemaphore; "CALSYN16"
NWFileSearchInitialize; "CALFIL16"
NWFileServerFileCopy; "CALFIL16"
NWFindFirstEA; "CALNAM16"
NWFindNextEA; "CALNAM16"
NWFinishServicingQueueJob2; "CALQMS16"
NWFinishServicingQueueJob; "CALQMS16"
NWFlushCapture; "CALPRT16"
NWFragNCPExtensionRequest; "CALNCP16"
NWFREECONNECTIONSLOT; "NETCON16"
NWFreeUnicodeTables; "LOCWIN16"
NWGetAccountStatus; "CALACT16"
NWGetActiveConnListByType; "CALFSE16"
NWGetActiveLANBoardList; "CALFSE16"
NWGetActiveProtocolStacks; "CALFSE16"
NWGetBannerUserName; "CALPRT16"
NWGetBinderyAccessLevel; "CALBND16"
NWGetBroadcastMessage; "CALMSG16"
NWGetBroadcastMode; "CALMSG16"
NWGetCacheInfo; "CALFSE16"
NWGetCaptureFlags; "CALPRT16"
NWGetCaptureFlagsConnRef; "CALPRT16"
NWGetCaptureStatus; "CALPRT16"
NWGetClientType; "CALMIS16"
NWGetCollationHandle; "LOCWIN16"
NWGetConnectionHandle; "CALCON16"
NWGETCONNECTIONIDFROMNAME; "NETCON16"
NWGETCONNECTIONIDFROMADDRESS; "NETCON16"
NWGetConnectionInformation; "CALCON16"
NWGetConnectionList; "CALCON16"
NWGetConnectionNumber; "CALCON16"
NWGetConnectionStatus; "CALCON16"
NWGetConnectionUsageStats; "CALCON16"
NWGetConnInfo; "CALCON16"
NWGetConnListFromObject; "CALCON16"
NWGetCPUInfo; "CALFSE16"
NWGetDataMigratorInfo; "CALMIG16"
NWGetDefaultConnectionID; "CALCON16"
NWGetDefaultConnRef; "CALCON16"
NWGETDEFAULTNAMECONTEXT; "NETCON16"
NWGetDefaultSupportModule; "CALMIG16"
NWGetDirCacheInfo; "CALFSE16"
NWGetDirectoryBase; "CALNAM16"
NWGetDirectoryHandlePath; "CALFIL16"
NWGetDirSpaceInfo; "CALFIL16"
NWGetDirSpaceLimitList; "CALFIL16"
NWGetDiskCacheStats; "CALSRV16"
NWGetDiskChannelStats; "CALSRV16"
NWGetDiskUtilization; "CALVOL16"
NWGetDMFileInfo; "CALMIG16"
NWGetDMVolumeInfo; "CALMIG16"
NWGetDriveInfoConnRef; "CALFIL16"
NWGetDriveInformation; "CALFIL16"
NWGetDrivePath; "CALFIL16"
NWGetDrivePathConnRef; "CALFIL16"
NWGetDriveStatus; "CALFIL16"
NWGetDriveStatusConnRef; "CALFIL16"
NWGetEAHandleStruct; "CALNAM16"
NWGetEffectiveDirectoryRights; "CALFIL16"
NWGetEffectiveRights; "CALFIL16"
NWGetExtendedFileAttributes2; "CALFIL16"
NWGetExtendedVolumeInfo; "CALVOL16"
NWGetFileConnectionID; "CALFIL16"
NWGetFileConnRef; "CALFIL16"
NWGetFileServerDateAndTime; "CALSRV16"
NWGetFileServerDescription; "CALSRV16"
NWGetFileServerExtendedInfo; "CALSRV16"
NWGetFileServerInformation; "CALSRV16"
NWGetFileServerInfo; "CALFSE16"
NWGetFileServerLANIOStats; "CALSRV16"
NWGetFileServerLoginStatus; "CALSRV16"
NWGetFileServerMiscInfo; "CALSRV16"
NWGetFileServerName; "CALSRV16"
NWGETFILESERVERUTCTIME; "NETNDS16"
NWGetFileServerVersion; "CALSRV16"
NWGetFileServerVersionInfo; "CALSRV16"
NWGetFileSystemStats; "CALSRV16"
NWGetFirstDrive; "CALFIL16"
NWGetFSDriveMapTable; "CALSRV16"
NWGetFSLANDriverConfigInfo; "CALSRV16"
NWGetGarbageCollectionInfo; "CALFSE16"
NWGetGeneralRouterAndSAPInfo; "CALFSE16"
NWGetInetAddr; "CALCON16"
NWGetInternetAddress; "CALCON16"
NWGetIPXSPXInfo; "CALFSE16"
NWGetKnownNetworksInfo; "CALFSE16"
NWGetKnownServersInfo; "CALFSE16"
NWGetLANCommonCountersInfo; "CALFSE16"
NWGetLANConfigInfo; "CALFSE16"
NWGetLANCustomCountersInfo; "CALFSE16"
NWGetLoadedMediaNumList; "CALFSE16"
NWGetLocalToUnicodeHandle; "LOCWIN16"
NWGetLongName; "CALNAM16"
NWGetLPTCaptureStatus; "CALPRT16"
NWGetLSLInfo; "CALFSE16"
NWGetLSLLogicalBoardStats; "CALFSE16"
NWGetMaximumConnections; "CALCON16"
NWGetMaxPrinters; "CALPRT16"
NWGetMediaMgrObjChildrenList; "CALFSE16"
NWGetMediaMgrObjInfo; "CALFSE16"
NWGetMediaMgrObjList; "CALFSE16"
NWGetMediaNameByMediaNum; "CALFSE16"
NWGetMonocaseHandle; "LOCWIN16"
NWGetNCPExtensionInfoByName; "CALNCP16"
NWGetNCPExtensionInfo; "CALNCP16"
NWGetNCPExtensionsList; "CALNCP16"
NWGETNEARESTDIRECTORYSERVICE; "NETCON16"
NWGETNEARESTDSCONNREF; "NETCON16"
NWGetNetWareFileSystemsInfo; "CALFSE16"
NWGetNetworkRouterInfo; "CALFSE16"
NWGetNetworkRoutersInfo; "CALFSE16"
NWGetNetworkSerialNumber; "CALSRV16"
NWGETNEXTCONNECTIONID; "NETCON16"
NWGetNLMInfo; "CALFSE16"
NWGetNLMLoadedList; "CALFSE16"
NWGetNLMsResourceTagList; "CALFSE16"
NWGetNSEntryInfo; "CALNAM16"
NWGetNSInfo; "CALNAM16"
NWGetNSLoadedList; "CALNAM16"
NWGetNSPath; "CALNAM16"
NWGetNumberNCPExtensions; "CALNCP16"
NWGETNUMCONNECTIONS; "NETCON16"
NWGetNWADVersion; "AUDWIN16"
NWGetNWCallsVersion; "CALMIS16"
NWGetNWLOCALEVersion; "LOCWIN16"
NWGETNWNETVERSION; "NETNDS16"
NWGetObjDiskRestrictions; "CALVOL16"
NWGetObjectConnectionNumbers; "CALCON16"
NWGetObjectDiskSpaceLeft; "CALBND16"
NWGetObjectEffectiveRights; "CALBND16"
NWGetObjectID; "CALBND16"
NWGetObjectName; "CALBND16"
NWGetOSVersionInfo; "CALFSE16"
NWGetOwningNameSpace; "CALNAM16"
NWGetPacketBurstInfo; "CALFSE16"
NWGetPathFromDirectoryBase; "CALFIL16"
NWGetPathFromDirectoryEntry; "CALFIL16"
NWGetPhysicalDiskStats; "CALSRV16"
NWGETPREFERREDCONNNAME; "NETCON16"
NWGETPREFERREDDSSERVER; "NETCON16"
NWGetPreferredServer; "CALCON16"
NWGetPrimaryConnectionID; "CALCON16"
NWGetPrinterDefaults; "CALPRT16"
NWGetPrinterQueueID; "CALQMS16"
NWGetPrinterStatus; "CALPRT16"
NWGetPrinterStrings; "CALPRT16"
NWGetProtocolStackConfigInfo; "CALFSE16"
NWGetProtocolStackCustomInfo; "CALFSE16"
NWGetProtocolStackStatsInfo; "CALFSE16"
NWGetProtocolStkNumsByMediaNum; "CALFSE16"
NWGetProtocolStkNumsByLANBrdNum; "CALFSE16"
NWGetQueueJobFileSize2; "CALQMS16"
NWGetQueueJobFileSize; "CALQMS16"
NWGetQueueJobList; "CALQMS16"
NWGetQueueJobList2; "CALQMS16"
NWGetRequesterVersion; "CALMIS16"
NWGetSearchDriveVector; "CALFIL16"
NWGetServerInfo; "CALFSE16"
NWGetServerSetCategories; "CALFSE16"
NWGetServerSetCommandsInfo; "CALFSE16"
NWGetServerSourcesInfo; "CALFSE16"
NWGetSparseFileBitMap; "CALFIL16"
NWGetSupportModuleInfo; "CALMIG16"
NWGetTaskInformationByConn; "CALMIS16"
NWGetTTSStats; "CALTTS16"
NWGetUnicodeToLocalHandle; "LOCWIN16"
NWGetUserInfo; "CALFSE16"
NWGetVolumeInfoWithNumber; "CALVOL16"
NWGetVolumeInfoWithHandle; "CALVOL16"
NWGetVolumeName; "CALVOL16"
NWGetVolumeNumber; "CALVOL16"
NWGetVolumeSegmentList; "CALFSE16"
NWGetVolumeStats; "CALVOL16"
NWGetVolumeSwitchInfo; "CALFSE16"
NWIncrement; "LOCWIN16"
NWInitUnicodeTables; "LOCWIN16"
NWIntEraseFiles; "CALFIL16"
NWIntFileSearchContinue; "CALFIL16"
NWIntMoveDirEntry; "CALFIL16"
NWIntScanDirectoryInformation2; "CALFIL16"
NWIntScanDirectoryInformation; "CALFIL16"
NWIntScanDirEntryInfo; "CALFIL16"
NWIntScanExtendedInfo; "CALFIL16"
NWIntScanFileInformation; "CALFIL16"
NWIntScanFileInformation2; "CALFIL16"
NWIntScanForTrustees; "CALFIL16"
NWisalnum; "LOCWIN16"
NWisalpha; "LOCWIN16"
NWisdigit; "LOCWIN16"
NWISDSAUTHENTICATED; "NETCON16"
NWISDSSERVER; "NETNDS16"
NWIsIDInUse; "CALCON16"
NWIsLNSSupportedOnVolume; "CALMIS16"
NWIsManager; "CALSRV16"
NWIsObjectInSet; "CALBND16"
NWitoa; "LOCWIN16"
NWLInsertChar; "LOCWIN16"
NWLlocaleconv; "LOCWIN16"
NWLmblen; "LOCWIN16"
NWLmbslen; "LOCWIN16"
NWLoadRuleTable; "LOCWIN16"
NWLocalToUnicode; "LOCWIN16"
NWLockConnection; "CALCON16"
NWLockFileLockSet; "CALFIL16"
NWLockLogicalRecordSet; "CALFIL16"
NWLockPhysicalRecordSet; "CALFIL16"
NWLogFileLock2; "CALFIL16"
NWLoginToFileServer; "CALSRV16"
NWLogLogicalRecord; "CALFIL16"
NWLogoutFromFileServer; "CALSRV16"
NWLogPhysicalRecord; "CALFIL16"
NWLongSwap; "CALMIS16"
NWLsetlocale; "LOCWIN16"
NWLSetPrimaryUnicodeSearchPath; "LOCWIN16"
NWLstrbcpy; "LOCWIN16"
NWLstrchr; "LOCWIN16"
NWLstrcoll; "LOCWIN16"
NWLstrcspn; "LOCWIN16"
NWLstrpbrk; "LOCWIN16"
NWLstrrchr; "LOCWIN16"
NWLstrrev; "LOCWIN16"
NWLstrspn; "LOCWIN16"
NWLstrstr; "LOCWIN16"
NWLstrtok; "LOCWIN16"
NWLstrupr; "LOCWIN16"
NWLstrxfrm; "LOCWIN16"
NWltoa; "LOCWIN16"
NWLTruncateString; "LOCWIN16"
NWModifyMaximumRightsMask; "CALFIL16"
NWMoveFileFromDM; "CALMIG16"
NWMoveFileToDM; "CALMIG16"
NWNCPExtensionRequest; "CALNCP16"
NWNetInit; "NETNDS16"
NWNetTerm; "NETNDS16"
NWNextChar; "LOCWIN16"
NWNSGetDefaultNS; "CALNAM16"
NWNSGetMiscInfo; "CALNAM16"
NWNSRename; "CALNAM16"
NWOpenBindery; "CALBND16"
NWOpenConnByName; "CALCON16"
NWOpenCreateNSEntry; "CALNAM16"
NWOpenDataStream; "CALNAM16"
NWOpenEA; "CALNAM16"
NWOpenNSEntry; "CALNAM16"
NWOpenSemaphore; "CALSYN16"
NWPackDate; "CALMIS16"
NWPackDateTime; "CALMIS16"
NWPackTime; "CALMIS16"
NWParseNetWarePath; "CALFIL16"
NWParseNetWarePathConnRef; "CALFIL16"
WParsePath; "CALFIL16"
NWParsePathConnRef; "CALFIL16"
NWPrevChar; "LOCWIN16"
NWPurgeDeletedFile; "CALFIL16"
NWPurgeErasedFiles; "CALFIL16"
NWQueryAccountingInstalled; "CALACT16"
NWReadEA; "CALNAM16"
NWReadExtendedNSInfo; "CALNAM16"
NWReadNSInfo; "CALNAM16"
NWReadPropertyValue; "CALBND16"
NWReadQueueCurrentStatus2; "CALQMS16"
NWReadQueueCurrentStatus; "CALQMS16"
NWReadQueueJobEntry; "CALQMS16"
NWReadQueueJobEntry2; "CALQMS16"
NWReadQueueServerCurrentStatus; "CALQMS16"
NWReadQueueServerCurrentStatus2; "CALQMS16"
NWRecoverDeletedFile; "CALFIL16"
NWReleaseFileLock2; "CALFIL16"
NWReleaseFileLockSet; "CALFIL16"
NWReleaseLogicalRecordSet; "CALFIL16"
NWReleaseLogicalRecord; "CALFIL16"
NWReleasePhysicalRecord; "CALFIL16"
NWReleasePhysicalRecordSet; "CALFIL16"
NWRemoveJobFromQueue2; "CALQMS16"
NWRemoveJobFromQueue; "CALQMS16"
NWRemoveObjectDiskRestrictions; "CALVOL16"
NWRenameDirectory; "CALFIL16"
NWRenameFile; "CALFIL16"
NWRenameObject; "CALBND16"
NWRequest; "CALMIS16"
NWRestoreDirectoryHandle; "CALFIL16"
NWRestoreErasedFile; "CALFIL16"
NWRestoreQueueServerRights; "CALQMS16"
NWSaveDirectoryHandle; "CALFIL16"
NWScanConnectionsUsingFile; "CALFIL16"
NWScanDirectoryForTrustees; "CALFIL16"
NWScanDirectoryForTrustees2; "CALFIL16"
NWScanForDeletedFiles; "CALFIL16"
NWScanLogicalLocksByName; "CALSYN16"
NWScanLogicalLocksByConn; "CALSYN16"
NWScanNCPExtensions; "CALNCP16"
NWScanNSEntryInfo; "CALNAM16"
NWScanObject; "CALBND16"
NWScanObjectTrusteePaths; "CALBND16"
NWScanOpenFilesByConn2; "CALFIL16"
NWScanOpenFilesByConn; "CALFIL16"
NWScanPhysicalLocksByFile; "CALSYN16"
NWScanPhysicalLocksByConnFile; "CALSYN16"
NWScanProperty; "CALBND16"
NWScanSemaphoresByConn; "CALSYN16"
NWScanSemaphoresByName; "CALSYN16"
NWScanVolDiskRestrictions; "CALVOL16"
NWScanVolDiskRestrictions2; "CALVOL16"
NWSendBroadcastMessage; "CALMSG16"
NWSendConsoleBroadcast; "CALMSG16"
NWServiceQueueJob; "CALQMS16"
NWServiceQueueJob2; "CALQMS16"
NWSetBannerUserName; "CALPRT16"
NWSetBroadcastMode; "CALMSG16"
NWSetCaptureFlags; "CALPRT16"
NWSetCompressedFileSize; "CALFIL16"
NWSETDEFAULTNAMECONTEXT; "NETCON16"
NWSetDefaultSupportModule; "CALMIG16"
NWSetDirectoryHandlePath; "CALFIL16"
NWSetDirectoryInformation; "CALFIL16"
NWSetDirEntryInfo; "CALFIL16"
NWSetDirSpaceLimit; "CALFIL16"
NWSetDriveBase; "CALFIL16"
NWSetEndOfJobStatus; "CALMIS16"
NWSetExtendedFileAttributes2; "CALFIL16"
NWSetFileAttributes; "CALFIL16"
NWSetFileInformation2; "CALFIL16"
NWSetFileInformation; "CALFIL16"
NWSetFileServerDateAndTime; "CALSRV16"
NWSetInitDrive; "CALFIL16"
NWSetLongName; "CALNAM16"
NWSetNetWareErrorMode; "CALMIS16"
NWSetNSEntryDOSInfo; "CALNAM16"
NWSetObjectVolSpaceLimit; "CALVOL16"
NWSETPREFERREDDSTREE; "NETCON16"
NWSetPreferredServer; "CALCON16"
NWSetPrimaryConn; "CALCON16"
NWSetPrimaryConnectionID; "CALCON16"
NWSetPrinterDefaults; "CALPRT16"
NWSetPrinterStrings; "CALPRT16"
NWSetQueueCurrentStatus; "CALQMS16"
NWSetQueueCurrentStatus2; "CALQMS16"
NWSetQueueServerCurrentStatus; "CALQMS16"
NWSetSearchDriveVector; "CALFIL16"
NWSignalSemaphore; "CALSYN16"
NWSMAddNSToVolume; "CALSVM16"
NWSMDismountVolumeByName; "CALSVM16"
NWSMDismountVolumeByNumber; "CALSVM16"
NWSMExecutNCFFile; "CALSVM16"
NWSMLoadNLM; "CALSVM16"
NWSMMountVolume; "CALSVM16"
NWSMSetDynamicCmdIntValue; "CALSVM16"
NWSMSetDynamicCmdStrValue; "CALSVM16"
NWSMUnloadNLM; "CALSVM16"
NWSpoolCancelCapture; "CALPRT16"
NWSpoolEndCapture; "CALPRT16"
NWSpoolGetBannerUserName; "CALPRT16"
NWSpoolSetBannerUserName; "CALPRT16"
NWStartFileCapture; "CALPRT16"
NWStartLPTCapture; "CALPRT16"
NWStartQueueCapture; "CALPRT16"
NWstrImoney; "LOCWIN16"
NWStripServerOffPath; "CALFIL16"
NWstrlen; "LOCWIN16"
NWstrmoney; "LOCWIN16"
NWstrncoll; "LOCWIN16"
NWstrncpy; "LOCWIN16"
NWstrnum; "LOCWIN16"
NWSubmitAccountCharge; "CALACT16"
NWSubmitAccountHold; "CALACT16"
NWSubmitAccountNote; "CALACT16"
NWSysCloseConn; "CALCON16"
NWTTSAbortTransaction; "CALTTS16"
NWTTSBeginTransaction; "CALTTS16"
NWTTSEndTransaction; "CALTTS16"
NWTTSGetConnectionThresholds; "CALTTS16"
NWTTSGetControlFlags; "CALTTS16"
NWTTSGetProcessThresholds; "CALTTS16"
NWTTSIsAvailable; "CALTTS16"
NWTTSSetConnectionThresholds; "CALTTS16"
NWTTSSetControlFlags; "CALTTS16"
NWTTSSetProcessThresholds; "CALTTS16"
NWTTSTransactionStatus; "CALTTS16"
NWultoa; "LOCWIN16"
NWUnicodeCompare; "LOCWIN16"
NWUnicodeToCollation; "LOCWIN16"
NWUnicodeToLocal; "LOCWIN16"
NWUnicodeToMonocase; "LOCWIN16"
NWUnloadRuleTable; "LOCWIN16"
NWUnpackDate; "CALMIS16"
NWUnpackDateTime; "CALMIS16"
NWUnpackTime; "CALMIS16"
NWutoa; "LOCWIN16"
NWVerifyObjectPassword; "CALBND16"
NWvsprintf; "LOCWIN16"
NWWaitOnSemaphore; "CALSYN16"
NWWordSwap; "CALMIS16"
NWWriteEA; "CALNAM16"
NWWriteExtendedNSInfo; "CALNAM16"
NWWriteNSInfo; "CALNAM16"
NWWritePropertyValue; "CALBND16"
unicat; "LOCWIN16"
unichr; "LOCWIN16"
unicpy; "LOCWIN16"
unicspn; "LOCWIN16"
uniicmp; "LOCWIN16"
unilen; "LOCWIN16"
unincat; "LOCWIN16"
unincpy; "LOCWIN16"
uninicmp; "LOCWIN16"
uninset; "LOCWIN16"
unipbrk; "LOCWIN16"
unipcpy; "LOCWIN16"
unirchr; "LOCWIN16"
unirev; "LOCWIN16"
uniset; "LOCWIN16"
unisize; "LOCWIN16"
unispn; "LOCWIN16"
unistr; "LOCWIN16"
unitok; "LOCWIN16"

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates