NetWare Programming in Visual Basic: Using Apiary's NetWare Client SDK for Visual Basic
Articles and Tips: article
Senior Research Engineer
Novell Research
01 Jul 1994
In the July '93 issue of NetWare Application Notes, Novell Research provided Visual Basic programmers with an interface to the Windows client API. A software development kit (SDK) from Apiary provides a new Visual Basic interface to the latest NetWare Windows client API. This article describes the contents of the SDK, and gives an example program based on it.
NIVB
In the July '93 issue of NetWare Application Notes (now Novell Application Notes), Novell Research introduced a NetWare programming interface for Visual Basic. The NetWare Interface for Visual Basic (NIVB) consisted of declarations for all the functions in the NetWare C Interface for Windows SDK (software development kit). Since that time, Novell has released a new Windows programming interface, in the NetWare Client SDK. The new interface, sometimes called the NWCALLS interface, differs from the previous interface in a number of ways:
Function names begin with "NW"; some function names have been shortened or otherwise changed.
Most functions have a connection handle parameter that specifies which file server the function is directed to. Under the previous interface, function calls were directed to the preferred or default file server.
The NWCALLS interface includes functions for NetWare Directory Services and other NetWare 4-specific functions.
Because NIVB was not an official Novell product, it was not supported through Novell's developer support channels. Novell Research provided a couple example programs that illustrated how to use NIVB to call a number of NetWare functions, but for the most part, NIVB has been unsupported.
Apiary's NetWare Client SDK for Visual Basic
Apiary, a software tools developer based in Little Rock, Arkansas, has released a Visual Basic interface for NetWare, based on the NetWare Client SDK. Apiary's product, the NetWare Client SDK for Visual Basic, includes function declarations for all NetWare APIs in the NetWare Client API, including Internationalization and Unicode services, but not including the transport protocol API (IPX, SPX, TLI, SAP, and Named Pipes). The following is a list of the API service groups included in the SDK:
Accounting ServicesApple File ServicesAuditing ServicesAuditing Services (Directory Support)Bindery ServicesConnection ServicesConnection Services (Directory Support)Data Migration ServicesDeleted File ServicesDirectory Services: AccessDirectory Services: AuthenticationDirectory Services:Context and Buffer ManagementDirectory Services: MiscellaneousDirectory Services: Partition ManagementDirectory Services: Schema ManagementExtended Attribute ServicesFile Server Environment Services |
File System Services: Directory EntryFile System Services: FileFile System Services: SubdirectoryInternationalization ServicesMessage ServicesMiscellaneous ServicesName Space ServicesNCP Extension ServicesPath and Drive ServicesPrint ServicesPrint Server Services: CommunicationPrint Server Services: ConfigurationPrint Server Services: Printer DefinitionQueue Management ServicesSynchronization ServicesTransaction Tracking ServicesUnicode ServicesVolume Services |
The SDK also includes constant declarations, and declarations for data structures that are used as parameters to NetWare functions.
Online Help
The SDK includes online documentation for the entire API set in WinHelp format. The online documentation is identical to the API reference manual included with Novell's NetWare Client SDK, with the addition of Visual Basic declarations for each function. Figure 1 shows the help entry for the NWChangeObjectSecurity function.
Figure 1: Online help for NetWare Client SDK for Visual Basic.
Example Programs
Apiary's SDK includes 20 example programs, illustrating how to use a number of NetWare features, including NetWare Directory Services, bindery services, file management, semaphores, volume auditing, and drive mapping.
Ordering Information
The NetWare Client SDK for Visual Basic costs $395, and is available from:
Apiary, a division of Intelec Systems Corporation
Phone: |
501-221-3699 |
Fax: |
501-221-7412 |
Payment: |
Visa/Mastercard/money order |
Shipping: |
$10 for overnight delivery, or same day via Compuserve mail |
Returns: |
30 day return policy |
Programmer Notes
NetWare's NWCALLS interface was designed primarily with C programmers in mind. When calling NetWare functions from Visual Basic, there are some accommodations you must make for the differences between Basic and C.
String Arguments
Visual Basic has two types of strings: variable-length strings and fixed-length strings. Fixed-length strings must be declared with a Dim statement that specifies how many characters to allocate for the string variable. For example,
Dim name As String * 48
declares a 48-character string variable called name.
Variable-length strings are, by default, zero bytes in length, and Visual Basic resizes them as programs modify their contents.
DLL routines cannot increase the length of Visual Basic strings (whether fixed- or variable-length). If a routine attempts to write a longer string than the one it receives as an argument, the routine will overwrite memory and cause a general protection fault.
Before calling a DLL routine that modify a string argument, Visual Basic programs must make sure that the string arguments are long enough for the longest possible string that can be returned by the routine. For example, NWScanObject returns a bindery object name in its objectName parameter. Bindery object names can be up to 48 characters, including the terminating null. Programs should either pass a fixed-length string of 48 characters in the objectName argument, or initialize a variable-length string to at least 48 characters.
Sometimes programs must check to see if a DLL routine has returned a null string in a string argument. In C, you could use the strlen function to see if the string has length zero (that is, if the first character in the string array is a null). In Visual Basic, you must explicitly look for the null. If you initialize a string to 48 null characters, Visual Basic's Len function will say that it has length 48.
Unsigned Arguments
Many NetWare DLL routines have unsigned arguments. The C interface has BYTE, WORD, and DWORD types that are defined as unsigned char, int, and long, respectively. Visual Basic has only signed data types. Because Visual Basic verifies only that arguments passed to DLL routines are the right number of bytes, it (for example) converts signed integers to unsigned WORD arguments without a type conflict. When working with unsigned arguments, you should keep in mind that this type conversion is taking place. When a DLL routine returns the value 65535 in a WORD argument, Visual Basic will interpret it as an Integer with the value -1.
Example Program: VIEWBIND
The program described below, VIEWBIND, was written with Visual Basic 3.0 and Apiary's NetWare Client SDK for Visual Basic. The program scans the bindery of a file server (selected by the user), and displays the name, type, and bindery ID of each object found. The user can specify whether to search for all objects, or just objects of a certain type (users, file servers, etc.). Figure 2 shows VIEWBIND's main screen display.
Figure 2: VIEWBIND bindery object list.
If the user double-clicks on an object, VIEWBIND opens another form and displays the object's properties, as shown in Figure 3.
Figure 3: VIEWBIND object property list.
If the user then double-clicks on one of the object's properties, VIEWBIND opens another window and displays the property's value. If the property is a set, VIEWBIND displays the names of bindery objects in the selected property's set, as shown in Figure 4.
Figure 4: VIEWBIND property value display.
One interesting aspect of the program is the list of bindery object types that the user is allowed to select from. Novell's Client SDK has constant declarations for 20 bindery object types. A network administrator collected a more complete list of object types, and posted it on Compuserve's NOVUSER forum. The list is unofficial, and is not guaranteed to be complete or accurate. The object types in the list are shown in Figure 5.
Figure 5: Bindery object types.
Object |
Bindery objecttype value |
WILD |
OT_WILD (-1 or &HFFFF) |
User |
OT_USER (&H0100) |
User Group |
OT_USER_GROUP (&H0200) |
Print Queue |
OT_PRINT_QUEUE (&H0300) |
File Server |
OT_FILE_SERVER (&H0400) |
Job Server |
OT_JOB_SERVER (&H0500) |
Gateway |
OT_GATEWAY (&H0600) |
Print Server |
OT_PRINT_SERVER (&H0700) |
Archive Queue |
OT_ARCHIVE_QUEUE (&H0800) |
Archive Server |
OT_ARCHIVE_SERVER (&H0900) |
Job Queue |
OT_JOB_QUEUE (&H0A00) |
Administration |
OT_ADMINISTRATION (&H0B00) |
NetBIOS |
&H2000 |
NAS SNA Gateway |
OT_NAS_SNA_GATEWAY (&H2100) |
NACS |
&H2300 |
Remote Bridge Server |
&H2400 |
Bridge Server |
OT_REMOTE_BRIDGE_SERVER (&H2600) |
TCP/IP Gateway |
OT_TCPIP_GATEWAY (&H2700) |
Eicon X.25 Point-Point Gateway |
&H2800 |
Eicon 3270 Gateway |
&H2900 |
Time Synch Server |
OT_TIME_SYNCHRONIZATION_SERVER(&H2D00) |
Arch Server Dyn SAP/SMS TSA |
OT_ARCHIVE_SERVER_DYNAMIC_SAP(&H2E00) |
DI3270 Gateway |
&H4500 |
Advertising Print Server |
OT_ADVERTISING_PRINT_SERVER(&H4700) |
Micom Interlan TCP/IP Gateway |
&H4800 |
Btrieve VAP v5.x |
&H4B00 |
NetWare SQL |
&H4C00 |
Xtree Network Version |
&H4D00 |
Btrieve VAP v4.x |
OT_BTRIEVE_VAP (&H5000) |
Print Queue User |
OT_PRINT_QUEUE_USER (&H5300) |
ARCserve VAP |
&H5500 |
Eicon X.25 Multipoint Gateway |
&H5800 |
ARCserve 3.0 |
&H6600 |
WANcopy Utility |
&H7200 |
TES - NetWare for VMS |
&H7A00 |
Emerald Backup |
&H9200 |
NetWare Access Server |
&H9800 |
Portable NetWare |
&H9E00 |
Progress DB Server |
&H9F00 |
PowerChute NLM (old) |
&HA100 |
Compaq IDA Status Monitor |
&HAC00 |
Intel LAN Protect |
&H201 |
Oracle DB Server |
&H301 |
RSPX |
&H701 |
Novell SNA Gateway |
&HF01 |
HP Print Server |
&H1201 |
CSA MUX |
&H1401 |
CSA LCA |
&H1501 |
CSA CM |
&H1601 |
CSA SMA |
&H1701 |
CSA DBA |
&H1801 |
CSA NMA |
&H1901 |
CSA SSA |
&H1A01 |
CSA STATUS |
&H1B01 |
CSA APPC |
&H1E01 |
SNA TEST |
&H2601 |
CSA TRACE |
&H2A01 |
Communications Executive |
&H3001 |
NNS Domain |
&H3301 |
NNS Profile |
&H3501 |
NNS Queue |
&H3701 |
NNS Domain Scheme Descriptor |
&H3801 |
Intel LANSpool VAP |
&H4101 |
Aladdin Knowledge |
&H4201 |
IrmaLAN Gateway |
&H5201 |
Intel PICKIT/CAS Talk Server |
&H6801 |
Compaq SNMP Agent |
&H7401 |
Xtree Server |
&H8001 |
Xtree |
&H8901 |
GARP Gateway |
&HB001 |
BindView |
&HB101 |
NMA Agent |
&H3302 |
LANZ Agent 401F NetExp |
&H3702 |
LANZ Agent 4800 |
&H3802 |
NMS Hub Management |
&H3902 |
LANZ Agent 401F |
&H3A02 |
NMS Console |
&H6A02 |
NW 4 Time Sync Server |
&H6B02 |
NW 4 NDS Server |
&H7802 |
NetWare for SAA Gateway |
&H403 |
Gallacticom BBS |
&HA03 |
HP Laserjet |
&HC03 |
Attachmate 3270 Gateway |
&H2003 |
PowerChute v3.0 |
&H7E03 |
ViruSafe Notify |
&H7F03 |
HP Bridge |
&H8603 |
HP Hub |
&H8703 |
Lotus Notes |
&H9B03 |
Certus Anti Virus NLM |
&HB703 |
ARCserve 4.0 |
&HC403 |
Intel LANSpool 3.5 |
&HC703 |
Lexmark 4033 Print Server |
&HD503 |
NetWare SQL/Gupta NLM |
&HDE03 |
UnixWare |
&HE103 |
UnixWare |
&HE403 |
SiteLock Anti-virus |
&H2904 |
SyBase |
&H7404 |
SyBase |
&H7504 |
SiteLock Checks |
&H2005 |
SiteLock Checks |
&H2905 |
SiteLock |
&H290B |
SiteLock Applications |
&H290C |
LAI SiteLock |
&H8023 |
Meeting Maker |
&H8C23 |
SiteLock Server |
&H848 |
SiteLock User |
&H5555 |
Tapeware |
&H1263 |
Rabbit 3270 Gateway |
&H6F |
Intel NetPort |
&H280 |
WordPerfect Network Version |
&H8888 |
SiteLock |
&H1FF1 |
Most of the source code for VIEWBIND is given below. Declarations for the user interface data structures have not been included, and the two large IF-THEN-ELSEIF-ELSE statements that deal with bindery object types have been shortened to save space. Source code for VIEWBIND is available on Compuserve's NOVLIB forum, Library 11.
GLOBAL.BAS
GLOBAL.BAS contains global declarations for VIEWBIND:
Global connHandle% Global propFlags% Global propSec% Global hasValue%
VIEWBIND.FRM
VIEWBIND.FRM contains one constant declaration and five functions:
Form_Load initializes the list of attached file servers and the list of bindery object types.
GetObjectType converts a bindery object type the user selected from the object type list to the corresponding integer value.
ObjectList_DblClick, which is executed when the user double-clicks on a bindery object in the bindery object list box. ObjectList_DblClick displays the form that gives information (including the property list) for the selected object.
ScanButton_Click, which is executed when the user clicks the button labelled "Scan" or "Rescan." The subroutine contains the program's main loop, which scans for all the objects of the selected type in the selected file server's bindery.
ServerNameBox_Click, which is executed when the user selects a server from the list of attached file servers. The subroutine changes the global connection handle variable, so that subsequent NetWare function calls are directed to the proper file server.
Const SUCCESSFUL = 0 Sub Form_Load () Dim connections As CONN_LIST Dim serverName As String * 49 Main.Show ScanButton.SetFocus 'Get the connection ID of the default server ' (used in nearly all other NetWare calls) ccode% = NWGetDefaultConnectionID(connHandle%) If (ccode% << SUCCESSFUL) Then< response = MsgBox("Unable to get default connection ID", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") End End If 'Get list of servers we're connected to for ServerNameBox 'CONN_LIST is declared as an array of 25 integers maxConns% = 24 ccode% = NWGetConnectionList(0, connections, maxConns%, numConns%) If (ccode% << SUCCESSFUL) Then< response = MsgBox("Unable to get server connection list", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") End End If For conn% = 0 To numConns% - 1 serverName = String$(49, 0) ccode% = NWGetFileServerName(connections.connection(conn%), serverName) ServerNameBox.AddItem serverName Next conn% serverName = String$(49, 0) ccode% = NWGetFileServerName(connHandle%, serverName) ServerNameBox.Text = serverName 'Build list of object types ObjectTypeBox.Text = "WILD (all types)" ObjectTypeBox.AddItem "WILD (all types)" ObjectTypeBox.AddItem "User" ObjectTypeBox.AddItem "User Group" . . . ObjectTypeBox.AddItem "SiteLock F11F" End Sub Function GetObjectType () As Integer 'This list of object types is taken from a list that was posted on NOVUSER ' no claim is made for accuracy or completeness ' ID values are in hi-lo byte order If ObjectTypeBox.Text = "WILD (all types)" Then GetObjectType = OT_WILD ElseIf ObjectTypeBox.Text = "User" Then GetObjectType = OT_USER ElseIf ObjectTypeBox.Text = "User Group" Then GetObjectType = OT_USER_GROUP . . . ElseIf ObjectTypeBox.Text = "SiteLock F11F" Then GetObjectType = &H1FF1& Else GetObjectType = Val(ObjectTypeBox.Text) End If End Function Sub ObjectList_DblClick () On Error GoTo oops ObjectInfo.Show 1 Exit Sub oops: Resume Next End Sub Sub ScanButton_Click () Dim objectName As String * 48 ScanButton.Caption = "Re&scan"& ObjectList.Clear 'main scan loop On Error GoTo OutOfMemory searchType% = GetObjectType() objectID& = -1 Main.MousePointer = 11 Do objectName = String$(49, 0) ccode% = NWScanObject(connHandle%, "*", searchType%, objectID&, objectName, objectType%, 0, 0, 0) out$ = Format$(Left$(objectName, InStr(objectName, Chr$(0)) - 1), "!" + String$(48, "@")) out$ = out$ + " " + Format$(Hex$(objectType%), "@@@@ ") out$ = out$ + Format$(Hex$(objectID&), "@@@@@@@@") If (ccode% = SUCCESSFUL) Then ObjectList.AddItem out$ Loop While (ccode% = SUCCESSFUL) EndOfLoop: Main.MousePointer = 0 Exit Sub OutOfMemory: If Err = 7 Then response = MsgBox("Unable to add item to list: out of memory", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") Else response = MsgBox("Unable to add item to list", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") End If Resume EndOfLoop End Sub Sub ServerNameBox_Click () ccode% = NWGetConnectionHandle(ServerNameBox.Text, 0, connHandle%, 0) If (ccode% << SUCCESSFUL) Then< response = MsgBox("Unable to get server connection ID", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") End End If End Sub
OBJINFO.FRM
OBJINFO.FRM contains three subroutines:
CloseButton_Click, which unloads the form when the user clicks on the button labelled "Close."
Form_Load, which displays information about the selected bindery object: its name, type, and object ID, whether the object is static or dynamic, the object's read and write security levels, and a list of the object's properties (if any).
PropertyList_DblClick, which is executed when the user double-clicks on one of the object's properties. PropertyList_DblClick displays the form that gives information about the selected property.
Sub CloseButton_Click () Unload ObjectInfo End Sub Sub Form_Load () Dim propName As String * 48 Dim objectName As String * 48 'Get the object name, type, and ID from the string on the Main form ObjectNameLabel.Caption = RTrim$(Left$(Main.ObjectList.List(Main.ObjectList.ListIndex), 48)) ObjectTypeLabel.Caption = LTrim$(Mid$(Main.ObjectList.List(Main.ObjectList.ListIndex), 51, 4)) searchType% = Val("&H" + ObjectTypeLabel.Caption)& ObjectIDLabel.Caption = LTrim$(Right$(Main.ObjectList.List(Main.ObjectList.ListIndex), 8)) 'Rescan the object to get all information about it ccode% = NWScanObject(connHandle%, ObjectNameLabel.Caption, searchType%, objectID&, objectName, objectType%, hasProps%, objectFlags%, objectSecurity%) If (ccode% << SUCCESSFUL) Then< response = MsgBox("Unable to get information about object", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") Unload ObjectInfo Else If (objectFlags% = BF_STATIC) Then FlagsLabel.Caption = "Static" Else FlagsLabel.Caption = "Dynamic" End If objectReadSecurity% = objectSecurity% And &HF& If (objectReadSecurity% = BS_ANY_READ) Then ReadLabel.Caption = "Any" ElseIf (objectReadSecurity% = BS_LOGGED_READ) Then ReadLabel.Caption = "Logged" ElseIf (objectReadSecurity% = BS_OBJECT_READ) Then ReadLabel.Caption = "Object" ElseIf (objectReadSecurity% = BS_SUPER_READ) Then ReadLabel.Caption = "Supervisor" ElseIf (objectReadSecurity% = BS_BINDERY_READ) Then ReadLabel.Caption = "Bindery" End If objectWriteSecurity% = (objectSecurity% And &HF0)& If (objectWriteSecurity% = BS_ANY_WRITE) Then WriteLabel.Caption = "Any" ElseIf (objectWriteSecurity% = BS_LOGGED_WRITE) Then WriteLabel.Caption = "Logged" ElseIf (objectWriteSecurity% = BS_OBJECT_WRITE) Then WriteLabel.Caption = "Object" ElseIf (objectWriteSecurity% = BS_SUPER_WRITE) Then WriteLabel.Caption = "Supervisor" ElseIf (objectWriteSecurity% = BS_BINDERY_WRITE) Then WriteLabel.Caption = "Bindery" End If 'get properties, if any seq& = -1 If (hasProps% << 0) Then< ccode% = NWScanProperty(connHandle%, objectName, objectType%, "*", seq&, propName, propFlags%, propSec%, hasValue%, more%) If (ccode% << SUCCESSFUL) Then< response = MsgBox("Unable to get property information", MB_OK + MB_ICONEXCLAMATION, "Bindery Scanner Error") Else Do PropertyList.AddItem propName ccode% = NWScanProperty(connHandle%, objectName, objectType%, "*", seq&, propName, propFlags%, propSec%, hasValue%, more%) Loop While ((ccode% = SUCCESSFUL) And (more% << 0))< End If End If End If End Sub Sub PropertyList_DblClick () PropInfo.Show 1 End Sub
PROPINFO.FRM
PROPINFO.FRM contains two subroutines:
CloseButton_Click, which unloads the form when the user clicks on the button labelled "Close."
Form_Load, which displays information about the selected property, including its name, whether it is static or dynamic, its read and write security, and the property's value, if any. If the property is a set, the subroutine displays a list of the bindery objects in the set, by name. If the property is an item, the property's value is displayed in hex and text formats.
Sub CloseButton_Click () Unload PropInfo End Sub Sub Form_Load () Dim segData As PROPERTY_BUFFER Dim objectName As String * 48 PropNameLabel.Caption = ObjectInfo.PropertyList.List(ObjectInfo.PropertyList.ListIndex) ObjectNameLabel.Caption = ObjectInfo.ObjectNameLabel.Caption If (propFlags% = BF_STATIC) Then FlagLabel1.Caption = "Static" Else FlagLabel1.Caption = "Dynamic" End If propReadSec% = propSec% And &HF& If (propReadSec% = BS_ANY_READ) Then ReadLabel.Caption = "Any" ElseIf (propReadSec% = BS_LOGGED_READ) Then ReadLabel.Caption = "Logged" ElseIf (propReadSec% = BS_OBJECT_READ) Then ReadLabel.Caption = "Object" ElseIf (propReadSec% = BS_SUPER_READ) Then ReadLabel.Caption = "Supervisor" ElseIf (propReadSec% = BS_BINDERY_READ) Then ReadLabel.Caption = "Bindery" End If propWriteSec% = (propSec% And &HF0)& If (propWriteSec% = BS_ANY_WRITE) Then WriteLabel.Caption = "Any" ElseIf (propWriteSec% = BS_LOGGED_WRITE) Then WriteLabel.Caption = "Logged" ElseIf (propWriteSec% = BS_OBJECT_WRITE) Then WriteLabel.Caption = "Object" ElseIf (propWriteSec% = BS_SUPER_WRITE) Then WriteLabel.Caption = "Supervisor" ElseIf (propWriteSec% = BS_BINDERY_WRITE) Then WriteLabel.Caption = "Bindery" End If If (hasValue% << 0) Then< segment% = 1 Do objectType% = Val("&H" + (ObjectInfo.ObjectTypeLabel.Caption))& ccode% = NWReadPropertyValue(connHandle%, ObjectNameLabel.Caption, objectType%, PropNameLabel.Caption, segment%, segData, more%, flags%) If (ccode% = SUCCESSFUL) Then segment% = segment% + 1 If (flags% = BF_ITEM) Then FlagLabel2.Caption = "Item" 'display the segment data in hex and character formats For row% = 0 To 7 out$ = "" For char% = 1 To 16 If (Asc(Mid$(segData.Value, (row% * 16) + char%, 1)) < 16) Then< out$ = out$ + "0" End If out$ = out$ + Hex$(Asc(Mid$(segData.Value, (row% * 16) + char%, 1))) + " " Next char% out$ = out$ + " " For char% = 1 To 16 If ((Asc(Mid$(segData.Value, (row% * 16) + char%, 1)) > 31) And (Asc(Mid$(segData.Value, (row% * 16) + char%, 1)) > 127)) Then> out$ = out$ + Mid$(segData.Value, (row% * 16) + char%, 1) Else out$ = out$ + "." End If Next char% DataDump.AddItem out$ Next row% 'Add blank line to separate segments DataDump.AddItem "" Else FlagLabel2.Caption = "Set" 'display object IDs and corresponding names id% = 0 Do itemID$ = "" For char% = 1 To 4 digit$ = Hex$(Asc(Mid$(segData.Value, (id% * 4) + char%, 1))) If (Len(digit$) < 2) Then digit$ = "0" + digit$< itemID$ = itemID$ + digit$ Next char% setItemID& = NWLongSwap(Val("&H" + itemID$))& = NWLongSwap(Val("& If (setItemID<< 0) Then< ccode% = NWGetObjectName(connHandle%, setItemID&, objectName, objectType%) If (ccode% << SUCCESSFUL) Then objectName = "Unknown object"< DataDump.AddItem Format$(Hex$(setItemID&), "@@@@@@@@ ") + objectName id% = id% + 1 End If Loop While ((setItemID<< 0) And (id% < 32))< End If Else DataDump.AddItem "Unable to get property value, error: " + Hex$(ccode%) End If Loop While ((ccode% = SUCCESSFUL) And (more% << 0))< End If End Sub
* 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.