Legal Information

Microsoft Systems Management Server
Programmer's Reference

Information in this document is subject to change without notice. This document is provided for informational purposes only and Microsoft Corporation makes no warranties, either express or implied, in this document. The entire risk of the use or the results of the use of this document remains with the user. The names of companies, products, people, characters, and/or data mentioned herein are fictitious and are in no way intended to represent any real individual, company, product, or event, unless otherwise noted. Complying with all applicable copyright laws is the responsibility of the user. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, without the express written permission of Microsoft Corporation. If, however, your only means of access is electronic, permission to print one copy is hereby granted.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

© 1996–1998 Microsoft Corporation. All rights reserved.

Microsoft, Windows, Win32, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.


Introduction

Microsoft® Systems Management Server (SMS) contains a set of libraries, header files, online Help, and sample source programs with which you can create applications that extend the SMS system and take advantage of its resources.

With the SMS component of the Platform SDK, you can extend or use SMS in the following ways:

Add custom objects and groups to the SMS inventory
Provides instructions for extending the SMS inventory by using Desktop Management Task Force (DMTF) standard Management Information Format (MIF) files. By using MIF files, you can add objects with custom architectures (such as printers and routers) to the inventory, add a new object to an existing architecture, and add groups (such as device driver information, hardware peripherals, and monitors) to computers already existing in the SMS database.
Access the SMS site database by using the SMS API
Provides an application programming interface (API) to access objects in the SMS site database. This means you can write applications that:
  • Access inventory data for SMS computers and other inventoried objects.
  • Access or delete existing packages and create new packages that define software for distribution.
  • Access or delete existing jobs and create new jobs that distribute software or run a command.
  • Access existing machine groups, which serve as aliases for groups of target computers for software distribution.
  • Access existing site groups, which serve as aliases for groups of target sites for software distribution.
  • Access or delete existing queries and create new queries that specify criteria for searching for SMS computers and other inventoried objects.

The SMS API also provides a sophisticated filtering mechanism to retrieve the exact objects that you want to find.

Create applications that are ready to distribute with SMS
Provides guidelines for writing setup programs or scripts so that they will be easy to distribute and run with SMS. Information is also provided for reporting custom installation status information back to the SMS system (this is done by using a MIF file).

Instructions for creating Package Definition Format (PDF) files for software packages are also provided. PDF files are ASCII text files that define a software package for distribution as a server version and a local installation version, and define inventory information used to find the package on SMS computers. When you have software that you want to make easy to distribute with SMS, you can provide a PDF file with your application disks so that an administrator can easily load the package information into SMS. After importing a PDF file, the administrator only needs to specify the network location of the source files for the software.

Access the SMS site database by using existing applications, ODBC, and SMSVIEW
Provides samples for accessing the SMS site database by using other applications such Microsoft® Word, Microsoft® Excel, and Microsoft® Access. This access is provided through use of the SMSVIEW.EXE utility, Open Database Connectivity (ODBC), and the ODBC SQL Server driver. SMSVIEW creates SQL Server views. The samples access the data in an SMS site database by using those views.
Override and extend graphics in the SMS Administrator
Provides instructions and samples for extending the SMS Administrator user interface. If you create a custom object and add a custom icon to display for it (or if you want to change the icon for an existing item, such as a Macintosh computer), you can create a resource DLL that contains the resources for the custom icon.
Create protocol parser DLLs for Network Monitor
Provides instructions and samples for creating a protocol parser DLL for the Network Monitor.

Network Monitor displays protocol information for network administrators to use when viewing network traffic and troubleshooting problems. By writing custom protocol parsers, you can extend the set of protocols for which information is displayed.

Add third-party and ISV applications into the SMS console
Provides support for launching ISV applications from the SMS Administrator console.

SMS supports application launching from its Tools menu. The application information is added to the Windows NT Registry. SMS uses this information to launch applications based on the user selections in the SMS Administrator console. By adding this information to the Registry, you can integrate your applications with SMS.


Extending the Inventory

To help you store and manage inventory information, Systems Management Server provides the following predefined architectures:

  • Personal Computer
  • SMSEvent
  • PackageLocation
  • JobDetails
  • UserGroups

To extend the inventory, you can also define custom architectures.

By using ASCII text files in the Management Information Format (MIF), you can add objects with new (custom) architectures to the SMS database, add new objects with existing architectures, and add new groups and attributes to existing objects. For example, you may want to add "Printers" to your list of architectures, add a new workstation with a Personal Computer architecture, or include a new device driver group in the inventory of a workstation.

The following topics contain background information on SMS inventories:

  • Inventory Terms
  • How MIF Files are Used to Maintain Inventory in an SMS Database

The following topics contain information on and procedures for customizing SMS inventories:

  • Adding Objects with Custom Architectures to the Inventory
  • Adding New Groups to Objects Already Existing in the SMS Inventory
  • Creating Forms to Generate MIF Files

For easy reference, the following topics contain a sample MIF file and important Desktop Management Interface (DMI) compatibility information:

  • Example MIF File for an Object with a Custom Architecture
  • Desktop Management Interface (DMI) Compatibility

For additional information about MIF format, refer to the Desktop Management Interface Specification version 4.5 (DMI45.DOC) provided in the \MSSDK\DOC subdirectory of the Microsoft® Platform SDK CD-ROM.


Inventory Terms

In an SMS site database, the inventory has a hierarchical structure. An architecture defines the structure for a set of objects. Each object is composed of groups, which contain attributes.

All inventory objects in the SMS system use the following structure:

Architecture
A standard structure for inventorying a set of related objects. An architecture is defined by the Architecture group, which specifies a unique architecture name. For a specific object, the attributes of its Identification group combine to form a unique identifier for the object. For example, the Personal Computer architecture has a structure for storing inventory for Intel x86, Alpha, MIPS, and Macintosh-based computers. The Identification group for Personal Computer objects contains six attributes that are used to uniquely identify a computer.
Object
A specific item with a specific architecture that is stored in the inventory database. For example, a specific Macintosh computer can be included in the inventory database as an object of the Personal Computer architecture. In a MIF file, an object is equivalent to a component block. A first-class object is one that is known directly to the API and does not require any additional information. For example, the system knows about architectures and platforms but cannot know about attributes without first knowing about an architecture and a group class.
Group
A structure for defining the distinct parts of an object. A group combines a set of attributes into a single identifiable entity. For example, Processor, Network, and Operating System are some of the groups that can exist on a computer with the Personal Computer architecture. In the Personal Computer architecture, groups can be used to store the properties of a hardware device (such as a COM port or mouse), a piece of software (such as the operating system or a defined software package), or any logical entity (such as asset or employee information through custom MIFs).

A group also has a class name that is used by SMS to uniquely identify a group. A class name is composed of the organization name (usually, the organization that defined the group), a name for the group, and the version number.

Attribute
A property of a group. Each attribute is assigned a value. The set of attribute values for a group makes up the inventory for the object. For example, a Disk group on a workstation has attributes such as Drive Index, Storage Type, Free Storage, and so on. In a computer's inventory, a Disk Drive Letter attribute can be assigned a value such as A, B, C, and so on.


How MIF Files are Used to Maintain Inventory in an SMS Database

To add or maintain items in an SMS database, the SMS system uses data in the Management Information Format (MIF). For example, computer inventory, events, package locations, job status, and user groups are all reported to the SMS database as MIF files.

This section provides the following topics:

  • Overview of the Inventory Collection Process
  • How Inventory History is Used to Maintain the SMS Inventory
  • Desktop Management Interface (DMI) Compatibility
  • How SMS Processes MIF Files

For additional information about the MIF format, refer to the Desktop Management Interface Specification version 4.5 (DMI45.DOC) provided in the \MSSDK\DOC subdirectory of the Microsoft® Platform SDK CD-ROM.


Overview of the Inventory Collection Process

When the Inventory Agent runs on a computer running SMS, it reports the inventory to an SMS logon server as a binary file. This file, called a RAW file, contains the computer's inventory in the MIF format. (For Macintosh and OS/2 computers, the Inventory Agent uses an ASCII text file to report inventory to an SMS logon server. Like the binary RAW file, the ASCII text file uses the MIF format to report a computer's inventory.) When the Inventory Processor processes a RAW file, it parses the RAW file (verifying the MIF syntax) and compares the inventory reported in the RAW file with the inventory history for the computer. The Inventory Processor then creates a Delta-MIF file that contains the groups whose inventories have changed (groups that have been added, updated, or deleted), and passes the file to the Inventory Data Loader. The Inventory Data Loader parses the Delta-MIF file and uses the data to update the SMS database.

Using the ASCII text files with the MIF format, you can also add, update, or delete custom objects and groups from the SMS database. You can add objects with new architectures (for example, printers or hardware routers) or add new types of objects of existing architectures (for example, a new computer to the Personal Computer architecture). When you add a new object to the SMS database, the MIF file containing the object's inventory must have an Architecture group and an Identification group. This is called an IDMIF. When you add a new group to an existing object, the MIF file containing the group(s) must not have an Architecture group or an Identification group. This is called a NOIDMIF.

The Architecture group is used to group related objects in the SMS database. The Identification group is used to identify an object. The specific properties of an object are reported as groups and attributes.

A group is identified by its class and keyed attributes. For a group class, each attribute's data type is set when that attribute is first reported to the SMS database. For example, when the Name attribute for the MICROSOFT|TOASTER|1.0 group is reported for the first time with a String(25) data type, any MIF files that report a group with class MICROSOFT|TOASTER|1.0 and the Name attribute must specify a string value that is 25 characters or less. If the value is a string longer than 25 characters, the value will be truncated to 25 characters when added to the SMS database. If the attribute has a different data type, the attribute will be considered invalid.

For custom objects and groups, you can also extend the SMS Administrator to display custom graphics for those objects and groups in the Sites window and Properties window of the SMS Administrator. If you want the new object to appear in the Sites window of the SMS Administrator, you must define seven specific attributes in the Identification group. For more information about extending the SMS Administrator's graphics, see Overriding and Extending Graphics in the SMS Administrator.


How Inventory History is Used to Maintain the SMS Inventory

For each computer running SMS, the Inventory Processor maintains a history file that contains the current inventory of that computer. These history files are placed in the SITE.SRV\INVENTRY.BOX\HISTORY directory of the site server.

Note For Microsoft® Windows NT®, Microsoft® Windows®, and Microsoft® MS-DOS® computers, the Inventory Processor gives each history file a unique name—usually, a file name with the computer's SMS identifier and the extension .HMS. For Novell NetWare servers, Macintosh workstations, and OS/2 computers, the HISTORY.MAP file maps each computer to its history file—these history files usually have unique file names and the extension .SMH. The HISTORY.MAP file is divided into sections according to architecture; each computer is listed by NetcardID, SMSID, and SMSLocation.

When the Inventory Processor processes a subsequent RAW file (or MIF file) from a computer, it compares the inventory reported in the RAW file (groups are identified by their class and keyed attributes) to the inventory reported in the computer's history file. If there are changes, the Inventory Processor creates a Delta-MIF file containing the groups whose inventories have changed (groups that have been added, updated, or deleted), and passes the file to the Inventory Data Loader. When the Inventory Data Loader detects a Delta-MIF file, it then adds, updates, or deletes the groups specified in the Delta-MIF file in the SMS database.

For example, the Operating System group has the class "MICROSOFT|OPERATING_SYSTEM|1.0" and uses the Operating System Name attribute as a key. When the Inventory Processor reads a group of this class in the RAW file, it looks for a group with the same class and an identical value for the Operating System Name attribute. If it found a RAW file that contained a group with this class and an Operating System Name of MS-DOS, the Inventory Processor would search the history file for a group with the same class and an Operating System Name of MS-DOS. The Inventory Processor would then use the data for the group in the RAW file to update the computer's history file and add the update information to a Delta-MIF file.

The Inventory Processor can add a PRAGMA statement to any group that it adds to the Delta-MIF file. A PRAGMA statement tells the Inventory Data Loader what to do with a group:

PRAGMA | Meaning
SMS:Add | Adds the group to the computer's inventory in the database.
SMS:Update | Updates the group in the database with the information in the Delta-MIF file.
SMS:Delete | Removes the group from the computer's inventory in the database.

For example, when the Inventory Processor detects that a group has been deleted, it reports the deletion by adding the group to the Delta-MIF file, using a PRAGMA="SMS:Delete" statement. If no PRAGMA is specified, the Inventory Data Loader will determine the PRAGMA. If the group exists in the database, the Inventory Processor performs an SMS:Update; if the group doesn't exist in the database, it performs an SMS:Add.

If there is no change to the computer's inventory (that is, the inventory in the history file matches the RAW file), the Inventory Processor does not report a Delta-MIF file. If a RAW file is processed later than four days after the last inventory report, and there is no change to the computer's inventory, the Inventory Processor will report a Delta-MIF file to update the computer's Workstation Status group.


Desktop Management Interface (DMI) Compatibility

In general, the SMS system can use any MIF file that complies with version 4.5 of the Desktop Management Interface (DMI) specification. However, SMS treats some aspects of the MIF syntax in a way that is unique to SMS. The full DMI 4.5 syntax is accepted by the SMS MIF parser; however, some fields are not used. For additional information about the MIF format, refer to the Desktop Management Interface Specification version 4.5 (DMI45.DOC) provided in the \MSSDK\DOC subdirectory of the Platform SDK CD-ROM.

This section includes the following information:

  • Differences between SMS and the DMI 4.5 Specification
  • Verifying the Syntax of a MIF File


Differences Between SMS and the DMI 4.5 Specification

Although SMS accepts the full DMI 4.5 syntax, the SMS MIF parser does not use some fields, and the SMS system may use the information in a way that differs from the DMI 4.5 specification.

ComponentID group is supported but not enforced.
DMI 4.5 requires this group; however, the SMS MIF parser does not enforce this requirement. The ComponentID group is checked for correct syntax only. If the group does not exist in the MIF file, the parser will not report an error.
Multiple Identification and Architecture groups are not allowed.
DMI 4.5 allows multiple Identification and Architecture groups within a component. SMS allows only one Identification group and one Architecture group within a component.
Some data types are simplified or merged.
DMI 4.5 has numerous data types: five types of integers, three types of strings, and one date type.

SMS handles these data types in the following manner:

  • All integer types (int, integer, int64, integer64, gauge, counter, and counter64) are treated as signed 32-bit values.

    Therefore, values exceeding 32 bits will not be correctly evaluated. Likewise, 32-bit unsigned values above 0x7FFFFFFF will be variously interpreted as unsigned 32-bit values or signed 32-bit values, depending on the context. However, the MIF parser will forward these values to other components as signed 32-bit integers.

  • All string types (displaystring, string, octetstring) are treated as the same type for database purposes.

    Because Microsoft® SQL Server™ places a limit of 255 characters on strings, any strings longer than 255 characters in the MIF will be truncated. However, there is no string length limitation in the syntax itself for attribute values. It is recommended that strings not exceed 255 characters in length, and that they not contain embedded NULL characters through an escape sequence.

  • Enumeration types are evaluated as the symbolic string and not as the integral value represented by the enumeration string.

    The enumeration string is preserved as a database item. Enumeration types take on the string type when the MIF has been parsed and evaluated. Enumeration types can be specified by using either the integer symbol or the enumeration string itself in all contexts where an attribute value is required.

These simplifications are for compatibility with SQL Server data types, and to compensate for the fact that the MIF is being compiled and transmitted to a remote database where the original hardware context of the MIF is lost. Also, there is no purpose served (for SMS inventory purposes) in distinguishing between some of these types. Finally, SQL Server supports a different set of types—so the SMS MIF compiler must map the DMI types to suitable SQL Server types, and the mapping is not necessarily on a one-to-one basis.

Unicode MIFs are detected but not supported.
DMI 4.5 allows Unicode MIFs. The SMS Inventory Processor will not process a Unicode MIF, and will report an error. The MIFCHECK utility will report that Unicode MIFs are not supported.
The Language statement is parsed but not used.
DMI 4.5 allows a Language statement that describes the language of the MIF. SMS parses the Language statement but does not use it for any purpose.
PRAGMA is a keyword for SMS.
DMI 4.5 does not specify PRAGMA as a keyword.

SMS uses the PRAGMA keyword to send commands between components. The PRAGMA statement can be used in a MIF group definition. The PRAGMA statement specifies a string that contains a command. The PRAGMA string is case-insensitive.

For example, the following PRAGMA statement tells the Inventory Processor and Inventory Dataloader components to update a group by using the information in the group definition specified in the MIF file:

PRAGMA = "SMS:Update"

If no PRAGMA is specified, the command is "Add" by default.
PRAGMA | Meaning
SMS:Add | Adds the group to the computer's inventory in the database.
SMS:Update | Updates the group in the database with the information in the Delta-MIF file.
SMS:Delete | Removes the group from the computer's inventory in the database.

Description statements are parsed but not used.
With DMI 4.5, you can use a Description statement to describe a component, group, or attribute. SMS parses Description statements but does not use them for any purpose.
The class string is converted to uppercase but not checked for internal format.
The class string is uppercased, but not checked for internal format, because this is not a strict requirement in the specification. The uppercasing is done to force all subsequent users of the CLASS string to treat it in a case-insensitive manner. Rather than relying on other components to do this, the parser uppercases the string, forcing the issue.
Path definitions are parsed but not used.
With DMI 4.5, you can use a Path statement to locate component instrumentation files. SMS parses Path statements but does not use them for any purpose.
Attributes that use instrumentation symbolic names are parsed but not used.
With DMI 4.5, you can use a Path statement to specify instrumentation symbolic names to specify paths to libraries that contain the actual value of an attribute. SMS parses attributes that use instrumentation symbolic names, but does not use them for any purpose.
The Unsupported keyword forces an attribute to be ignored in the SMS system.
With DMI 4.5, you can specify the keyword Unsupported to tell the DMI service layer that an attribute is not supported by a component.

For SMS, an Unsupported keyword applied to an attribute value causes that attribute to be specially marked. The MIF parser will retain the Unsupported tag; however, the SMS Inventory Processor will ignore such attributes, treating them as though they were not present in the MIF file.

The Access statement is parsed but not used.
DMI 4.5 lets you use an Access statement to specify the access to an attribute. SMS parses Access statements, but does not use them for any purpose. The Access statements have meaning only to the DMI service layer. However, the restrictions in the DMI specification on the correct or incorrect placement of these values with regard to enumerated types or key values are still enforced.
The Date data type has the following restrictions:
  • The value for an attribute with the Date data type must be represented using the full 25 octets required for the Date data type. You should pad values with zeros if necessary (for example, the month of May should be represented as 05, not 5). If a date field has no value, you should place zeros in that field.
  • For the Date data type, the microsecond field is ignored.
  • SMS will store dates only to the resolution of 1 second. The microsecond field will be ignored. However, you must still specify zeros in the microsecond field.
  • For the Date data type, the UTC offset is parsed and available for use by SMS components, but currently no SMS components use the UTC offset information.
  • An attribute cannot contain a date before 1980 or after 2030. Date attributes outside of this range will be considered errors by the SMS MIF parser.
  • The asterisk character (*) in a date field is replaced with the value for the current date in the corresponding field on the computer where the MIF parser is running.

    For example, if the current date is November 11, 1995, the value 1995**01130000.000000+000 would be processed as 1:00 P.M. November 1, 1995 (** is replaced by 11, the current month).

    With DMI 4.5, you can use asterisks to avoid specifying a part of a date. SMS requires that a date value be a complete date value because Microsoft SQL Server cannot store partial date values.

    An attribute that contains all asterisks will be considered a NULL or blank date in the SMS database.

  • For non-English versions of SMS, the MIF syntax and keywords must be in English, but the string data can be in the localized language of the client.
For the String data type, you should use escape characters for characters outside the standard ANSI range (32 through 127).
Literal (non-escape) characters embedded in quoted strings outside of the range 32 to 127 will be parsed and passed on to the rest of the system. These values may have different appearances, depending upon the active display font. Strictly speaking, for string types, you should restrict the characters to the ISO 8859-1 character set. However, the parser does not currently enforce this particular character set.
For the String data type, escape characters are fully interpreted.
All escape characters are fully interpreted as the correct 8-bit value.

You should be careful when using escape characters. For example, a NULL in the middle of a string "abc\0abc" causes SMS to interpret the string as having a length of only three characters. Although the parser supports a stream of bytes by this mechanism, SMS truncates the string when it detects an escape NULL.

Also note that how the escape character is stored in the SMS database depends on the character set used by the SQL Server containing the database. How the escape character is displayed depends on the code page used by the computer running the SMS Administrator.

For the String data type, the string length should be 255 characters or less.
DMI 4.5 has no limits on string length. For SMS, you should limit the string length to 255 characters or less. Because of the 255-character limit for SQL Server, the SMS Inventory Processor does not support string lengths longer than 255 characters. Any string that is longer than 255 characters will be truncated to the first 255 characters. The SMS MIF parser will not report an error if the declared string length exceeds 255 characters.
For the String data type, you should explicitly declare the string length.
Although the DMI does not require you to specify the string length of an attribute with a String data type, you should explicitly declare the length of all String data types for MIFs used with SMS.

If an attribute with a String data type does not have a declared string length, the SMS Inventory Processor will use the string length of the value that is specified for the first occurrence of the attribute. This string length will be used as the declared string length of the attribute. Any attributes of the same type will use the declared string length as the string length of the attribute.

If no string length is declared for an attribute, the Inventory Processor will use the following rules to set the string length (in the specified order):

  1. For an attribute with a String data type that does not explicitly specify the string length, the SMS MIF parser will set the maximum string length of the attribute to the length of the value specified for that attribute.

    The exception is any Name statement for a component, group, attribute, path, enum, or table. These statements have a maximum length of 255 characters.

    If the group containing this unsized attribute is part of a group template, then the length of the default string becomes the defining size, as if the string had been declared with a length of that value. So, if you declare no default string size and no default string value, this sets the maximum string length to zero in the table declarations.

  2. For Group templates and tables, if a default string length is specified, no initializer value in a table may exceed this length.

    If a string length is not declared, the default string value's length will be used implicitly as the maximum length, and any initializers in a table may not exceed this length.

  3. If no default value and no default initializer are specified in a Group template, the length is derived from the actual string length of the string initializer in the table row.
For groups and tables, the SMS MIF parser does not enforce the uniqueness of key attributes.
DMI 4.5 requires that the key attributes be unique. You should follow the DMI recommendations. If a key attribute is not unique, SMS will store only the last instance of the duplicated key attribute.


Verifying the Syntax of a MIF File

By using the MIFCHECK utility, you can check the syntax of a MIF file. The MIFCHECK utility runs the same MIF parser used by the SMS components. Because the same parsing engine is used by both the Inventory Processor and MIFCHECK, any MIF accepted by MIFCHECK will also be accepted by the SMS system. MIFCHECK verifies that the specified MIF files adhere to the syntax of the DMI Specification version 4.5—with the exceptions noted in the previous section.

The MIFCHECK utility is provided on the Microsoft Systems Management Server CD-ROM in the platform subdirectory for the processor type of your computer in the \PSSTOOLS directory (for example, the \PSSTOOLS\X86 directory if you want to run MIFCHECK on a computer with an x86 processor).


How SMS Processes MIF Files

This section describes how SMS processes MIF files. The process varies depending upon the network operating system (Windows NT, Microsoft® LAN Manager, NetWare, or Macintosh), and whether the inventory reported in the MIF file is standard or custom:

  • Standard Inventory Collection Process
  • Custom Inventory Collection Process


Standard Inventory Collection Process

When a client computer logs on to a domain that is part of a site, the Inventory Agent program runs at the client and scans the client for software and hardware. There are four variations of the Inventory Agent program for clients: INVDOS, INVWIN32, INVOS2, and INVMac.

The Inventory Agent program reports the inventory for the client by creating a RAW Inventory Agent file (*.RAW) in Management Information Format (MIF) and placing this file in the INVENTRY.BOX directory of the SMS_SHR share on the client's logon server. For NetWare servers, the file is placed in the LOGON.SRV\INVENTRY.BOX directory under the SMS root directory. Note that OS/2 and Macintosh clients write *.MIF files instead of *.RAW files. The *.MIF files are written to the LOGON.SRV\ISVMIF.BOX directory.

At the site server, the Maintenance Manager service monitors the LOGON.SRV\INVENTRY.BOX directories of the SMS_SHR share on all logon servers at the site. The Maintenance Manager collects the client inventory files (*.RAW files) from these directories on the logon servers, and places them in the SITE.SRV\INVENTRY.BOX directory on the site server. Inventory history files are maintained in the SITE.SRV\INVENTRY.BOX\HISTORY directory. If NetWare servers are present, the Maintenance Manager polls the INVENTRY.BOX directory on these servers for inventory information.

The Inventory Processor processes the client inventory files (*.RAW and *.MIF) and places the processed files (*.MIF) in the SITE.SRV\DATALOAD.BOX\DELTAMIF.COL directory on the site server. These processed files are called inventory Delta-MIFs.

The Inventory Data Loader processes the Delta-MIFs and updates the site database with inventory reported by the clients. Note that the Inventory Data Loader copies all Delta-MIFs that cannot be processed by the database into a \BADFILES subdirectory.

After the site database update, you can view the updates to the computer inventory by using the SMS Administrator.

The standard inventory collection process is illustrated below:

Notes On servers running Windows NT Server and LAN Manager, the Inventory Agent is installed as a service. The Inventory Agent service wakes up every 24 hours to check its inventory scan interval (the inventory scan interval for hardware and software is set in the Inventory dialog box from the Site Properties dialog box). If the interval has expired, the Inventory Agent scans for inventory.

The Inventory Agent for Windows NT Server reports inventory in the same manner as clients running Windows NT Workstation and LAN Manager. The Inventory Agent for OS/2 service reports inventory in the same manner as OS/2 clients. On servers running NetWare, the Maintenance Manager on the site server scans the NetWare server and reports inventory as a text MIF to the site server's SITE.SRV\INVENTRY.BOX directory, where the MIF is processed by the Inventory Processor.

For LAN Manager clients, the Inventory Agent (INVDOS) is run by means of the SMSLS batch file logon script. NetWare clients execute the same Inventory Agent program, but instead of an SMSLS batch file logon script, commands execute from a system login script. NetWare clients can also connect to a NetWare server and run INVDOS manually from the LOGON.SRV\X86.BIN directory.

Collecting Inventory from Macintosh Clients

To initiate inventory collection for the first time, a user at a Macintosh client must connect manually to a Windows NT Server Services for Macintosh logon server and run the Installer program. After that, inventory collection is automatic.

The user runs the Installer by using the Chooser to connect to the logon server, and locating the MAC.BIN folder. When the user opens the Installer within the Macintosh folder, SMS files, including the INVMac program, are copied to the client. INVMac is copied to the System Folder:Startup Items. When the Installer is finished it will require the Macintosh to be restarted. At restart, INVMac runs automatically because it is a startup item.

When INVMac runs, it creates a local SMS.INI file as well as two files that store the hardware and software inventory history: InvHWScanResult and InvSWScanResult. INVMac also launches the Package Command Manager (PCMMac).

INVMac puts inventory results in the LOGON.SRV\ISVMIF.BOX directory on the logon server as a *.MIF file. The Maintenance Manager moves the MIFs from the Services for Macintosh logon server to the SITE.SRV\ISVMIF.BOX directory on the site server. The Inventory Processor processes these files, and places them in the SITE.SRV\DATALOAD.BOX\DELTAMIF.COL directory.

At a primary site, the Inventory Processor processes these files into Delta-MIFs, and places them in the SITE.SRV\DATALOAD.BOX\DELTAMIF.COL directory. The Inventory Data Loader uses the Delta-MIFs to update the computer inventory in the site database and places the MIFs in the SITE.SRV\SITEREP.BOX directory for the Site Reporter to forward the MIFs to the site's parent site.

At a secondary site, the Inventory Processor processes these files into Delta-MIFs and places them in the SITE.SRV\SITEREP.BOX directory for the Site Reporter to forward the MIFs to the site's parent site.

Collected files are placed in the *.CFD directory on the Services for Macintosh logon server. (If there are no collected files, this directory does not exist.) Inside the directory are files of the form *.FIL collected from the Macintosh client and one cataloging file, COLLFILE.LST. COLLFILE.LST is an ASCII file relating the files' 0000000x.FIL to the path on the Macintosh client.

Collecting Inventory from OS/2 Computers

When the Inventory Agent for OS/2 service runs on LAN Manager version 2.x servers and the Inventory Agent program runs on OS/2 client computers, the Inventory Agent scans for hardware and software inventory. However, the Inventory Agent for OS/2 does not report inventory as a RAW file in the LOGON.SRV\INVENTRY.BOX directory. Instead, it creates text MIFs and places them in the LOGON.SRV\ISVMIF.BOX directory on the logon server. The Maintenance Manager moves the MIFs from the logon server to the SITE.SRV\ISVMIF.BOX directory on the site server.

At a primary site, the Inventory Processor processes these files into Delta-MIFs, and places them in the SITE.SRV\DATALOAD.BOX\DELTAMIF.COL directory. The Inventory Data Loader uses the Delta-MIFs to update the computer inventory in the site database and places the MIFs in the SITE.SRV\SITEREP.BOX directory for the Site Reporter to forward the MIFs to the site's parent site.

At a secondary site, the Inventory Processor processes these files into Delta-MIFs and places them in the SITE.SRV\SITEREP.BOX directory for the Site Reporter to forward the MIFs to the site's parent site.


Custom Inventory Collection Process

There are two types of MIF files for reporting customized client and server inventory: IDMIFs and NOIDMIFs. IDMIFs, used for adding custom architectures to the inventory, contain Identification and Architecture groups. NOIDMIFs are generally used for adding new groups to the inventory of a workstation already existing in the SMS database; these contain no Identification or Architecture groups.

For extensive information on customizing your inventory, refer to Adding Objects with Custom Architectures to the Inventory.

Collecting IDMIFs

If the Inventory Agent detects an IDMIF in the C:\MS\SMS\IDMIFS directory on a Windows NT or MS-DOS system, it appends the *.MIF file to the *.RAW file it created as part of regular inventory collection. The Inventory Processor then extracts the *.MIF information from the *.RAW file and uses it to create Delta-MIFs in the SITE.SRV\DATALOAD.BOX\DELTAMIF.COL directory.

If the Inventory Agent detects an IDMIF on an OS/2 or Macintosh client (IDMIFs will be in the C:\MS\SMS\IDMIFS on an OS/2 client, and in an SMS\IDMIF directory created by the user on a Macintosh client), it moves the file to the \ISVMIF directory on the appropriate logon server. The SMS Maintenance Manager moves client (and server) *.MIF files found in this directory to the SITE.SVR\ISVMIF.BOX directory on the site server where they are processed by the SMS Inventory Processor and written to the SITE.SRV\DATALOAD.BOX\DELTAMIF.COL directory as Delta-MIFs. (Note that the Inventory Agent programs for OS/2 and Macintosh computers write *.MIF files to the LOGON.SRV\ISVMIF.BOX directory as part of the standard inventory process.)

Collecting NOIDMIFs

NOIDMIFs are placed in the MS\SMS\NOIDMIFS directory on SMS clients. For example, when a client user enters a form by using the MIF Entry tool, a *.MIF file is put in the directory that is specified by the MachineISVMIFPath entry in the client's SMS.INI file. By default, MachineISVMIFPath is the MS\SMS\NOIDMIFS directory. The next time the Inventory Agent program scans for software on Windows NT or MS-DOS clients, it appends the information to the inventory *.RAW file. If the client is an OS/2 or Macintosh client, the Inventory Agent copies the MIF to the client's logon server (in LOGON.SRV\ISVMIF.BOX). The groups defined by the MIFs are then added to the SMS system database.

NOIDMIFs can exist only on clients, except in one case: a user can place a NOIDMIF with a *.NIM suffix in the ISVMIF.BOX directory on a NetWare logon server in order to extend inventory for that server. The Maintenance Manager processes the file, which includes appending the NetWare server's Architecture and Identification group to it, and writes it to the DELTAMIF.COL directory as a Delta-MIF.

The Inventory Processor creates inventory history files for IDMIFs and NOIDMIFs and places them in the SITE.SRV\INVENTRY.BOX\HISTORY directory. Note that history is not created if a user copies an IDMIF with an *.NHM extension to the LOGON.SRV\ISVMIF.BOX directory. Additionally, *.NIM files do not have history.

The custom inventory collection process is illustrated in the following figure:


Adding Objects with Custom Architectures to the Inventory

You can extend the inventory beyond the architectures already defined in the SMS system by adding objects with new (custom) architectures. A custom architecture can store information about objects that have little or no relationship to the predefined SMS architectures.

To add an object with a custom architecture to the inventory, you use a MIF file. A MIF file is an ASCII text file that contains information using the Desktop Management Task Force (DMTF) Management Information Format (MIF). In the MIF file you include the properties of the object and define the structure of the architecture. The structure of the architecture is defined by the attributes you include in the Identification and Architecture groups, and by the other groups and attributes that you choose to include in the MIF file.

Depending on how you define a custom architecture, objects with custom architectures can be displayed by using a query or the Sites window of the SMS Administrator. If you want to display an object with a custom architecture in the Sites window, the object's Identification group must include the Name, Site, Domain, SystemRole, and SystemType attributes, and the values for the Site and Domain attributes must be those of existing sites and domains in the SMS database. Otherwise, you can display the object only by creating and executing a query. Refer to Viewing the Objects for a Custom Architecture.

To add an object with a custom architecture to the inventory
  1. Create a MIF file that contains the inventory information for the object.
  2. Run the MIFCHECK utility on the MIF file. Refer to Verifying the Syntax of a MIF File.
  3. At the site where you want to add the object, place the MIF file in the C:\MS\SMS\IDMIFS subdirectory on an inventory collection point.
  4. If the architecture is new to an SMS site database, and the SMS Administrator is connected to that site database, restart the SMS Administrator to enable access to the new architecture.

This section provides the following topics to help guide you through this process:

  • Creating a MIF File to Add an Object
  • Placing the MIF File on an Inventory Collection Point
  • Restarting the SMS Administrator
  • Viewing the Objects for a Custom Architecture
  • Maintaining Objects from a Custom Architecture
  • Removing Objects


Creating a MIF File to Add an Object

When creating a MIF file to add or update an object with a custom architecture, observe the following rules:

  • The full definition for the object starts with the keyword Start Component and ends with End Component. You should define only one object (component) per MIF file.
  • The object definition begins with the Name entry for the object.
  • The Identification and Architecture groups must be included in the MIF file, using the structure you defined for the architecture.
  • The Class values for the Identification and Architecture groups should be microsoft|identification|1.0 and microsoft|architecture|1.0, respectively.
  • If you want the object to appear in the Sites window of the SMS Administrator, you must include the Name, Site, Domain, SystemRole, and SystemType attributes in the Identification group; and the values for the Site and Domain attributes must be those of sites and domains existing in the SMS database.
  • The group and attribute identifier values must be 1 or greater.
  • The attributes for an object must be specified in groups that adhere to the structure you defined for the architecture.

Important When updating inventory information for an object already existing in the SMS database, make sure to specify values for all of the attributes defined in the previous MIF file for that object; otherwise the values for those attributes will be set to NULL.

To assist you in creating MIF files for objects with custom architectures, this section provides the following information:

  • Example MIF File for an Object with a Custom Architecture
  • MIF File Syntax for Custom Architectures
  • Displaying an Architecture's Objects in the Sites Window


Example MIF File for Object with a Custom Architecture

Example MIF File for an Object with a Custom Architecture

The following MIF file adds an object with a custom architecture called "Employee" to the SMS database. The group types are Identification, Architecture, Employee Status, Location, and Position.

Start Component
    Name = "EMPLOYEE"
    Start Group
        Name = "Identification"
        ID = 1
        Class = "MICROSOFT|IDENTIFICATION|1.0"
        Start Attribute
            Name = "Site"
            ID = 1
            Access = READ-ONLY
            Storage = COMMON
            Type = String(3)
            Value = "ULF"
        End Attribute
        Start Attribute
            Name = "Domain"
            ID = 2
            Access = READ-ONLY
            Storage = COMMON
            Type = String(16)
            Value = "NESSI_DOM"
        End Attribute
        Start Attribute
            Name = "SystemType"
            ID = 3
            Access = READ-ONLY
            Storage = COMMON
            Type = String(50)
            Value = "Person"
        End Attribute
        Start Attribute
            Name = "SystemRole"
            ID = 4
            Access = READ-ONLY
            Storage = COMMON
            Type = String(50)
            Value = "Writer"
        End Attribute
        Start Attribute
            Name = "Name"
            ID = 5
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(64)
            Value = "Sue Turner"
        End Attribute
        Start Attribute
            Name = "Project"
            ID = 6
            Access = READ-ONLY
            Storage = COMMON
            Type = String(32)
            Value = "SMS"
        End Attribute
        Start Attribute
            Name = "Company"
            ID = 7
            Access = READ-ONLY
            Storage = COMMON
            Type = String(32)
            Value = "Microsoft"
        End Attribute
    End Group
    Start Group
        Name = "Architecture"
        ID = 2
        Class = "MICROSOFT|ARCHITECTURE|1.0"
        Start Attribute
            Name = "ArchitectureName"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(10)
            Value = "Employee"
        End Attribute
    End Group
    Start Group
        Name = "Employee Status"
        ID = 3
        Class = "MICROSOFT|EMPLOYEE STATUS|1.0"
        Start Attribute
            Name = "Hours Worked"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = Counter
            Value = 500
        End Attribute
        Start Attribute
            Name = "Done?"
            ID = 2
            Access = READ-ONLY
            Storage = COMMON
            Type = String(40)
            Value = "No"
        End Attribute
    End Group
    Start Group
        Name = "Location"
        ID = 4
        Class = "MICROSOFT|LOCATION|1.0"
        Start Attribute
            Name = "Building"
            ID = 1
            Access = READ-ONLY
            Storage = COMMON
            Type = String(40)
            Value = "26s"
        End Attribute
        Start Attribute
            Name = "Office Number"
            ID = 2
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(40)
            Value = "667"
        End Attribute
        Start Attribute
            Name = "Phone"
            ID = 3
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(40)
            Value = "M"
        End Attribute
    End Group
    Start Group
        Name = "Position"
        ID = 5
        Class = "MICROSOFT|POSITION|1.0"
        Start Attribute
            Name = "Title"
            ID = 1
            Access = READ-ONLY
            Storage = COMMON
            Type = String(40)
            Value = "Technical Writer"
        End Attribute
        Start Attribute
            Name = "Level"
            ID = 2
            Access = READ-ONLY
            Storage = COMMON
            Type = Integer
            Value = 2
        End Attribute
    End Group
End Component

The figure below shows how the object defined by the example MIF file is displayed in the SMS Administrator.

This is how the object's properties are displayed:


MIF File Syntax for Custom Architectures

In the MIF file, an object must have one Component section, an Identification group, an Architecture group, and optionally any additional groups that contain attributes describing the object.

For each attribute, follow a standard format that uses the same spelling for the attribute name, the same data type, and the same access entries.

When you create a MIF file to add an object with a custom architecture, you must ensure that the MIF file follows the DMI Specification version 4.5. See Desktop Management Interface (DMI) Compatibility


Displaying an Architecture's Objects in the Sites Window

Depending on how you define a custom architecture, you can choose whether to display custom architectures in the Sites window.

To create an object that is displayed in the Sites window, the object's architecture must have an Identification group with the following five attributes defined:

Site
The site containing the object.
Domain
The domain containing the object.
Name
The name used to identify the object.
SystemType
The type of object.
SystemRole
The role the object has in the SMS system.

An object with these attributes defined is displayed in the Sites window within the specified Site and Domain.

If a custom architecture does not have these attributes defined, its objects are not displayed in the Sites window; you must display these objects by using a query.

Object Syntax

An SMS object is a specific item that uses a specific architecture. For example, the SMS system uses the Personal Computer architecture to inventory computers as objects. An object contains groups. For SMS, an object must have an Identification group and an Architecture group.

An object definition within a MIF file starts with the line Start Component and ends with the line End Component. Within an object definition, you should have the following entry:

Name
A string (enclosed by quotation marks) that labels the object.

Example of an object:

Start Component
    Name = "EMPLOYEE"
    Start Group
        Name = "Architecture"
        ID = 1
        Class = "MICROSOFT|ARCHITECTURE|1.0"
        Start Attribute
            Name = "ArchitectureName"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(10)
            Value = "Employee"
        End Attribute
    End Group
    Start Group
        Name = "Identification"
        ID = 2
        Class = "MICROSOFT|IDENTIFICATION|1.0"
        Start Attribute
            Name = "Employee Name"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(32)
            Value = "Mitch Duncan"
        End Attribute
    End Group
End Component

Group Syntax

A group is a set of one or more attributes. When the inventory for an object is displayed in the object's Properties window, all the groups for the object are displayed in the left pane. The attributes for the selected group are displayed in the right pane.

Objects (called Components in the DMTF structure) for every architecture must have an Identification group and an Architecture group.

A group starts with the line Start Group and ends with the line End Group. Within the group, specify the following entries:

Name
A string (enclosed by quotation marks) that labels the group. When the group is displayed in the Properties window, this string is used to label the group in the left pane.
ID
A number that identifies the group. The ID must be unique for each group within the object. The ID is an integer value. Group IDs must be 1 or greater.
Key
Applies only to multiple-instance groups. For example, an object such as a disk drive can have multiple instances on a computer. One or more keys are used to differentiate the instances. For example, the Disk Drive group has a key defined for the Drive Letter attribute. The key entry specifies one or more identifiers for the attributes used to uniquely identify an instance of a group. If you have multiple keys, you must separate them with commas. If a group can have only a single instance, then no key should be defined.
Class
A required string describing the source of the group definition.

A group also contains one or more attributes.

Example of a group:

    Start Group
        Name = "Employee Name"
        ID = 1
        Class = MICROSOFT|EMPLOYEE NAME|1.0
        Start Attribute
            Name = "Last Name"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(32)
            Value = "Smith"
        End Attribute
        Start Attribute
            Name = "First Name"
            ID = 2
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(32)
            Value = "John"
        End Attribute
    End Group

Identification Group Syntax

Objects for every architecture must have an Identification group. The Identification group can have any number of attributes. However, you should ensure that all attributes are included in all objects that are part of a single custom architecture.

    Start Group
        Name = "Identification"
        ID = 1
        Class = "MICROSOFT|IDENTIFICATION|1.0"
        Start Attribute
            Name = "Employee Name"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(32)
            Value = "Mitch Duncan"
        End Attribute
    End Group

Architecture Group Syntax

Objects for every architecture must also have an Architecture group. The Architecture group contains one attribute. The value of the ArchitectureName attribute should be the label you want to display for the architecture in the SMS Administrator. For example, when you view an object with a custom architecture, the ArchitectureName attribute is displayed in the Properties window title bar.

    Start Group
        Name = "Architecture"
        ID = 1
        Class = "MICROSOFT|ARCHITECTURE|1.0"
        Start Attribute
            Name = "ArchitectureName"
            ID = 0
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = String(10)
            Value = "Employee"
        End Attribute
    End Group

Attribute Syntax

When the inventory for an object is displayed in the object's Properties window, all the groups for the object are displayed in the left pane. The attributes for the selected group are displayed in the right pane.

An attribute starts with the line Start Attribute and ends with the line End Attribute. Within the attribute, you should have the following entries:

Name
A string (enclosed by quotation marks) that labels the attribute. When the attribute is displayed in the Properties window, this string is used to label the attribute in the right pane.
ID
A number that identifies the attribute. The ID must be unique for each attribute within the group. The ID is an integer value.
Access
Determines the access type of the table where the attribute will be stored. Values can be READ-ONLY, READ-WRITE, and WRITE-ONLY. The Access statement is optional and defaults to READ-ONLY.
Storage
Assists management applications to optimize storage requirements. Values can be common or specific. The Storage statement is optional.
Type
The data type used to store the value of the attribute. There are two data types. Counter is an integer. String is a character string. For strings you must specify the maximum length for the string.

The SQL Server database has a limit of 255 characters for any attribute value. Any string longer than 255 characters will be truncated. In addition, any values longer than the originally defined length will be silently truncated. For example, if the attribute "Employee Name" is defined as "string(40)", SMS will add only the first 40 characters for an "Employee Name" value that is longer than 40 characters.

The SMS system uses the first definition of Type. For example, if you first defined "Employee Name" as "string(40)", the SMS system will always use that type. You cannot change the Type value after you have first defined it.

Value
The value assigned to the attribute. The value must be in the form specified by the Type entry. Strings must be enclosed within quotation marks. Counters must be decimal integers. The Value statement is optional.

Example of an attribute:

        Start Attribute
            Name = "Hours Worked"
            ID = 1
            Access = READ-ONLY
            Storage = SPECIFIC
            Type = Counter
            Value = 500
        End Attribute


Placing the MIF File on an Inventory Collection Point

To add an object to the inventory, you place its MIF file at an inventory collection point for the site where you want to add the object. The object will be added to the inventories of all sites up to the Central Site.

You can place the MIF file at either of the following collection points:

  • An ISV collection directory at one of the site's logon servers. By default, this directory is the \ISVMIF.BOX subdirectory of the SMS_SHR share on an SMS logon server.
  • A stand-alone MIF collection directory on an SMS workstation at the site. The location of this directory is specified by the StandaloneISVMIFPath entry in the [SMS] section of the workstation's SMS.INI file. By default, this directory is C:\MS\SMS\IDMIFS.

The share name and path for these collection points were specified when you first installed the site.

The SMS system detects the MIF file at inventory collection points. Using the information in the MIF file, the SMS system adds the object to the SMS system databases of the site containing the collection point and all of its parent sites.


Restarting the SMS Administrator

To update the SMS Administrator with new custom architectures, you must exit the SMS Administrator and restart it.


Viewing the Objects for a Custom Architecture

Depending on how you define a custom architecture, objects with custom architectures can be displayed by using a query or the Sites window of the SMS Administrator. If you want to display an object with a custom architecture in the Sites window, the object's Identification group must include the Name, Site, Domain, SystemRole, and SystemType attributes, and the values for the Site and Domain attributes must be those of existing sites and domains in the SMS database. Otherwise, you can display the object only by creating and executing a query.

For more information about creating and executing queries, see the "Queries" chapter in the Microsoft Systems Management Server for Windows NT Administrator's Guide.

To view all the objects for a custom architecture
  1. Create a query for the architecture and leave the Find All Machines Where box blank (this includes all objects).
  2. Define a query format for the new architecture.
  3. Execute the query (using the Query command from the File menu). Specify the query and query formats you defined for the architecture, and leave the Start After box blank.

As with the standard architectures provided with SMS (Personal Computer, Event, and so on), you can also create queries to find objects that meet a specified set of criteria. Make sure that you specify the custom architecture name in the Architecture box when you create the query.

To view the inventory for an object with a custom architecture
  1. Execute a query that displays the object that has the custom architecture.
  2. From the query's Query Results window, double-click the object.

    A properties window appears (the title bar displays the object's architecture name). The object's groups are displayed in the left pane. The attributes for the selected group are displayed in the right pane.

    To view the attributes for a group, select the group's icon from the left pane. The right pane displays the attributes of the group. If the object has multiple instances of a group, the right pane displays a table of all groups of the selected group type. In the figure below, the Macintosh Printer object has five instances of the Font group.

You can also view the inventory history for an object that has a custom architecture. The inventory history for an object with a custom architecture is maintained in the same way as the inventory for a computer. For more information about viewing the inventory history of a computer, see How Inventory History is Used to Maintain the SMS Inventory.


Maintaining Objects from a Custom Architecture

To maintain the properties of objects from a custom architecture, you make changes directly to the object's MIF file. The SMS Inventory Agent program detects the changes when it reads the MIF file, and the SMS system updates the object's inventory in the database.

Note When making changes to a MIF file, make sure to specify values for all of the attributes defined in the previous MIF file; otherwise the values for those attributes not specified will be set to NULL.


Removing Objects

If objects are selected in either the SMS Administrator Sites window or the Query Results window, you can use the Delete menu item (from the Edit menu) to remove them from the database; however, this simply moves the objects to history, where they remain. Note that history for a deleted object cannot be viewed from the SMS Administrator.

With the Delete Special menu item (also under the Edit menu), you can group and delete objects according to criteria you define in the Delete Special dialog box fields. For example, you can group objects by their last activity date, deleting all objects that were added to the inventory on or before that specific date. You can also group and delete history records.

You can also use the SMS Database Manager (DBCLEAN.EXE) to delete items from the SMS database. Use the Delete Duplicates menu to delete entries for computers that are the same, but have different SMSID numbers. Under the Tools menu, you can use Delete Group Classes and Delete Unused Common/Specific Records.

Important Be careful when deleting groups. For example, it is important not to delete a predefined group such as the Identification group. This will cause a failure of all SMS processes (such as jobs, alerts, and running queries) that require the information contained in the predefined group.

Before you use the SMS Database Manager, make sure that there are no other administrators using the SMS Administrator to access that database.

The SMS Database Manager (DBCLEAN.EXE) is installed in the SITE.SRV\platform.BIN directory (where platform is the processor type of the computer where it is installed) on any computer where the SMS Administrator is installed.


Adding New Groups to Objects Already Existing in the SMS Inventory

You can use a Management Information Format (MIF) file to add new hardware or software groups to the inventory of a workstation. For example, you can add a tape backup unit or CD-ROM changer to the inventory of a workstation that already exists in the SMS database.

To add a new group to a workstation's inventory
  1. Create a MIF file containing the group you want to add. See the sample below.

    Important The MIF file must not have an Identification or Architecture group. If you include either of these groups, you may corrupt the inventory stored in the database for the workstation. The MIF file should have a component section with one or more groups within the component section. Also, make sure to specify values for all of the attributes defined in the previous MIF file for this object; otherwise the values for those attributes are set to NULL.

  2. Run the MIFCHECK utility on the MIF file. Refer to Verifying the Syntax of a MIF File.
  3. Place the MIF file in the MIF collection directory of the workstation to which you are adding the group.

    The location of this directory is specified by the MachineISVMIFPath entry in the [SMS] section of the workstation's SMS.INI file. By default, this directory is C:\MS\SMS\NOIDMIFS. From the machine MIF directory, the SMS Inventory Agent program detects MIF files and includes their information in the workstation's inventory.

Example of a MIF file for adding a group to a workstation's inventory:

Start Component
    Name = "TAPE BACKUP DEVICE"
    Start Group
        Name = "Tape Drive"
        ID = 1
        Class = "MICROSOFT|TAPEDRIVE|1.0"
        Start Attribute
            Name = "Manufacturer"
            ID = 1
            Type = String(32)
            Value = "Trey Research"
        End Attribute
        Start Attribute
            Name = "Model"
            ID = 2
            Type = String(32)
            Value = "MS32-DLX"
        End Attribute
        Start Attribute
            Name = "Native Transfer Rate (Kbps)"
            ID = 3
            Type = Counter
            Value = 400
        End Attribute
        Start Attribute
            Name = "Tape Type"
            ID = 4
            Type = String(16)
            Value = "DAT"
        End Attribute
    End Group
End Component

In the workstation's Personal Computer Properties window, the Tape Backup Device Group is displayed as an icon in the left pane with its attributes in the right pane.


Creating Forms to Generate MIF Files

The SMS MIF Form Generator and the SMS MIF Entry utility let users at SMS clients add new groups to their computers' inventories.

For example, you can use the SMS MIF Form Generator to create a form for an Employee Information group that stores user information such as full name, location, room number, phone number, employee identifier, division, and so on.

You can distribute the form to SMS clients by sending a Run Command On Workstation job. At the SMS clients, users complete the forms by using the MIF Entry utility. The SMS system then collects the MIF files generated by the users who completed the forms, adding the groups included in the MIF files to the inventory of the users' computers in the site database. The new groups can then be viewed in the Personal Computer Properties – [computername] window for each client that reported new groups to the inventory.

The MIF form sets up the structure of the group: the group name, its class, and its attributes. It lets you set default values and add instructions for filling in each attribute. You can also modify the default form, UINFO.XNF. You can find this form on the site server in the following path:

SMS\SITE.SRV\MAINCFG.BOX\CLIENT.SRC\X86.BIN

Note On a MIPS computer, UINFO.XNF is in the following path:

SITE.SRV\MAINCFG.BOX\CLIENT.SRC\MIPS.BIN

On an Alpha computer, UINFO.XNF is in the following path:

SITE.SRV\MAINCFG.BOX\CLIENT.SRC\ALPHA.BIN

For extensive information on and procedures for using the SMS MIF Form Generator and MIF Entry utility, refer to the "Customizing the Computer Inventory" appendix in the Microsoft Systems Management Server for Windows NT Administrator's Guide.


Microsoft SMS API

The Systems Management Server API provides a C language interface that enables your application to retrieve, add, and remove data in the SMS database.

  • System Requirements
  • Installing the SMS API Components
  • SMS API Overview
  • SMS API Container Hierarchy
  • SMS API Functions
  • Return Codes for the SMS API Functions
  • Container Types
  • Folder Types
  • Filter Types
  • Structures
  • Manifest Constants
  • Sample Applications for the SMS API
  • Using the SMS API with Visual Basic


System Requirements

To build and run applications that use the SMS API, your computer must meet the following requirements:

  • Microsoft Windows NT version 3.5 and later.
  • Systems Management Server version 1.1 and later.

Note that applications using the SMS API are compatible with primary site databases for SMS version 1.1 and later. Sites running SMS version 1.0 are not supported.

For information about requirements for running applications using the SMS API, see Installing Your Application.

For information about installing the SMS API components, see Installing the SMS API Components.


Installing the SMS API Components

To use the SMS API, you need the following libraries and header files:

Dynamic-Link Libraries
The following DLLs are required for running an application that uses the SMS API:
SMSAPI.DLL
DLL for the SMS API user functions.
OBJECTTY.DLL
DLL for the SMS API engine.

You must make sure that your application uses the correct version of the DLLs. Applications compiled for a particular version of the DLLs may not run with earlier versions. Additionally, the DLLs are matched to a particular minor version of the SMS base DLLs and will only run with that version of SMS. See DLL Version Checking for ISV Application Installation for details.

A version of both the SMS 1.1 and 1.2 SDK DLLs ship with this SDK. The SMS 1.2 SDK DLLs are located in the BIN or BIN\platform directory, where platform is the processor type of the computer—i386, Alpha, or MIPS. The SMS 1.1 SDK DLLs are located in a SMS 1.1 directory under BIN or BIN\platform.

Static Libraries
The following static libraries are required for building an application that uses the SMS API:
SMSAPI.LIB
Static library for the SMS API user functions.
OBJECTTY.LIB
Static library for the SMS API engine.

The specific libraries for the platform of your computer are located in the \MSSDK\LIB\platform directory of the Microsoft® Platform SDK CD-ROM, where platform is the processor type of the computer—i386, Alpha, or MIPS.

Header Files
The following header files are required for building an application that uses the SMS API:
SMSAPI.H
Header file for SMS API user functions.
OBJECTTY.H
Header file for SMS API engine functions.
QRYCODES.H
Header file containing relational operators for filters.
SMSINFO.H
Header file for manifest constants for SMS objects.

The header files are located in the \MSSDK\INCLUDE directory of the Platform SDK CD-ROM.


SMS API Overview

In an SMS system, a primary site's site database stores the inventory and configuration information for itself and the sites below it in the site hierarchy. Using the SMS API, your application can access the information in a site database.

The SMS API enables your application to retrieve, add, and remove data in the SMS database. Using the SMS API, you can access the following objects in an SMS database:

  • Sites
  • Inventoried objects
  • Packages
  • Jobs
  • Queries
  • Machine groups
  • Site groups

The SMS API represents all SMS objects in terms of containers, folders, and scalars. This paradigm provides a standard interface to all types of objects.

Containers hold objects of a specific type. For example, the C_SITE container can contain sites.

Within a container, the instance of an object is represented as a folder. For example, a C_SITE container can contain a set of folders that represent the current site (the site whose SMS database your application is accessing) or sites below the current site in the site hierarchy.

A folder contains scalars, subfolders, or both. A scalar is the value stored for an attribute of a folder. In addition to a value, each scalar also contains a name, a data type, and an access mode. For example, the folder for a site contains scalars for site name, parent site, depth, status, and site type. The folder for a specific site would have a specific value for each scalar. For example, the folder for the TIM site could contain the string "Tim World" for site name.

Note that an inventory rules folder (which can be a subfolder within a package folder) contains a single scalar along with one or more tokens that represent the set of files used to identify a package.

Because some objects themselves can contain multiple components, a folder can also contain subfolders. For example, a site folder can contain subfolders for the domains in the site and any subsites below that site in the site hierarchy.

To access objects in the site database, you must open a container for the type of object you need to access. When you first open a container, it contains no folders. To retrieve objects from the site database, you must populate the container with objects from a site database. The objects are represented as folders in the container. After the container has been populated, you can access the folders and their properties.

Filters can also be set on a container. Filters define the criteria used to select the objects you want to find. If no filter is set for a container, all objects (that is, all objects of the type supported by the container) are returned when the container is populated. There are eight types of filters available. The types of filters that you can set are dependent on the container. For example, filters of type ARCHITECTURE_FILTER, MACHINE_FILTER, GROUP_FILTER, and ATTRIBUTE_FILTER can be set on a machine container.

Your application can configure a filter by adding tokens to the filter. A token lets you specify a condition used to select the objects you want to find. Within a filter, tokens can be connected together using AND or OR operators. For example, a token can be added to the ARCHITECTURE_FILTER of a machine container to find objects that have the Personal Computer architecture.

Note that inventory rules folders use tokens in the same way that filters do—except that each token contains the file name and file attributes used to identify a file.

In addition, filters of type MACHINE_FILTER can be added to the site database by using a filter container. MACHINE_FILTER filters are added as queries in the site database. Your application can also retrieve queries stored in the site database by opening a filter container. When the filter container is opened, it is populated with the queries stored in the site database. These queries are represented as persistent filters in the filter container. Currently, the SMS API does not support deletion of persistent filters from the site database.

The following list shows the hierarchy of the containers and folders supported by the SMS API. Click an item to display details about the object.

Site container
Site folder (Read-only)
Site folder (Read-only)
Domain folder (Read-only)
Machine folder (Read-only)
Group folder (Read-only)
Machine container
Machine folder (Read-only)
Group folder (Read-only)
Package container
Package folder (Read/Create/Delete)
Workstation Command Line folder (Read/Create/Delete)

Program Item folder (Read/Create/Delete)

Inventory Rules folder (Read/Create/Delete)

Job container
Run Command On Workstation job folder (Read/Create/Delete)

Share Package On Server job folder (Read/Create/Delete)

Remove Package From Server job folder (Read/Create/Delete)

System job folder (Read-only)

Machine Group container
Machine Group folder (Read-only)
Machine Group folder (Read-only)
Machine folder (Read-only)
Group folder (Read-only)
Site Group container
Site Group folder (Read-only)
Site Group folder (Read-only)
Site folder (Read-only)
Site folder (Read-only)
Domain folder (Read-only)
Machine folder (Read-only)
Group folder (Read-only)

The folders within the site, site group, machine, and machine group containers are read-only. MIF files are used to maintain (create, update, and delete) the machine objects. For more information about MIF files, see Extending the Inventory. The site and domain objects are maintained by the SMS system. Site groups and machine groups can be created, modified, and deleted by using the SMS Administrator.

The package and job containers allow read, create, and delete operations. For example, you can use the SMS API to view the existing packages and jobs within an SMS database, as well as to create new packages and jobs.

The functions in the SMS API behave in a uniform manner:

  • All functions return a status code (SMS_STATUS).
  • To return values, the functions use a reference parameter.
  • Except for the static information functions, all functions are handle-based.


SMS API Container Hierarchy

Click the item to see details about the object.


Containers

The SMS API uses containers to hold objects retrieved from an SMS site database.

The SMS API accesses objects in a site database by retrieving information about those objects and storing that information in containers. There are different types of containers for different types of objects. For example, the C_PACKAGE container contains packages. To access an object in a site database, your application must open a container (which must support the type of object to be retrieved) by using the SmsOpenContainer function.

After your application has populated a container with objects from a site database, the application can access those objects and their properties. An application populates a container by using the SmsPopulate function.

Within a container, the instance of an object is represented as a folder. For example, a C_PACKAGE container can contain a set of folders that represent the packages in the current site's site database. The properties of an object are represented as subfolders or scalars within that object's folder. For example, a package folder has scalars that represent the package name, package identifier, and so on. In addition, a package folder can contain workstation command line folders, program item folders, and one inventory rules folder.

Before your application populates a container, it can set filters on the container. Filters specify the objects to retrieve from the site database and store in the container. If no filter is set for a container, all objects (that is, all objects of the type supported by the container) are returned when the container is populated. There are eight types of filters available. The types of filters that you can set are dependent on the container. For example, filters of type ARCHITECTURE_FILTER, SITELIMIT_FILTER, MACHINE_FILTER, GROUP_FILTER, and ATTRIBUTE_FILTER can be set on a machine container. For more information on creating and setting filters, see Filters.

After a container has been populated, the order of the folders within that particular container is fixed. Using the SmsGetNextFolder function, your application can access the folders in the container sequentially. SmsGetNextFolder returns the handle to the next folder in the list of folders within a container. Because SmsGetNextFolder reads folders sequentially, your application must explicitly reset the folder list to start at the beginning of the list again. When SmsGetNextFolder has reached the end of the folder list, it returns SMS_NO_MORE_DATA. Your application can use SmsRewind to start at the beginning of the folder list again. SmsRewind enables your application to iterate the folders again from the beginning of the folder list.

If a folder within a container has subfolders, your application can use SmsGetNextFolder to access those subfolders. Your application can also access a subfolder within a folder by the subfolder's identifier, by using the SmsGetFolderByID function. Note that top-level folders in a container can be retrieved only by using SmsGetNextFolder.

For more information about accessing containers, folders, and scalars, see General Steps for Using the SMS API to Manage SMS Objects.


Container Types

There are six types of containers:

C_JOB

C_MACHINE

C_MACHINEGROUP

C_PACKAGE

C_SITE

C_SITEGROUP

Each type of container supports specific types of objects. For example, the C_SITE container contains sites, which are represented as site folders. The site folders contain scalars and subfolders that represent the contents of a site (namely, domains and computers).

In addition, queries are represented as persistent machine filters in a filter container. For more information about persistent filters and filter containers, see Filter Containers.


Job Container (C_JOB)

A job container is used to gain access to jobs in the current site's site database. The job container is analogous to the Jobs window in the SMS Administrator. Thus, a job container contains, at the topmost level, job folders. Each type of job is represented as a type of job folder. For example, a Run Command On Workstation job is represented as an F_INSTALLJOB folder.

Jobs are SMS objects that store instructions for system actions. For example, you can define a Run Command On Workstation job to install a package on computers, or the SMS system can create a job to maintain part of the system.

Job folders do not contain any subfolders. The properties of a job are represented by the scalars within the job's folder.

Using a job filter, your application can specify the job folders that will appear in the container. For example, a job filter can be used to populate a job container with folders for only one type of job, such as a Run Command On Workstation job.

A job container has the following properties:

Property | Value | Description
Tag | "Job container" | String. A description of the container type.
Container type | C_JOB | Integer. Container type.
Applied filters | JOB_FILTER | Integer. Filters that can be applied to a job container. These filters act upon objects at the job container level.
Active filters | JOB_FILTER | Integer. Filters that are directly activated on the container. These filter types are used to retrieve the top-level folders in the container.
Immediate subfolders | F_SYSTEMJOB F_INSTALLJOB F_REMPKGJOB F_SRVINSTALLJOB | Integer. Types of subfolders that the container type can contain.


Machine (MIF) Container (C_MACHINE)

A machine (MIF) container is used to access inventoried objects in the site database. A machine container contains objects that have been added to the site database by using MIF files. Each inventoried object is represented as a machine folder. Note that machine folders can be included in a site container, site group container, machine container, or machine group container.

Each object is an instance of a specific type of object. An object type is called an architecture. For example, computers inventoried in the site database have the Personal Computer architecture and SMS events have the SMSEvent architecture.

Your application can view objects of any architecture stored in the site database.

Note that objects can be added so that they are part of a site and domain (for example, objects with the Personal Computer architecture can be represented as part of a domain within a site). These types of objects can be viewed by using a site container or a machine container. To be represented in the site hierarchy, an object must have specific attributes set in the Identification group. For more information about adding objects to be represented in the site hierarchy, see Extending the Inventory. If an object does not have these attributes set, it can only be viewed by using a machine container.

A machine container has the following properties:

Property | Value | Description
Tag | "Machine container" | String. A description of the container type.
Container type | C_MACHINE | Integer. Container type.
Applied filters | ARCHITECTURE_FILTER MACHINE_FILTER ATTRIBUTE_FILTER SITELIMIT_FILTER GROUP_FILTER | Integer. Filters that can be applied to the container type.
Active filters | None. | Integer. Filters that are directly activated on the container. These filter types are used to retrieve the top-level folders in the container.
Immediate subfolders | F_MACHINE | Integer. Types of subfolders that the container type can contain.


Machine Group Container (C_MACHINEGROUP)

A machine group container is used to view and create machine groups in the current site's site database. The machine group container is analogous to the Machine Groups window in the SMS Administrator. Thus, a machine group container contains, at the topmost level, machine group folders. Machine group folders contain machine folders which, in turn, contain group folders. Machine group folders can also contain other machine group folders.

A machine group serves as an alias for a set of computers. Machine groups can be used to specify the job targets and distribution servers for Run Command On Workstation and Share Package On Server jobs.

A machine group folder can be created within a machine group container, but not within another machine group (this is an SDK restriction, not an SMS one). Machines can be copied from the machine or site container into a newly-created machine group folder using the SmsDupFolder function. Machine folders cannot be created any other way in a machine group (or in any other folder). Once created, the folder must be linked to its parent and committed to the site database in the same manner as when creating any other type of folder.

A machine group container has the following properties:

Property | Value | Description
Tag | "MachineGroup container" | String. A description of the container type.
Container type | C_MACHINEGROUP | Integer. Container type.
Applied filters | GROUP_FILTER | Integer. Filters that can be applied to the container type.
Active filters | None. | Integer. Filters that are directly activated on the container. These filter types are used to retrieve the top-level folders in the container.
Immediate subfolders | F_MACHINEGROUP | Integer. Types of subfolders that the container type can contain.


Package Container (C_PACKAGE)

A package container is used to gain access to packages in the current site's site database. The package container is analogous to the Packages window in the SMS Administrator. Thus, a package container contains, at the topmost level, package folders. A package folder can contain workstation command line folders, program item folders, or an inventory rules folder.

A package stores information about software so that the software can be identified, installed on computers, and shared from servers. When you create a package, you define the files that make up the software, and the package's configuration and identification information. After you create a package, you can use SMS to install the package on computers, share the package so that it can be run from network servers, or maintain inventory on the package. You can create packages for commercial applications, for applications you have developed, and for data files.

A package folder contains scalars that represent most of the properties of the package. Which properties you define are determined by how the package will be used. The properties apply to the package in general, or to one or more of the following three purposes:

Workstations
Used to specify the source files and commands for a package that is installed on computers. These properties are used when the package is used for a Run Command On Workstation job.
Sharing
Used to specify the source files, share name, program items, and directory permissions used for a package that is installed as a network application. These properties are used when the package is used for a Share Package On Server job.
Inventory
Used to specify the rules used by the SMS system to identify a package, maintain its inventory, and collect files.

Within a package, workstation command line folders are used for the Workstations property and program item folders are used for the Sharing property.

Using a package filter, your application can specify the package folders that will appear in the container. For example, a package filter can be used to populate a package container with only packages that have the Workstations property defined.

A package container has the following properties:

Property | Value | Description
Tag | "Package container" | String. A description of the container type.
Container type | C_PACKAGE | Integer. Container type.
Applied filters | PACKAGE_FILTER | Integer. Filters that can be applied to a package container. These filters act upon objects at either the package container or folder level, depending on the type of filter.
Active filters | PACKAGE_FILTER | Integer. Filters that are directly activated on the container. These filter types are used to retrieve the top-level folders in the container.
Immediate subfolders | F_PACKAGE | Integer. Type of folder that the container contains at the top level. Note that the top-level folders may have their own hierarchy of subfolders.


Site Container (C_SITE)

A site container is used to gain access to sites and to objects that exist within a site hierarchy. The site container is analogous to the Sites window in the SMS Administrator. Thus, a site container contains, at the topmost level, site folders. Site folders themselves can contain other folders such as domain folders and site folders. Using this container, your application can access the sites, subsites, domains, machines, and the detailed inventory of each machine in a site hierarchy.

Using a site filter, your application can specify the site folders that will appear at the top level of the container. Note that the SMS Administrator allows only a hierarchical view starting from the current site (the site that is using the current database as its site database).

A site container has the following properties:

Property | Value | Description
Tag | "Site container" | String. A description of the container type.
Container type | C_SITE | Integer. Container type.
Applied filters | SITE_FILTER GROUP_FILTER MACHINE_FILTER ATTRIBUTE_FILTER ARCHITECTURE_FILTER | Integer. Filters that can be applied to a site container. These filters act upon objects at either the site container or folder level, depending on the type of filter.
Active filters | SITE_FILTER | Integer. Filters that are directly activated on the container. These filter types are used to retrieve the top-level folders in the container.
Immediate subfolders | F_SITE | Integer. Type of folder that the container contains at the top level. Note that the top-level folders may have their own hierarchy of subfolders.


Site Group Container (C_SITEGROUP)

A site group container is used to gain access to site groups in the current site's site database. The site group container is analogous to the Site Groups window in the SMS Administrator. Thus, a site group container contains, at the topmost level, site group folders. Site group folders contain site folders which, in turn, contain site folders and/or domain folders. The domain folders contain machine folders, group folders, and so on. Site group folders can also contain other site group folders.

A site group serves as an alias for a set of sites. Site groups can be used to specify the site limits for Run Command On Workstation, Share Package On Server, and Remove Package From Server jobs.

A site group container has the following properties:

Property | Value | Description
Tag | "SiteGroup container" | String. A description of the container type.
Container type | C_SITEGROUP | Integer. Container type.
Applied filters | ARCHITECTURE_FILTER MACHINE_FILTER ATTRIBUTE_FILTER GROUP_FILTER | Integer. Filters that can be applied to the container type.
Active filters | None. | Integer. Filters that are directly activated on the container. These filter types are used to retrieve the top-level folders in the container.
Immediate subfolders | F_SITEGROUP | Integer. Types of subfolders that the container type can contain.


Container Properties

The SmsEnumContainers function enables your application to get information about the container types. SmsEnumContainers retrieves information about all container types supported by the SMS API. The properties for each container type are stored in a FOLDER_INFO structure.

By accessing the members of the FOLDER_INFO structure, your application can get the following information about the container type:

tObjectity
Specifies the type of object: T_CONTAINER or T_FOLDER. See BASETYPE.

Because the FOLDER_INFO structure is used to describe both containers and folders, this member indicates which of these types is being described.

pszTag
Points to the string form of the container's tag.
dwTag
Specifies the integer form of the container's tag.
ctFolders
Specifies the number of immediate folder types that the specified container contains. Note that ctFolders specifies the types of folders that the specified container is capable of containing—not the number of actual folders contained within a specific container.
pFolderTags
Points to an array of DWORD values that indicate the types of immediate folders supported by the container.
ctFilters
Specifies the number of filter types that the container supports.
pFilterTags
Points to an array of DWORD values that indicate the types of filters supported by the container.

You can also use the SmsDescribeFolder function to retrieve information about an individual container.


Populating Containers

To access objects from a site database, your application must populate a container by using the SmsPopulate function.

Before a container is populated, your application can specify the criteria to use in selecting the objects to retrieve. Your application does this by applying filters to the container.

If your application does not set a filter on the container by using the SmsSetFilter function, SmsPopulate fills the container with folders that represent all objects (of the type supported by the container) in the site database. There are eight types of filters available. The types of filters that you can set are dependent on the container. For example, filters of type ARCHITECTURE_FILTER, SITELIMIT_FILTER, MACHINE_FILTER, GROUP_FILTER, and ATTRIBUTE_FILTER can be set on a machine container. For more information on creating and setting filters, see Filters.

For containers that contain machine folders (site container, site group container, machine container, and machine group container), the SmsPopulate function can retrieve folders in one of two modes: synchronous or asynchronous. For package containers and job containers, only synchronous mode is supported. Note that there are some special issues to be addressed when using asynchronous retrieval for site containers and site group containers. For more detailed information, see Populating Containers in Asynchronous Mode.

After a container has been populated, your application can access the objects (which are represented as folders) and their properties. Note that folders retrieved by SmsPopulate represent the set of objects in the site database at the time when SmsPopulate was called by your application. Any objects added to the site database after SmsPopulate is called are not reflected in the list of folders within the container. Currently, containers cannot be refreshed. To get the latest information from the site database, your application must open and populate a new container and then access the information in the new container.

After a container has been populated, the order of the folders within that particular container is fixed. Using the SmsGetNextFolder function, your application can access the folders in the container sequentially. SmsGetNextFolder returns the handle to the next folder in the list of folders within a container.


Populating Containers in Asynchronous Mode

The SmsPopulate function can retrieve folders in asynchronous mode from containers that contain machine folders (site containers, site group containers, machine containers, and machine group containers). Using asynchronous mode, your application goes immediately to the next line of code (after the SmsPopulate call) while the SMS API engine retrieves all folders that satisfy the filter criteria. You can set additional flags that specify that the SMS API engine should set an event handle or post a message to a window each time a specified number of objects is retrieved and when the retrieval is completed.

Although the SmsPopulate function applies to containers, the asynchronous behavior goes into effect only when retrieving machine folders from their parent containers or folders. For machine containers, the asynchronous behavior is in effect when SmsPopulate is called, because machine folders are the top-level folder in the container.

However, the machine folders in a site container are lower-level folders; they are contained within the domain folders within site folders. When your application uses asynchronous population on a site container, the asynchronous retrieval takes effect when it accesses the folder containing the machine folders—the domain folder. The site folders and the domain folders are not retrieved asynchronously.

When your application uses asynchronous mode to retrieve machine folders within a site container, you must consider the following issues:

To start asynchronous retrieval of the machine folders in a domain folder, the domain folder must be initialized.
Asynchronous retrieval in a site container begins only after the domain folder is initialized. This initialization does not occur when the domain folder is retrieved. The initialization is triggered by calling one of the following functions:

SmsGetFolderByID

SmsGetFolderCount

SmsGetNextFolder

SmsGetNextScalar

SmsGetScalarByName

SmsGetScalarCount

SmsSetScalar

For example, if a site folder contains four domain folders and your application calls one of the listed functions (such as SmsGetFolderCount) for only one domain folder, machine folder retrieval will be triggered only for that one domain.

Only one event handle (or window handle) is used for notification for all domain folders in a site container.
If your application triggers the retrieval for more than one domain folder, all the domain folders will use the single handle to signal the event. This means that your application cannot determine which domain folder has set the signaled state by using only the state of the event.

To avoid problems, your application should use one of the following methods to retrieve machine folders from multiple domain folders:

Sequential Processing of Domain Folders
Retrieves machine folders for domain folders sequentially by initializing each domain folder one at a time and allowing the retrieval for the domain folder to complete before initializing the next domain folder.
Processing Multiple Domain Folders Simultaneously
Retrieves machine folders for multiple domain folders at the same time.


Sequential Processing of Domain Folders

The simplest method for retrieving machine folders from multiple domain folders is sequential processing. Your application processes each domain folder one at a time. This means that your application initializes, and waits for the retrieval of, all machine folders for a single domain folder before initializing another domain folder.

The following example populates a site container and retrieves the machines for each domain, one domain at a time.

// Function to display all domains and machine folders for all
// sites in a site container.
// Function uses asynchronous population with
// event notification for every 10 machines
// that are retrieved.

SMS_STATUS EnumerateMachinesInSiteContainer(
    HANDLE hConnect)

{
SMS_STATUS stat;
// Open a site container.
HANDLE hSiteContainer;
stat = SmsOpenContainer( C_SITE,
                         hConnect,
                         &hSiteContainer);

// Create the notification event (auto-reset, non-signaled).
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
NOTIFY Notify;
Notify.dwFreq  = 10;  // Notify every 10 machines.
Notify.hEvent  = hEvent;
// Populate the container with no site filters to retrieve
// a flat list of all sites in the site database.
stat = SmsPopulate( hSiteContainer,
                    POP_ASYNC | POP_EVENT,
                    &Notify );

// Get count of folders in container.
DWORD totFolders;
SmsGetFolderCount( hSiteContainer, F_ANY, &totFolders );
printf("The site container has %d site folders.\n",
       totFolders );

HANDLE hSiteFolder;
HANDLE hDomainFolder;
HANDLE hMachineFolder;
DWORD dwSiteI;
DWORD dwDomainI;
DWORD dwMachineI;
DWORD totDFolders;
DWORD totMFolders;
DWORD fType;
DWORD dwRet;
char szfType[SMS_DATA_BUFF_SIZE];
char szFolderID[SMS_DATA_BUFF_SIZE];
// Open each site folder and process it.
// Note site folders are retrieved synchronously.
for (dwSiteI = 0; dwSiteI < totFolders; dwSiteI++) {
    stat = SmsGetNextFolder( hSiteContainer,
                             F_ANY,
                             &hSiteFolder );
    if (stat != SMS_OK) {
        printf("SmsGetNextFolder failed for site container.\n");
        printf("Status code: %d\n", stat);
        break;
    }
    // If site folder is retrieved, display the site name.
    SmsGetFolderID( hSiteFolder, szFolderID );
    SmsGetFolderType( hSiteFolder, &fType, szfType );
    printf("%s: \"%s\"\n", szfType, szFolderID);
    // Count how many domain folders.
    SmsGetFolderCount( hSiteFolder, F_DOMAIN, &totDFolders );
    // Retrieve the domain folders within the site folder.
    // Note domain folders are retrieved synchronously.
    for (dwDomainI = 0; dwDomainI < totDFolders; dwDomainI++) {
        stat = SmsGetNextFolder( hSiteFolder,
                                 F_DOMAIN,
                                 &hDomainFolder );
        if (stat != SMS_OK) {
            printf("\tSmsGetNextFolder failed for site folder.\n");
            printf("\tStatus code: %d\n", stat);
            break;
        }
        // If domain folder is retrieved, display the domain name.
        SmsGetFolderID( hDomainFolder, szFolderID );
        SmsGetFolderType( hDomainFolder, &fType, szfType );
        printf("\t%s: \"%s\"\n", szfType, szFolderID);
        // Trigger asynchronous retrieval for the domain folder
        // by calling SmsGetFolderCount for the domain folder.
        SmsGetFolderCount( hDomainFolder,
                           F_MACHINE,
                           &totMFolders );
        // Process machine folders as the number specified by
        // the frequency is retrieved
        // and print "." for progress.
        printf("\t\tRetrieving machines");
        while (1) {
            dwRet = WaitForSingleObject( Notify.hEvent, 1000 );
            if (dwRet != WAIT_OBJECT_0) {
                printf("."); // Simple wait indication.
                continue;
            }
            SmsGetFolderCount( hDomainFolder,
                               F_MACHINE,
                               &totMFolders );
            printf("\n\t\tCurrently %d folders in %s.\n",
                   totMFolders,
                   szFolderID);
            // Retrieved at least Notify.dwFreq machines.
            // Retrieve the machine folders currently
            // in the domain folder.
            for (dwMachineI = 0; dwMachineI < Notify.dwFreq;
             dwMachineI++) {
               stat = SmsGetNextFolder( hDomainFolder,
                                         F_MACHINE,
                                         &hMachineFolder );
               // If machine folder is retrieved,
               // display the machine ID and type.
               if (stat == SMS_OK) {
                   SmsGetFolderID( hMachineFolder, szFolderID );
                   SmsGetFolderType( hMachineFolder,
                                     &fType,
                                     szfType );
                   printf("\t\t%s: \"%s\"\n", szfType, szFolderID);
                   // Close the machine folder.
                   SmsCloseFolder( hMachineFolder );
            }
               else if (stat == SMS_NO_MORE_DATA) {
                   // End of folder list break out of loop.
                   printf("\t\tEnd of folder list for domain.\n");
                   break;
               }
               else {
                   printf("\t\tSmsGetNextFolder failed for domain folder.\n");
                   printf("\t\tStatus code: %d\n", stat);
                   break;
               }
            }
            // Check the status of retrieval.
            // If SMS_OK, then go back to wait for more folders.
            // If SMS_NO_MORE_DATA, then all machine folders in
            // the domain have already been processed
            // so the loop can be terminated.
            if (stat == SMS_OK) {
                printf("\t\tRetrieving more machines.\n");
            }
            else if (stat == SMS_NO_MORE_DATA) {
                printf("\t\tNo more machines in domain\n");
                break;
            }
            else {
                printf("\t\tSmsGetNextFolder failed: %d\n", stat);
                break;  // Exit machine folder retrieval loop
            }
        }
        // Close the Domain folder.
         SmsCloseFolder( hDomainFolder );
    }
    // Close the Site folder.
    SmsCloseFolder( hSiteFolder );
}
return stat;
} /* EnumerateMachinesInSiteContainer */


Processing Multiple Domain Folders Simultaneously

When more than one domain folder has been initialized, the Win32® WaitForSingleObject function returns when an event is set for any of those domain folders. The sequential processing for the example function EnumerateMachinesInSiteContainer in Sequential Processing of Domain Folders could not be used. While processing each domain folder, your application must be aware of all other domain folders that have been initialized.

When your application processes each domain folder, it triggers the machine folder retrieval for a domain folder by calling SmsGetFolderCount (or another function from the list of domain folder intialization functions) and then calling WaitForSingleObject. However, when WaitForSingleObject returns, your application cannot detect which domain folder set the signaled state on the event. To confirm which domain folder set the signaled state, your application should use the following technique:

For each domain folder, maintain a running count of the machine folders retrieved. When the WaitForSingleObject function returns, call the SmsGetFolderCount function and then compare the current count with the previous count. If there is a change, there are more machine folders in the domain folder that your application can process. If the count is unchanged for that domain folder, then the signal was for another domain folder. You must now call SmsGetFolderCount for each domain folder that has been initialized.

Your application should use this technique to ensure that it does not lose a signal for any of the domain folders.


Folders

Within a container, the instance of an object is represented as a folder. For example, a C_SITE container can contain a set of F_SITE folders that represent the current site (the site whose SMS database your application is accessing) or sites below the current site in the site hierarchy.

A folder contains scalars, subfolders, or both. A scalar is the value stored for an attribute of a folder. For example, the folder for a site contains scalars for site name, parent site, depth, status, site type, and detailed status. The folder for a specific site would have a specific value for each scalar. For example, the folder for the TIM site could contain the string "Tim World" for site name.

Because some objects themselves can contain multiple components, a folder can also contain subfolders. For example, a site folder can contain subfolders for the domains in the site and any subsites below that site in the site hierarchy.

The set of scalars that a folder can contain is determined by the type of the folder. Except for group folders, the set of scalars for all folder types is predetermined by the SMS API. For example, all site folders always contain the same set of scalars; however, the values for those scalars will differ between each instance of a site folder. Group folders contain scalars that represent attributes for an inventoried item. However, the set of attributes within a group folder is determined by the specific instance of the group folder.

For more information about accessing containers, folders, and scalars, see General Steps for Using the SMS API to Manage Queries.


Folder Properties

The SmsEnumFolders function enables your application to get information about the folder types supported by a specific container or folder. SmsEnumFolders retrieves information about all folder types supported by the SMS API. The properties for each folder type are stored in a FOLDER_INFO structure.

By accessing the members of the FOLDER_INFO structure, your application can get the following information about the folder type:

tObjectity
Specifies the type of object. For folders, the type of object is T_FOLDER. See BASETYPE.

Because the FOLDER_INFO structure is used to describe both containers and folders, this member indicates which of these types is being described.

pszTag
Points to the string form of the folder's tag.
dwTag
Specifies the integer form of the folder's tag.
ctFolders
Specifies the number of subfolder types that the specified folder supports. Note that ctFolders specifies the types of folders that the specified folder is capable of containing—not the number of actual subfolders contained within a specific folder.
pFolderTags
Points to an array of DWORD values that indicate the types of subfolders supported by the folder.
ctFilters
Specifies the number of filter types that the specified folder or container supports.
pFilterTags
Points to an array of DWORD values that indicate the types of filters supported by the folder.
ctScalars
Specifies the number of scalars that the specified folder supports.
pScalars
Points to an array of SCALAR_INFO structures that describe the scalars supported by the folder.

You can also use the SmsDescribeFolder function to retrieve information about an individual folder type. SmsEnumFolderTypes retrieves information about the folder types for a specific container or folder. SmsGetFolderCount retrieves the count of actual subfolders contained within a folder or container.


Folder Types

There are 14 types of folders:

F_DOMAIN

F_GROUP

F_INSTALLJOB

F_INVENTORY

F_MACHINE

F_MACHINEGROUP

F_PACKAGE

F_PROGITEM

F_REMPKGJOB

F_SITE

F_SITEGROUP

F_SRVINSTALL

F_SYSTEMJOB

F_WCL

Each type of folder represents a specific type of object. For example, F_SITE folders represent sites. A folder can contain scalars, subfolders, or both. The scalars and subfolders represent properties of the object.

In addition, queries are represented as persistent machine filters in a filter container. For more information about persistent filters and filter containers, see Filter Containers.


Domain Folder (F_DOMAIN)

A site contains one or more domains. Therefore, a site folder contains one or more domain folders that represent the site's domains. Domain folder scalars have read-only access. Therefore, an application cannot set scalar values for a domain folder.

Property | Value | Description
Tag | "Domain" | String. A description of the folder type.
Folder type | F_DOMAIN | Integer. Folder type.
ID | domain. For example, "REDDOM". | String. The name of the domain.
Active filters | None | Integer. Filters that are directly activated on the folder.
Immediate subfolders | F_MACHINE | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 1 | Integer. Number of scalars for the folder type.


Inventory Rules Folder (F_INVENTORY)

An inventory rules folder contains the rules used to identify a package so that the SMS system can scan for the package on SMS computers.

In addition to the Inventory this package scalar, an inventory rules folder contains one or more tokens that represent the rule for collecting inventory on the package. An inventory rules folder must contain at least one expression token. In addition, a package folder can contain one and only one inventory rules folder.

Using the SMS API, your application can perform the following actions:

  • View the existing inventory rules within a package
  • Create inventory rules within a new package

An inventory rules folder contains the following properties:

Property | Value | Description
Tag | "Inventory Rules" | String. A description of the folder type.
Folder type | F_INVENTORY | Integer. Folder type.
ID | "Inventory rules" | String. An inventory rules folder always uses "Inventory rules" as the ID.
Applied filters | None |
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 1 | Integer. Number of scalars for the folder type. Note that an inventory rules folder also contains tokens that represent the rule for collecting inventory on a package.


Machine Folder (F_MACHINE)

Objects that have been added to the site database by using MIF files are represented as machine folders. Note that machine folders can be included in a site container, site group container, machine container, or machine group container.

Each object is an instance of a specific type of object. An object type is called an architecture. For example, computers inventoried in the site database have the Personal Computer architecture and SMS events have the SMSEvent architecture. To be able to view an object as a machine folder with the SMS API, the machine folder must contain an Architecture group folder.

The inventory for an object in the site database is represented as a machine folder with the object's properties represented as grouped attributes. A machine folder contains group subfolders. Group folders represent distinct parts of the object. A group combines a set of attributes into a single, identifiable entity. For example, Processor, Network, and Operating System are some of the groups that can exist on a computer with the Personal Computer architecture. In the Personal Computer architecture, groups can be used to store the properties of a hardware device (such as a COM port or mouse), a piece of software (such as the operating system or a defined software package), or any logical entity (such as asset or employee information through custom MIFs).

Your application can view objects of any architecture stored in the site database.

Only objects that are part of a site hierarchy can populate a machine group container, site container, or site group container. These types of objects are added to the SMS inventory as part of a site and domain (for example, objects with the Personal Computer architecture can be represented as part of a domain within a site). To be represented in the site hierarchy, an object must have specific attributes set in the Identification group. For more information about adding objects to be represented in the site hierarchy, see Extending the Inventory. If an object does not have these attributes set, it can be viewed only by using a machine container.

A machine folder has the following properties:

Property | Value | Description
Tag | "Machine" | String. A description of the folder type.
Folder type | F_MACHINE | Integer. Folder type.
ID | For the Personal Computer architecture, the value has the form site|domain|name. For example, "JS1|REDDOM|jonathan1". For all other architectures, the value is the string form of an integer. For example, "1234". | String. For Personal Computer objects, the combination of the site, domain, and name attributes of the Identification group of the MIF object. If the object is of any other architecture, the ID is the string form of an integer identifier.
Active filters | GROUP_FILTER | Integer. Filters that are directly activated on the folder. These filter types are used to retrieve the subfolders in the folder.
Immediate subfolders | F_GROUP | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 0 | Integer. Number of scalars for the folder type.


Machine Group Folder (F_MACHINEGROUP)

Machine group folders contain machine folders which, in turn, contain group folders. Machine group folders can also contain other machine group folders.

A machine group folder has the following properties:

Property | Value | Description
Tag | "Machine Group" | String. A description of the folder type.
Folder type | F_MACHINEGROUP | Integer. Folder type.
ID | Machine group ID. For example, "MyGroup". | String. The name of the machine group.
Active filters | None |
Immediate subfolders | F_MACHINEGROUP F_MACHINE | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 2 | Integer. Number of scalars for the folder type.


MIF Group Folder (F_GROUP)

A machine folder contains group subfolders. Group folders represent distinct parts of the object. A group combines a set of attributes into a single, identifiable entity.

For example, Processor, Network, and Operating System are some of the groups that can exist on a computer with the Personal Computer architecture. In the Personal Computer architecture, groups can be used to store the properties of a hardware device (such as a COM port or mouse), a piece of software (such as the operating system or a defined software package), or any logical entity (such as asset or employee information through custom MIFs).

A group folder contains scalars that represent the actual properties (or attributes) of the group. Each attribute is assigned a value. The set of attribute values for a group makes up the inventory for a specific item. For example, a Disk group on a computer has attributes such as Drive Index, Storage Type, Free Storage, and so on. In a workstation's inventory, a Disk's Drive Letter attribute can be assigned a value such as A, B, C, and so on.

There is only one defined scalar for group folders in general (the LastChanged scalar; see MIF Group Folder Scalars). A group folder will usually also contain many scalars specific to the group. The set of scalars within a group folder depends on its group class.

The set of scalars within a group folder is also dependent on the instance of the group—all attributes defined for the group may not have been included by the MIF that reported the inventory. Indeed, different instances of the same group may contain completely different sets of attributes.

A group folder has the following properties:

Property | Value | Description
Tag | "Group" | String. A description of the folder type.
Folder type | F_GROUP | Integer. Folder type.
ID | Group class name of the form: organization:name:version. For example, the Identification group for the Personal Computer architecture has the class name: "MICROSOFT|IDENTIFICATION|1.0". | String. Class name of the group.
Active filters | None | Integer. Filters that are directly activated on the folder. These filter types are used to retrieve the subfolders in the folder.
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | Dependent on the group. | Integer. Number of scalars for the folder type.


Package Folder (F_PACKAGE)

A package folder (F_PACKAGE) represents a package. A package stores information about software so that the software can be identified, installed on computers, and shared from servers.

A package folder contains scalars that represent most of the properties of the package. The properties you define are determined by how the package will be used. The properties apply to the package in general or to one or more of the following three purposes:

Workstations
Used to specify the source files and commands for a package that is installed on computers. These properties are used when the package is used for a Run Command On Workstation job.
Sharing
Used to specify the source files, share name, program items, and directory permissions used for a package that is installed as a network application. These properties are used when the package is used for a Share Package On Server job.
Inventory
Used to specify the rules used by the SMS system to identify a package, maintain its inventory, and collect files.

A package folder can also contain workstation command line folders or program item folders. In addition, a package folder can contain an inventory rules folder that contains tokens that represent the rule for collecting inventory on the package.

Using the SMS API, your application can perform the following actions:

  • View existing packages
  • Delete existing packages
  • Create new packages

A package folder has the following properties:

Property | Value | Description
Tag | "Package" | String. A description of the folder type.
Folder type | F_PACKAGE | Integer. Folder type.
ID | packageID. For example, "RTM00001". | String. An eight-character identifier that the SMS system assigns to the package. Note that the first three characters are the site code for the site where the package was created.
Active filters | None |
Immediate subfolders | F_WCL F_PROGITEM F_INVENTORY | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 14 | Integer. Number of scalars for the folder type.


Program Item Folder (F_PROGITEM)

A program item folder contains the properties of a program item. A program item determines how a network application is configured and how it is exposed to the user.

Using the SMS API, your application can perform the following actions:

  • View existing program items within a package
  • Create program items within a new package

A program item folder contains the following properties:

Property | Value | Description
Tag | "Program Item" | String. A description of the folder type.
Folder type | F_PROGITEM | Integer. Folder type.
ID | programitemID. For example, "RTM00001". | String. An eight-character identifier that the SMS system assigns to the program item. Note that the first three characters are the site code for the site where the program item was created.
Applied filters | None |
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 12 | Integer. Number of scalars for the folder type.


Remove Package From Server Job Folder (F_REMPKGJOB)

A remove package job folder (F_REMPKGJOB) represents a Remove Package From Server job.

A Remove Package From Server job removes a package that has been installed on servers. A Remove Package From Server job removes the compressed version of the package stored at the receiving site server(s) and the uncompressed package files at the distribution servers. It does not, however, remove the package source directory stored on the originating server.

Using the SMS API, your application can perform the following actions:

  • View existing Remove Package From Server jobs
  • Delete existing Remove Package From Server jobs
  • Create new Remove Package From Server jobs

A remove package job folder has the following properties:

Property | Value | Description
Tag | "Remove package job" | String. A description of the folder type.
Folder type | F_REMPKGJOB | Integer. Folder type.
ID | jobID. For example, "RTM00001". | String. An eight-character identifier that the SMS system assigns to the job. Note that the first three characters are the site code for the site where the job was created.
Active filters | None |
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 20 | Integer. Number of scalars for the folder type.


Run Command On Workstation Job Folder (F_INSTALLJOB)

A workstation install job folder (F_INSTALLJOB) represents a Run Command On Workstation job.

A Run Command On Workstation job sends the source directory specified by the package's Workstations properties to target sites (and places this source directory on specified servers) and makes one or more package commands available at target computers. At each target computer, the user can run the package commands by choosing the package from the Package Command Manager window. A package command can start an executable file, batch file, or Microsoft Test script to install the package or to run a command.

Using the SMS API, your application can perform the following actions:

  • View existing Run Command On Workstation jobs
  • Delete existing Run Command On Workstation jobs
  • Create new Run Command On Workstation jobs

A workstation install job folder has the following properties:

Property | Value | Description
Tag | "Workstation install job" | String. A description of the folder type.
Folder type | F_INSTALLJOB | Integer. Folder type.
ID | jobID. For example, "RTM00001". | String. An eight-character identifier that the SMS system assigns to the job. Note that the first three characters are the site code for the site where the job was created.
Active filters | None | Integer. Filters that are directly activated on the folder. These filter types are used to retrieve the subfolders in the folder.
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 33 | Integer. Number of scalars for the folder type.


Share Package On Server Job Folder (F_SRVINSTALLJOB)

A server install job folder (F_SRVINSTALLJOB) represents a Share Package On Server job.

A Share Package On Server job sends the source directory specified by the package's Sharing properties to target sites, installs this source directory on the specified servers, shares the directories on the network, and makes them available to users who have the specified access permissions. This job can be used to install a source directory on a set of servers and set up the directory as a share. Or it can be used to install a package for network applications.

Using the SMS API, your application can perform the following actions:

  • View existing Share Package On Server jobs
  • Delete existing Share Package On Server jobs
  • Create new Share Package On Server jobs

A server install job folder has the following properties:

Property | Value | Description
Tag | "Server install job" | String. A description of the folder type.
Folder type | F_SRVINSTALLJOB | Integer. Folder type.
ID | jobID. For example, "RTM00001". | String. An eight-character identifier that the SMS system assigns to the job. Note that the first three characters are the site code for the site where the job was created.
Active filters | None |
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 22 | Integer. Number of scalars for the folder type.


Site Folder (F_SITE)

A site folder represents a site in the SMS system. A site folder has the following properties:

Property | Value | Description
Tag | "Site" | String. A description of the folder type.
Folder type | F_SITE | Integer. Folder type.
ID | sitecode. For example, "RTM". | String. The site code. A three-character code used by the SMS system to identify the site. The site code is specified when the site is created, and cannot be changed.
Active filters | None. | Integer. Filters that are directly activated on the folder. These filter types are used to retrieve the subfolders in the folder.
Immediate subfolders | F_SITE F_DOMAIN | Integer. Type of subfolders that the folder contains directly beneath it in hierarchy.
Number of scalars | 5 | Integer. Number of scalars that the folder contains.

A site folder can contain subfolders. A site can contain one or more domains. The domains are represented as domain folders within a site folder. A primary site can also contain other sites—a primary site database contains the current site (the primary site that uses the current database as a site database) and all sites beneath it in the site hierarchy. The child sites are represented as site folders within a site folder.

A site folder also has scalars that store information about the site.


Site Group Folder (F_SITEGROUP)

Site group folders contain site folders or other site group folders.

A site group folder has the following properties:

Property | Value | Description
Tag | "Site Group" | String. A description of the folder type.
Folder type | F_SITEGROUP | Integer. Folder type.
ID | Site group ID. For example, "MyGroup". | String. The name of the site group.
Active filters | None |
Immediate subfolders | F_SITEGROUP F_SITE | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 2 | Integer. Number of scalars for the folder type.


System Job Folder (F_SYSTEMJOB)

A system job folder (F_SYSTEMJOB) represents a job created by the SMS system to maintain the configuration at sites below the current site in the site hierarchy.

The SMS system uses system jobs to transfer instructions and data to other sites. For example, if you change a package's properties in the site's database, these package changes trigger a system job that updates the package in the databases of all primary sites beneath the current site.

Unlike other types of jobs, system jobs (except NAD transfer system jobs) are targeted for a single site and do not return job details or status information. However, system jobs created at a site appear in the Jobs window. Internally, SMS has full control over these jobs—it can cancel, activate, or delete system jobs.

Using the SMS API, your application can perform the following actions:

  • View existing system jobs
  • Delete existing system jobs

Note that your application can delete a system job from the site database only when it is active or after it has been completed or canceled by SMS.

Different types of system jobs perform different actions. The type of system job is identified by the Comment field in the system job folder.

A system job folder has the following properties:

Property | Value | Description
Tag | "System job" | String. A description of the folder type.
Folder type | F_SYSTEMJOB | Integer. Folder type.
ID | jobID. For example, "RTM00001". | String. An eight-character identifier that the SMS system assigns to the job. Note that the first three characters are the site code for the site where the job was created.
Active filters | None | Integer. Filters that are directly activated on the folder. These filter types are used to retrieve the subfolders in the folder.
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 15 | Integer. Number of scalars for the folder type.


Workstation Command Line Folder (F_WCL)

A workstation command line folder contains the properties of a workstation command line.

Workstation command lines are used for Run Command On Workstation jobs. A Run Command On Workstation job runs a specified package command line on individual computers. A command line can be used to install a package (by running a script or starting an application's setup program) or to run a program (such as a virus scan utility). You can define multiple command lines for a package. When you create a Run Command On Workstation job for a package, you select the specific command line you want to use.

Using the SMS API, your application can perform the following actions:

  • View existing workstation command lines within a package
  • Create workstation command lines within a new package

A workstation command line folder has the following properties:

Property | Value | Description
Tag | "Workstation Command Line" | String. A description of the folder type.
Folder type | F_WCL | Integer. Folder type.
ID | CommandName. For example, "Complete". | String. The name for the workstation command line. The Name scalar is used as the ID. This scalar has a maximum length of 255 characters. Within a specific package folder, the Name scalar must be unique.
Active Filters | None |
Immediate subfolders | None | Integer. Types of subfolders that the folder type can contain.
Number of scalars | 4 | Integer. Number of scalars for the folder type.


Creating Folders

Folders are created in the context of a parent, that is, folders are always created within a container or a parent folder. In addition, some folder types support creation and others do not. You can only create a new folder if the folder's type supports creation. The following folder types support creation:

F_INSTALLJOB

F_INVENTORY

F_PACKAGE

F_PROGITEM

F_REMPKGJOB

F_SRVINSTALL

F_WCL

After a new folder has been created, the folder is empty, that is, it has no scalars set within it. Note that your application must set the scalars for the new folder. Using the SmsDescribeFolder function, your application can retrieve the list of scalars for a folder. Using the SmsSetScalar function, your application can set the value for each scalar in the new folder. For some folders, such as the job folders F_INSTALLJOB, F_SRVINSTALL, and F_REMPKGJOB, some scalars are required and others are optional or dependent on the settings of other scalars.

A new folder also does not contain any subfolders. You can use the SmsCreateFolder function to add subfolders to the new folder.

In addition, a new folder created by SmsCreateFolder is not linked to its parent folder. Your application must use the SmsLinkFolder function to link a new folder to its parent. Linking associates the new folder to its parent within your application's memory—the folder is not written to the site database.

To add the new folder to the site database, your application must use the SmsCommitFolder function to write the folder to the database.

Some types of folders require their parent folder to be committed. These folders are not written to the site database until their parent folder is committed. If a folder requires its parent to be committed, the SmsCommitFolder function returns SMS_PARENT_NEEDS_COMMIT. Currently, when folders of the following types are committed, their parent folders also need to be committed:

F_INVENTORY

F_PROGITEM

F_WCL

Note that when your application creates a folder the usage count for the new folder is set to 1. To deallocate the memory for the new folder, your application must use SmsCloseFolder to close the folder.


Setting the Scalars for a New Job Folder

After creating a Job folder, your application can set the scalars for the folder. Each type of Job folder has its own set of scalars. Note that not all scalars need to be set. For example, the Job ID scalar is automatically set by the SMS system when the Job folder is committed to the site database.

To set the scalars for the new folder, use the SmsSetScalar function to set the value of a scalar.

To set the value of a scalar, both the scalar and its folder must have an access right of ACCESS_MODIFY or ACCESS_CREATE. If you do not have ACCESS_MODIFY to the scalar, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, the SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

To get information (such as name, data type, access rights, and so on) about all scalars within a folder, use the SmsDescribeFolder function.

The SmsSetScalar function takes two parameters:

  • The handle to the folder containing the scalar
  • A pointer to a SCALAR structure that contains the scalar data to be set

Example

//***********************************************************
// Function to list set of available packages,
// prompt for package ID, verify the package ID
// entered by the user, and set the Package ID scalar
// for an F_INSTALLJOB folder.
//***********************************************************

SMS_STATUS SetPackageIDScalar(HANDLE hJobFolder, // Job folder handle.
                              HANDLE hConnect)      //    Connection handle.
{
//***********************************************************
//****** Get a valid package ID.
//***********************************************************
// The package ID must be for an existing package that has
// Workstation properties set. Therefore, open a package
// container and populate it with a Package filter set to Workstation.
// Use the package container to get the list of available packages
// and prompt the user to select one. When the package ID is input,
// use the package container to verify the package ID.

SMS_STATUS stat;
// Open a package container.
HANDLE hPackageContainer;
stat = SmsOpenContainer( C_PACKAGE,
                         hConnect,
                         &hPackageContainer);
// Create a package filter.
HANDLE hFilter;
stat = SmsCreateFilter( PACKAGE_FILTER, // Type of filter.
                        hConnect,   // Handle to database
                                    // connection.
                        &hFilter    // Assign handle to new filter
                      );            // to hFilter.

// Add a token to the package filter that
// finds all packages with Workstation properties set.
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );
// Set the expression token to
// "PackageType is equal to Workstation".

// Set the attribute name to PackageType.
strcpy( Token.szName, "PackageType");
// Set the operator used to evaluate the expression.
Token.dwOp = QOP_STR_EQ; // Use the equals operator.
// Set the value to evaulate.
strcpy( Token.szValue, "Workstation");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use the AND control token to connect
                             // the expression to adjacent expressions.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );

// Apply the filter to the container.
stat = SmsSetFilter ( hPackageContainer,  // Handle to container.
                      hFilter      // Handle to filter.
                    );

// Populate the container with the folders meeting the criteria set
// by the filter applied to the container. Retrieve folders
// synchronously.
stat = SmsPopulate( hPackageContainer,  // Handle to container.
                    POP_SYNC,    // Retrieve folders in
                                 // synchronous mode.
                    NULL         // NULL for synchronous.
                  );

// Use SmsGetFolderCount to get number of folders in package container.
DWORD ctFolders;
stat = SmsGetFolderCount( hPackageContainer, // Handle to package container.
                          F_PACKAGE,      // Get count of package folders
                                      // in package container.
                          &ctFolders  // Assign count to pctFolders.
                        );

// Loop to retrieve the handles to the
// package folders in the package container using SmsGetNextFolder,
// retrieve the scalar value for the Package ID and Name scalars using
// SmsGetScalarByID, and print the Package ID and Name.
HANDLE hFolder;

SCALAR scalar;
char *pszName;
char szScalarName[SMS_DATA_BUFF_SIZE];
char szScalarValue[SMS_DATA_BUFF_SIZE];
scalar.dwLen = sizeof(szScalarValue)-1;
scalar.pszName = szScalarName;
scalar.pszValue = szScalarValue;
scalar.scType = SCALAR_STRING;

DWORD iLoop;
for (iLoop = 1; iLoop <= ctFolders+1; iLoop++) {
    stat = SmsGetNextFolder( hPackageContainer,
                             F_ANY,
                             &hFolder);
    // if folder was retrieved, display ID and Name.
    if (stat == SMS_OK) {
        //print heading if first time in loop.
        if (iLoop == 1)    {
            printf("%-12s", "Package ID");
            printf("%-25s\n", "Name");
        }
        // Get the ID and Name and print them.
        pszName = "Key";
        stat = SmsGetScalarByName(hFolder, pszName, &scalar);
        printf("%-12s", scalar.pszValue);
        scalar.dwLen = SMS_DATA_BUFF_SIZE;
        pszName = "Name";
        stat = SmsGetScalarByName(hFolder, pszName, &scalar);
        printf("%-25s\n", scalar.pszValue);
    }
    // break if end of folder list.
    else if (stat == SMS_NO_MORE_DATA)
        break;
    // break if folder retrieval error.
    else {
        printf("Could not retrieve folder: %d\n", stat);
        break;
    }
}

//Prompt for package ID.
char szPackageID[9];
printf("Enter package ID:");
gets(szPackageID);

//Verify package ID.
int iCompare;
BOOL bPackageExist = FALSE;
//Rewind folders in container to iterate folders again.
stat = SmsRewind(hPackageContainer, RW_FOLDER);
//Loop to search for package with ID match in szPackageID.
iLoop = 1;
while ( iLoop <= ctFolders) {
    stat = SmsGetNextFolder( hPackageContainer,
                             F_ANY,
                             &hFolder);
    // if folder is retrieved, check if szPackageID matches
    // the folder's ID.
    if (stat == SMS_OK) {
        pszName = "Key";
        stat = SmsGetScalarByName(hFolder, pszName, &scalar);
        //compare package ID with ID of folder.
        iCompare = strcmp(szPackageID , scalar.pszValue);
        // if package id matches folder's ID,
        // then set bPackageExist to TRUE and break.
        if (iCompare == 0) {
               bPackageExist = TRUE;
            printf("Package ID verified.\n");
               break;
        }
    }
    // if end of folder list, package ID does not match;
    // therefore, reprompt for ID and check again.
    else if (stat == SMS_NO_MORE_DATA) {
        printf("Package ID specified does not exist.\n");
        // reset folder list to start of list.
        stat = SmsRewind(hPackageContainer, RW_ALL);
        // reset loop.
        iLoop=0;
        // prompt again for ID.
        printf("Enter package ID again:");
        gets(szPackageID);
    }
    // if error retrieving folder, print status code
    // and break.
    else {
        printf("Could not retrieve folder: %d\n", stat);
        break;
    }
    iLoop++;
}

//***********************************************************
//****** Set the package ID scalar for the job folder.
//***********************************************************
// If the the package ID is valid, use it to set the
// Package ID scalar for the Run Command On Workstation job.
if (bPackageExist == TRUE) {
    SCALAR sc; // Declare SCALAR struct to hold scalar data.
    char *pszScalarName = "Package ID"; // Name of the scalar to set.
    SCALARTYPE scType = SCALAR_STRING; // Data type of scalar.

    // Assign the scalar data to the sc structure.
    sc.pszName = pszScalarName;
    sc.scType  = scType;
    sc.dwLen = sizeof(szPackageID)-1; // -1 for terminating NULL.
    sc.pszValue = szPackageID;

    // Use SmsSetScalar to use the sc struct to set the
    // scalar for the folder.
    stat = SmsSetScalar( hJobFolder, // Handle to folder containing
                                     // the scalar to set.
                         &sc);       // Pointer to SCALAR struct
                                     // containing value to set.
    if (stat == SMS_OK)
        printf("Package ID %s scalar set successfully.\n", sc.pszValue);
}
return stat;

}


Setting Scalars for Run Command On Workstation Jobs

When your application creates a Run Command On Workstation job (F_INSTALLJOB folder), some scalars (such as Activate time and Send phase) must have valid values so that the job activates, sends, distributes, and completes successfully. Other scalars (such as Job comment) are optional or are used by the SMS system to report status (such as Job status) or other system information (such as Job ID and Cancel mode). Still other scalars must be set if another scalar is set to a certain value (for example, the Query ID scalar must be set if Job target is set to WKSTAJOB_TGT_QUERY).

This section lists the scalars that must be set to create a valid Run Command On Workstation job.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For F_INSTALLJOB folders, the following scalars must be set:

Scalar name | Data type | Requirement
Job comment | String | Optional.
Activate time | Time | Required.
Priority | Integer | Required.
Repeat mode | Integer | Required.
Package ID | String | Required.
Job target | Integer | Required.
Query ID | String | If Job target is set to WKSTAJOB_TGT_QUERY, this scalar is required. Otherwise, it is not used.
Machine group name | String | If Job target is set to WKSTAJOB_TGT_MACHGROUP, this scalar is required. If this scalar is set to NULL, the Default Servers machine group will be used. Otherwise, it is not used.
Machine path | String | If Job target is set to WKSTAJOB_TGT_MACHPATH, this scalar is required. Otherwise, it is not used.
Limit to sites | Integer | Required.
Include subsites | Integer | If Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE, this scalar is required. Otherwise, it is not used.
Site limit name | String | If Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE, this scalar is required. Otherwise, it is not used.
Send phase | Integer | Required.
Distribute phase | Integer | Required.
Distribution servers | String | If Distribute phase is set to WKSTAJOB_DIST_SPECIFIED, this scalar is required. If this scalar is set to NULL, the Default Servers machine group will be used. Otherwise, it is not used.
Run workstation command | Integer | Required. If this scalar is set to FALSE, there is no Run phase for the job.
WCL name | String | If Run workstation command is set to TRUE, this scalar is required. Otherwise, it is not used.
Offer time | Time | If Run workstation command is set to TRUE, this scalar is required. Otherwise, it is not used.
Mandatory time | Time | If Use mandatory time is set to TRUE, this scalar is required. If Run workstation command is set to FALSE, this scalar is not used.
Use mandatory time | Integer | If Run workstation command is set to TRUE, this scalar is required. Otherwise, it is not used.
Force over slow link | Integer | If Use mandatory time is set to TRUE, this scalar is required. If Run workstation command is set to FALSE, this scalar is not used.
Use expire time | Integer | If Run workstation command is set to TRUE, this scalar is required. Otherwise, it is not used.
Expire time | Time | If Use expire time is set to TRUE, this scalar is required. If Run workstation command is set to FALSE, this scalar is not used.


Setting Scalars for Share Package On Server Jobs

When your application creates a Share Package On Server job (F_SRVINSTALLJOB folder), some scalars (such as Activate time and Send phase) must have valid values so that the job activates, sends, distributes, and completes successfully. Other scalars (such as Job comment) are optional or are used by the SMS system to report status (such as Job status) or other system information (such as Job ID and Cancel mode). Still other scalars must be set if another scalar is set to a certain value (for example, the Site limit name scalar must be set if Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE).

This section lists the scalars that must be set to create a valid Share Package On Server job.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For F_SRVINSTALLJOB folders, the following scalars must be set:

Scalar name | Data type | Requirement
Job comment | String | Optional.
Activate time | Time | Required.
Priority | Integer | Required.
Repeat mode | Integer | Required.
Package ID | String | Required.
Limit to sites | Integer | Required.
Include subsites | Integer | If Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE, this scalar is required. Otherwise, it is not used.
Site limit name | String | If Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE, this scalar is required. Otherwise, it is not used.
Send phase | Integer | Required.
Distribute phase | Integer | Required.
Distribution servers | String | If Distribute phase is set to SHAREJOB_DIST_SPECIFIED, this scalar is required. If this scalar is set to NULL, the Default Servers machine group will be used. Otherwise, it is not used.


Setting Scalars for Remove Package From Server Jobs

When your application creates a Remove Package From Server job (F_REMPKGJOB folder), some scalars (such as Activate time and Package type) must have valid values so that the job activates, sends, and completes successfully. Other scalars (such as Job comment) are optional or are used by the SMS system to report status (such as Job status) or other system information (such as Job ID and Cancel mode). Still other scalars must be set if another scalar is set to a certain value (for example, the Site limit name scalar must be set if Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE).

This topic lists the scalars that must be set to create a valid Remove Package From Server job.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For F_REMPKGJOB folders, the following scalars must be set:

Scalar name | Data type | Requirement
Job comment | String | Optional.
Activate time | Time | Required.
Priority | Integer | Required.
Repeat mode | Integer | Required.
Package ID | String | Required.
Package type | Integer | Required.
Job tasks | Integer | Required.
Limit to sites | Integer | Required.
Include subsites | Integer | If Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE, this scalar is required. Otherwise, it is not used.
Site limit name | String | If Limit to sites is set to JOBTGT_SITEGROUP or JOBTGT_SITE, this scalar is required. Otherwise, it is not used.
Distribution servers | String | If Job tasks is set to RMPKGJOB_TASKS_RM_SELECTED, this scalar is required. If this scalar is set to NULL, the Default Servers machine group will be used. Otherwise, it is not used.


Setting the Scalars for a New Package Folder

When your application creates a package (F_PACKAGE folder), some scalars (such as Name) must have valid values so that the package can be used for creating Run Command On Workstation jobs, creating Share Package On Server jobs, and detecting this package for the SMS computer inventory. Other scalars are optional (such as Comment) or are used by the SMS system (such as Key and Workstation transfer file).

This topic lists the scalars that must be set to create a valid package for use with Run Command On Workstation jobs, Share Package On Server jobs, network applications, or inventory.

Note that an inventory rules folder (which can be a subfolder within a package folder) contains only one scalar as well as one or more tokens that represent the set of files used to identify a package. See Setting Tokens for an Inventory Rules Folder.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For F_PACKAGE folders, the following scalars must be set:

Scalar name | Data type | Requirement
Name | String | Required.
Comment | String | Optional.
Workstation package Integer Required.

If this scalar is set to TRUE, this package will be available for Run Command On Workstation jobs. The SMS API engine sets this scalar to TRUE if the package has at least one Workstation Command Line subfolder and has the Workstation root scalar set.

If this scalar is set to FALSE, this package will not be available for Run Command On Workstation jobs.
Workstation root | String | This scalar is required for the package to be available for Run Command On Workstation jobs.
Workstation permissions | Integer | This scalar is required for the package to be available for Run Command On Workstation jobs.
Sharing package Integer Required.

If this scalar is set to TRUE, this package will be available for Share Package On Server jobs. The SMS API engine sets this scalar to TRUE if the package has the Server root and Share name scalars set.

If this scalar is set to FALSE, this package will not be available for Share Package On Server jobs.
Server root | String | This scalar is required for the package to be available for Share Package On Server jobs.
Share name | String | This scalar is required for the package to be available for Share Package On Server jobs.
Share permissions | Integer | This scalar is required for the package to be available for Share Package On Server jobs.
Inventory package Integer Required.

If this scalar is set to TRUE, this package will be inventoried on all computers in the current site and all subsites below it in the site hierarchy. The SMS API engine sets this scalar to TRUE if the package has an Inventory rules subfolder and the Inventory this package scalar for the Inventory rules subfolder is set to TRUE.

If this scalar is set to FALSE, this package will not be inventoried.


Setting Scalars for a New Workstation Command Line Folder

When your application creates a workstation command line (F_WCL folder), it must set the following scalars:

Scalar name | Data type | Requirement
Name | String | Required.
Command | String | Required.
Flags | Integer | Required.
Platforms | Integer | Required.


Setting Scalars for a New Program Item Folder

When your application creates a program item (F_PROGITEM folder), it must set the following scalars:

Scalar name | Data type | Requirement
Description | String | Required.
Command line | String | Required.
Run minimized | Integer | Required.
Platforms | Integer | Required.
Configure script file | String | Required.
Search local flag | Integer | Required.
Drive mode | Integer | Required.
Drive letter | String | If Drive mode is set to PI_DRIVEMODE_SPECIFIC_LETTER, this scalar is required.
Registry name | Integer | Required.
Display Icon in Program Group | Integer | Required.
Icon | Binary. | Required.


Setting Tokens for an Inventory Rules Folder

An inventory rules folder (which can be a subfolder within a package folder) contains only one scalar. However, an inventory rules folder must also contain one or more tokens that represent the rule for collecting inventory on the package.

The inventory rules folder uses expression tokens and control tokens in the same way that filters do—except that each expression token contains a string that specifies attributes that identify the file. In addition, the NOT operator is not supported for inventory rules. For an inventory rules folder, an expression token uses only the szTokenString member in the TOKEN structure.

The szTokenString string in an expression token is a string that contains the file name and file attributes used to identify a file. For information about the format required for szTokenString, see Inventory Rules Folder Tokens.

Note that your application is responsible for specifying a string containing a valid format as well as valid attributes for szTokenString. It is recommended that your application use the retrieve keyword so that the SMS API engine can retrieve the attribute value directly from the file, or that you use the FILETOKN.EXE utility provided with SMS to retrieve the attribute value from the file. Because there are several methods for calculating a CRC value, it is particularly important that you use the retrieve keyword or FILETOKN.EXE to calculate the CRC value, especially if you are unsure whether your CRC calculation uses the CCITT-CRC algorithm. For more information about the retrieve keyword, see Inventory Rules Folder Tokens.

Note that the inventory rules folder must contain at least one expression token. An inventory rules folder that does not contain one or more expression tokens cannot be committed to the site database.

In all other respects, the tokens for a inventory rules folder have the same behavior as tokens in a filter—expression tokens are connected by AND or OR operators, expression tokens can be grouped and ungrouped, and they can be deleted. However, the Inventory Agent program that scans for inventory uses the operators and groupings for a package's inventory rule in a specific manner. See Grouping Tokens in an Inventory Rules Folder.

Important To collect inventory on a package with tokens defined, the Inventory properties scalar for the package must be set to TRUE. The Inventory package scalar is used to indicate whether the SMS system scans for the package on all SMS computers at the current site and all sites below the current site in the site hierarchy. The SMS API engine sets the Inventory package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package has an Inventory rules subfolder and the inventory rules folder has the Inventory this package scalar set to TRUE.

When the Inventory properties scalar is set to TRUE and the inventory rules folder and package folder are committed, the package will be inventoried on all computers in the current site and all subsites below it in the site hierarchy.

If the Inventory properties scalar is set to FALSE, this package will not be inventoried. However, the tokens (that is, the inventory rule) for the package will be stored in the site database when the package folder is committed. After the package is committed, a user can use the SMS Administrator to enable inventory collection on the package.

Example

This example creates a package with the following inventory rule for Microsoft Word and enables inventory collection on that package:

file "winword.exe" CHECKSUM 20 200 7232
AND
file "winword6.reg" DATE 10/05/94

// Function to create a package folder with inventory rules for
// for Microsoft Word 6.0.
SMS_STATUS CreatePackageWithInventory( HANDLE hConnect )
// hConnect is a handle to a site database connection
// established by SmsDataSourceConnect.

{
SMS_STATUS retStatus;
SMS_STATUS status;

// Open a package container.
HANDLE hPackageContainer;
DWORD cType;
cType = C_PACKAGE; // Set container type to package.

status = SmsOpenContainer( cType,    // Type of container.
                         hConnect, // Handle to database connection.
                         &hPackageContainer // Assign handle for
                                     //container to hPackageContainer.
                        );
    if (status != SMS_OK) {
        printf("Cannot open package container. Error code: %d\n", status);
        return status;
    }

// Create a package folder.
HANDLE hFolder;
status = SmsCreateFolder ( hPackageContainer, // Handle to parent
                                            // container.
                         F_PACKAGE, // Folder type is package
                         NULL,         // SMS system assigns the
                                       // ID. Therefore, this
                                       // parameter is ignored.
                         &hFolder      // Handle to new folder.
                        );

// Set basic scalars for package so that inventory can be defined.
// This means set only Name.
int intValue;
SCALAR scalar;
// Set the Name scalar to Microsoft Word 6.0
char *pszScalarName = "Name"; // Name of the scalar to set.
SCALARTYPE scType = SCALAR_STRING; // Data type of scalar.
char *pszScalarValue = "Microsoft Word 6.0"; // Value to set.
// Assign the scalar data to the scalar structure.
scalar.pszName = pszScalarName;
scalar.scType  = scType;
scalar.dwLen = sizeof(pszScalarValue)-1;
scalar.pszValue = pszScalarValue;

// Use SmsSetScalar to use the SCALAR struct to set
// the Name scalar for the folder.
status = SmsSetScalar( hFolder,   // Handle to folder containing
                                 // the scalar to set.
                     &scalar     // Pointer to SCALAR struct
                                 // containing value to set.
                   );

// Create an inventory rules folder.
HANDLE hInventoryFolder;
status = SmsCreateFolder ( hFolder, // Handle to parent
                                            // folder.
                         F_INVENTORY, // Folder type is inventory
                         NULL,         // SMS system assigns the
                                       // ID. Therefore, this
                                       // parameter is ignored.
                         &hInventoryFolder   // Handle to new folder.
                        );

// Set the Inventory this package scalar to TRUE
// so that the SMS API engine will enable the Inventory this package
// scalar for the package.
pszScalarName = "Inventory this package"; // Name of the scalar to set.
scType = SCALAR_INT; // Data type of scalar.
intValue = TRUE; // Value to set.
// Assign the scalar data to the scalar structure.
scalar.pszName = pszScalarName;
scalar.scType  = scType;
scalar.dwValue = intValue;

// Use SmsSetScalar to use the SCALAR struct to set
// the Name scalar for the folder.
status = SmsSetScalar( hInventoryFolder, // Handle to folder containing
                                 // the scalar to set.
                     &scalar     // Pointer to SCALAR struct
                                 // containing value to set.
                   );
// Set the token for inventory rule for winword.exe.
TOKEN token;
memset( &token, 0, sizeof(TOKEN) );
// Assign the string containing the rule to winword.exe to pszRule.
char *pszRule = "file \"winword.exe\" CHECKSUM 20 200 7232";
// Set szTokenString member to pszRule.
strcpy(token.szTokenString, pszRule);
// Use SmsAddToken to add the token to the package's inventory rule.
status = SmsAddToken( hInventoryFolder, // Handle to folder.
                    OP_AND,  // Use AND operator.
                    &token,  // Pointer to token to set.
                    AT_END );    // Add to end of token list.

// Set the token for inventory rule for winword6.reg.
memset( &token, 0, sizeof(TOKEN) );
// Assign the string containing the rule to winword.exe to pszRule.
pszRule = "file \"winword6.reg\" DATE 10/05/94";
// Set szTokenString member to pszRule.
strcpy(token.szTokenString, pszRule);
// Use SmsAddToken to add the token to the package's inventory rule.
status = SmsAddToken( hInventoryFolder, // Handle to folder.
                    OP_AND,  // Use AND operator.
                    &token,  // Pointer to token to set.
                    AT_END );    // Add to end of token list.

// Link the inventoryfolder to its parent.
status = SmsLinkFolder( hInventoryFolder );

// Link the package folder to its parent.
status = SmsLinkFolder( hFolder );

// Write the inventory folder to the site database.
status = SmsCommitFolder( hInventoryFolder );

// Write the new package folder to the site database.
retStatus = SmsCommitFolder( hFolder );

// Close inventory folder
status = SmsCloseFolder( hInventoryFolder );

// Close package folder
status = SmsCloseFolder( hFolder );

// Close Container
status = SmsCloseContainer( hPackageContainer );

return retStatus;
}


Creating a Package for Run Command On Workstation Jobs

To create a package (F_PACKAGE) that can be used for Run Command On Workstation jobs (F_INSTALLJOB), some scalars must have valid values (such as the Name scalar). Other scalars are optional (such as Comment) or are set and used only by the SMS system (such as Key and Workstation transfer file).

The Workstation package scalar is used to indicate whether the package is available for Run Command On Workstation jobs. The SMS API engine sets the Workstation package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package has at least one Workstation Command Line subfolder and has the Workstation root scalar set.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For a package to be available for Run Command On Workstation jobs, the following scalars must be set (and the package must contain at least one workstation command line folder):

Scalar name | Data type | Requirement
Name | String | Required.
Comment | String | Optional.
Workstation package | Integer | Required. The SMS API engine sets this scalar to TRUE if the package has at least one Workstation Command Line subfolder and has the Workstation root scalar set. When this scalar is set to TRUE, this package will be available for Run Command On Workstation jobs. If this scalar is set to FALSE, this package will not be available for Run Command On Workstation jobs.
Workstation root | String | Required.
Workstation permissions | Integer | Required.


Creating a Package for Share Package On Server Jobs

To create a package (F_PACKAGE) that can be used for Share Package On Server jobs (F_SRVINSTALLJOB), some scalars must have valid values (such as the Name scalar). Other scalars are optional (such as Comment) or are set and used only by the SMS system (such as Key and Server transfer file).

The Sharing package scalar is used to indicate whether the package is available for Share Package On Server jobs. The SMS API engine sets the Sharing package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package has the Server root and Share name scalars set. If the package will be used for network applications, your application must also create program item subfolders for each network application within the package.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For a package to be available for Share Package On Server jobs, the following scalars must be set:

Scalar name | Data type | Requirement
Name | String | Required.
Comment | String | Optional.
Sharing package | Integer | Required. The SMS API engine sets this scalar to TRUE if the package has the Server root and Share name scalars set. When this scalar is set to TRUE, this package will be available for Share Package On Server jobs. If this scalar is set to FALSE, this package will not be available for Share Package On Server jobs.
Server root | String | Required.
Share name | String | Required.
Share permissions | Integer | Required.


Creating a Package for Inventory

To create a package (F_PACKAGE) that can be used for inventory, some scalars must have valid values (such as the Name scalar). Other scalars are optional (such as Comment) or are set and used only by the SMS system (such as Key).

The Inventory package scalar is used to indicate whether the SMS system scans for the package on all SMS computers at the current site and all sites below the current site in the site hierarchy. The SMS API engine sets the Inventory package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package folder has an inventory rules subfolder and the Inventory this package scalar for the Inventory rules subfolder is set to TRUE.

Note that Required means that a valid value must be set. For more information about the range of valid values for a scalar, click on the scalar name in the following table. Your application is responsible for verifying that the value it sets for a scalar is valid.

For a package to be available for inventory, the following scalars must be set in the package folder:

Scalar name | Data type | Requirement
Name | String | Required.
Comment | String | Optional.
Inventory package | Integer | Required. The SMS API engine sets this scalar to TRUE if the package has an Inventory rules subfolder and the Inventory this package scalar for the Inventory rules subfolder is set to TRUE. When this scalar is set to TRUE, this package will be available for inventory. If this scalar is set to FALSE, this package will not be available for inventory.

In addition, the following scalar must be set in the inventory rules folder:

Scalar name | Data type | Requirement
Inventory this package | Integer | Required.


Deleting Folders

The following folder types support deletion:

F_INSTALLJOB

F_INVENTORY

F_PACKAGE

F_PROGITEM

F_REMPKGJOB

F_SRVINSTALL

F_WCL

When your application deletes a folder, it must first call SmsUnlinkFolder to unlink the folder from its parent (within the application's memory) and call SmsCommitFolder to delete the folder from the site database.

SmsUnlinkFolder removes the specified folder from the parent's folder list within your application's memory. An unlinked folder is not deleted from the site database until your application uses the SmsCommitFolder function to remove the folder from the database.

Note Before an F_PACKAGE folder is deleted, each of its subfolders (F_WCL, F_PROGITEM, and F_INVENTORY) must be unlinked and committed first. In addition, in order to delete F_WCL, F_PROGITEM, and F_INVENTORY folders, you must delete the F_PACKAGE folder that contains them, as well as all subfolders within it. Note that F_WCL, F_PROGITEM, and F_INVENTORY folders are not removed from the site database until their parent folder is unlinked and committed. When an unlinked F_WCL, F_PROGITEM, or F_INVENTORY folder is committed, the SmsCommitFolder function returns SMS_PARENT_NEEDS_COMMIT.


Scalars

A scalar is the value stored for an attribute of a folder. For example, the folder for a site contains scalars for site name, parent site, depth, status, site type, and detailed status. The folder for a specific site would have a specific value for each scalar. For example, the folder for the TIM site could contain the string "Tim World" for site name.

In addition to a value, each scalar also contains a name, a data type, and an access mode.

The set of scalars that a folder can contain is determined by the type of the folder. Except for group folders, the set of scalars for all folder types is predetermined by the SMS API. For example, all site folders always contain the same set of scalars; however, the values for those scalars will differ between each instance of a site folder.

Group folders contain scalars that represent attributes for an inventoried item. However, there is no defined set of scalars for group folders in general. The set of scalars within a group folder depends on its group class. The set of scalars within a group folder are also dependent on the instance of the group—all attributes defined for the group may not have been included by the MIF that reported the inventory. Indeed, different instances of the same group may contain completely different sets of attributes. Your application can retrieve the list of scalars within a folder by using the SmsGetNextScalar function to retrieve each scalar sequentially.

For more information about accessing containers, folders, and scalars, see General Steps for Using the SMS API to Manage SMS Objects.

Note that scalars can also read from persistent filters. Scalars can be set on machine filters that will be committed to the site database as persistent filters in a filter container.

For more information about handling persistent filters, see General Steps for Using the SMS API to Manage Queries.


Scalar Properties

Using SmsDescribeFolder, your application can retrieve information about the scalars for an individual folder type. The SmsDescribeFolder function enables your application to retrieve information about an individual folder type. The properties for the specified folder type are stored in a FOLDER_INFO structure.

Within the FOLDER_INFO structure, the following members provide information about the scalars within the specified folder type:

ctScalars
Specifies the number of scalars that the specified folder supports.
pScalars
Points to an array of SCALAR_INFO structures that describe the scalars supported by the folder.

By accessing the members of the SCALAR_INFO structure, your application can get the following information about the scalar:

szName
Specifies the name of the scalar. The string has the length specified by BUFF_SIZE.
scType
Specifies a SCALARTYPE enumerated type that indicates the type of the scalar.
fAccess
Specifies the access rights of the scalar. See Access Rights.

Note that the access right of each scalar is set by the SMS API engine—your application can read the access right of a scalar but it cannot set the access right.

To set the value of a scalar, both the scalar and its folder must have an access right of ACCESS_MODIFY or ACCESS_CREATE. If you do not have ACCESS_MODIFY or ACCESS_CREATE right to the scalar, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

To read a scalar, the scalar must have an access right of ACCESS_READ.


Domain Folder Scalars

A domain folder contains one scalar that represents the site code for the site that it is part of.

Site code
String. Read-only access. Three-character site code for the site that the domain is part of.


Inventory Rules Folder Scalars

An inventory rules folder contains a single scalar that stores information about the package's availablity for inventory. Inventory rules folder scalars have both create and read access. Therefore, an application can create an inventory rules folder.

An inventory rules folder has the following scalar:

Inventory this package
Integer. Create access. A flag that specifies that the package be included in the SMS software inventory, using the rule defined by the tokens in the inventory rules folder. TRUE specifies that the package is included in the inventory. FALSE specifies that the package is not included in the inventory.

The Inventory this package scalar is used by the SMS API engine to determine whether to set the Inventory package scalar for the package folder that contains the inventory rule folder. Note that the SMS API engine will set the Inventory package scalar for a package folder to TRUE only if the following conditions are met:

  • Inventory this package scalar is set to TRUE.
  • The inventory rules folder contains at least one expression token.


Machine Group Folder Scalars

A machine group folder contains a set of scalars that store information about the machine group. Machine group folder scalars have read-only access. Therefore, an application cannot create a machine group folder.

A machine group folder has the following scalars:

Name
String. Read-only access. Name of the machine group. This is the alias you can use to refer to the set of computers defined in the machine group. The name is not case-sensitive. Spaces are allowed.
Comment
String. Read-only access. Text that contains any comments used to describe the machine group.


MIF Group Folder Scalars

A MIF group folder contains scalars that represent the actual properties (or attributes) of the group. Each attribute is assigned a value. The set of attribute values for a group makes up the inventory for a specific item. For example, a Disk group on a computer has attributes such as Drive Index, Storage Type, Free Storage, and so on. In a workstation's inventory, a Disk's Drive Letter attribute can be assigned a value such as A, B, C, and so on.

LastChanged is the only defined scalar for MIF group folders (see description below). The set of scalars within a group folder depends on its group class.

The set of scalars within a group folder is also dependent on the instance of the group—all attributes defined for the group may not have been included by the MIF that reported the inventory. Indeed, different instances of the same group may contain completely different sets of attributes.

Your application can retrieve the list of scalars within a specific folder by using the SmsGetNextScalar function to retrieve each scalar sequentially.

A MIF group folder has the following scalar:

LastChanged
Time. Read-only access. The time that any scalar in the MIF group was last changed. This could be the time of creation or subsequent modification. LastChanged is a read-only system scalar and will not be recognized if specified as a scalar when creating a MIF group folder.


Package Folder Scalars

A package folder contains a set of scalars that store information about the package. Package folder scalars have both create and read access. Therefore, an application can create a package folder.

A package folder has the following scalars:

Key
String. Read-only access. Unique identifier for the package. The SMS system assigns the job a unique eight-character job identifier based on the site code (first three characters) and five characters (last five characters).
Name
String. Create access. Name for the package. This scalar is required for committing the package folder to the site database.

Give the package a descriptive name, such as the name of the application. When you create a Run Command On Workstation job to install this package on computers, this name appears as the package's description in the Package Command Manager at the target computers.

Comment
String. Create access. Text to further describe the package.

For a Run Command On Workstation job, the comment text is displayed to the user in the Details dialog box of the Package Command Manager. The Comment text can be used to display a short description of instructions for the applications (or command line) provided by the package.

For Share Package On Server jobs, the comment is not used.

Workstation root
String. The network path to the shared directory where the files for the Workstations properties are located. This scalar is required for the package to be available for Run Command On Workstation jobs.

You can specify the universal naming convention (UNC) share name or a redirected drive name. Note that SMS resolves the redirected drive to its UNC path. For example, a UNC path could be \\APPSVR\WINSHARE\EXCEL. Or if drive K: is connected to \\APPSVR\WINSHARE, you could specify K:\EXCEL as the source directory, unless the SMS Scheduler is on another server. If the Scheduler is not on the site server, use the UNC path to specify the source directory.

Important Your application is responsible for verifying that the Workstation root scalar contains a valid path to the source directory for Workstation properties. The Scheduler will use the directory specified by the Workstation root scalar as the location for the files to be distributed with Run Command On Workstation jobs that use the package.

Server root
String. The network path to the shared directory where the files for the sharing properties are located. This scalar is required for the package to be available for Share Package On Server jobs.

You can specify the universal naming convention (UNC) share name or a redirected drive name. (See the preceding entry, "Workstation root.")

Important Your application is responsible for verifying that the Server root scalar contains a valid path to the source directory for Sharing properties. The Scheduler will use the directory specified by the Server root scalar as the location for the files to be distributed with Share Package On Server jobs that use the package.

Share name
String. Create access. The share name that you want to assign to the shared package when it is installed on a server. This scalar is required for the package to be available for Share Package On Server jobs.

At each target server (specified by the Share Package On Server job), this share name is set for the directory that contains the shared version of the package. The share name can be no longer than eight characters, but subdirectories can have longer names.

For example, if you specify FRISBEE\TESTGROUP as the share name, the Despooler creates the root directory FRISBEE (if it does not already exist) and shares it as FRISBEE. It also creates the subdirectory TESTGROUP and places the shared package in the directory FRISBEE\TESTGROUP. If the FRISBEE directory already exists, the Despooler creates the directory FRISBEE00\TESTGROUP. You can specify an unlimited number of subdirectories in the share name.

Note that the Despooler creates the package share on the server drive with the most free space.

Note If you are setting up a package for sharing on a NetWare server, you must specify a volume name and a subdirectory as the share name.

Share permissions
Integer. The permissions for users to access the package's shared directory that you specified in the Share name scalar. By default, all four available permission settings are set.

You can assign permissions to two user groups: Users and Guests. Users is the Domain Users global group (for LAN Manager domains, Users is the Users group) for the domains at each target site. Guests is the Guests global group, which can contain user accounts not defined in the domain, or a set of user accounts in the domain that is part of the Guests group. For NetWare domains, Users is equivalent to the default group EVERYONE and Guests applies to default user GUEST.

PACKAGE_USER_READ
Permits users in the Domain Users, Users, or EVERYONE group to read and copy files, run programs, change directories within the shared directory, and read extended attributes of files.

To run a program file (one with a .COM, .EXE, or .BAT extension), a user must have read permission.

PACKAGE_USER_WRITE
Permits users in the Domain Users, Users, or EVERYONE group to write the contents and extended attributes of files.

Write permission is required for applications that need to write information back to the shared package directory.

PACKAGE_GUEST_READ
Permits users in the Guests or GUEST group to read and copy files, run programs, change directories within the shared directory, and read extended attributes of files.

To run a program file (one with a .COM, .EXE, or .BAT extension), a user must have read permission.

PACKAGE_GUEST_WRITE
Permits users in the Guests or GUEST group to write the contents and extended attributes of files.

Write permission is required for applications that need to write information back to the shared package directory.

Workstation permissions
Integer. The permissions for users to access the package's shared directory on distribution servers for the package source directory for Run Command On Workstation jobs. By default, all four available permission settings are set.

You can assign permissions to two user groups: Users and Guests. Users is the Domain Users global group (for LAN Manager domains, Users is the Users group) for the domains at each target site. Guests is the Guests global group, which can contain user accounts not defined in the domain or a set of user accounts in the domain that is part of the Guests group. For NetWare domains, Users is equivalent to the default group EVERYONE and Guests applies to default user GUEST.

PACKAGE_USER_READ
Permits users in the Domain Users, Users, or EVERYONE group to read and copy files, run programs, change directories within the shared directory, and read extended attributes of files.

To run a program file (one with a .COM, .EXE, or .BAT extension), a user must have read permission.

PACKAGE_USER_WRITE
Permits users in the Domain Users, Users, or EVERYONE group to write the contents and extended attributes of files.

Write permission is required for applications that need to write information back to the shared package directory.

PACKAGE_GUEST_READ
Permits users in the Guests or GUEST group to read and copy files, run programs, change directories within the shared directory, and read extended attributes of files.

To run a program file (one with a .COM, .EXE, or .BAT extension), a user must have read permission.

PACKAGE_GUEST_WRITE
Permits users in the Guests or GUEST group to write the contents and extended attributes of files.

Write permission is required for applications that need to write information back to the shared package directory.

Workstation package
Integer. Read-only access. This scalar specifies that the package has Workstations properties set and that the package is available for Run Command On Workstation jobs. TRUE specifies availablility for Run Command On Workstation jobs. FALSE specifies no availability.

The SMS API engine sets the Workstation package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package has at least one Workstation Command Line subfolder and has the Workstation root scalar set.

Sharing package
Integer. Read-only access. This scalar specifies that the package has Sharing properties set and that the package is available for Share Package On Server jobs. TRUE specifies availablility for Share Package On Server. FALSE specifies no availability.

The SMS API engine sets the Sharing package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package has the Server root and Share name scalars set. If the package will be used for network applications, your application must also create program item subfolders for each network application within the package.

Inventory package
Integer. Read-only access. This scalar specifies that the package has Inventory properties set and that the package will be inventoried at the current site and all its subsites. TRUE specifies that inventory rules for the package have been set and the SMS system will scan for this package in its software scan. FALSE specifies no availability.

The SMS API engine sets the Inventory package scalar when the package is created. The SMS API engine sets this scalar to TRUE if the package folder has an inventory rules subfolder and the Inventory this package scalar for the Inventory rules subfolder is set to TRUE.

Workstation transfer file
String. Read-only access. The file name and UNC path to the compressed package file for the package when it is used for Run Command On Workstation jobs.

After the job's activation time has elapsed, the Scheduler starts the job by creating a compressed package file (packageid.W* where packageid is the eight-character package identifier for the package used by the job) that contains all directories and files specified by the package's source directory (Workstation root scalar). The packageid.W* file is placed in the SITE.SRV\SENDER.BOX\TOSEND directory in the SMS root directory of the computer where the Scheduler is installed (usually the site server).

Server transfer file
String. Read-only access. The file name and UNC path to the compressed package file for a package used for Share Package On Server jobs.

After the job's activation time has elapsed, the Scheduler starts the job by creating a compressed package file (packageid.S* where packageid is the eight-character package identifier for the package used by the job) that contains all directories and files specified by the package's source directory (Server root scalar). The packageid.S* file is placed in the SITE.SRV\SENDER.BOX\TOSEND directory in the SMS root directory of the computer where the Scheduler is installed (usually, the site server).


Program Item Folder Scalars

A program item folder contains a set of scalars that store information about the program item. Program item folder scalars have both create and read access. Therefore, an application can create a program item folder.

A program item folder has the following scalars:

ItemKey
String. Read-only access. An eight-character identifier that the SMS system assigns to the program item. Note that the first three characters are the site code for the site where the program item was created.
Description
String. Modify access. The text that will be used at SMS computers to describe the network application's program item. Maximum length is 64 characters.

At Windows and Windows NT computers where this network application is available, this text is used for the application's program item in the Program Manager and for its icon when the icon is minimized on the desktop.

For example, you could specify the name of the application, such as "Microsoft Excel version 5.0."

Command line
String. Modify access. The command that will be used to start the network application. The command line has a limit of 255 characters and cannot include commas.

Specify the file name of the application; the extension is optional. (For example, WINWORD.EXE, WINWORD, VPPROF.BAT, and VPROF will all work.) You can also specify a text editor and a file together, such as NOTEPAD README.TXT.

The command line is run from the package's root directory, which is located on a shared directory on a server.

Run minimized
Integer. Modify access. A flag that specifies that the application should be minimized to an icon each time it starts. TRUE specifies that the application starts as a minimized icon. FALSE specifies that the application runs at its normal window size.
Icon
Binary. Modify access. An icon resource that will be used as the icon for the program item in the client's program group in the Program Manager, and when the network application represented by the program item is minimized. The icon will automatically be distributed to clients that use the network application. The binary data for the Icon scalar has the same format as an icon resource file (.ICO). For information about the Icon binary scalar, see Example of Retrieving a SCALAR_BINARY Scalar and Example of Setting a SCALAR_BINARY Scalar.
Platforms
Integer. Modify access. Flags that specify the supported operating systems and processors. You can select one or more operating systems.

Caution Your application must set at least one platform flag for the Platform flags scalar. If your application does not set a platform flag, the program item will not be available for program groups. To correct this problem, your application must delete the program item folder and re-create the folder with the Platform flag scalar set correctly.

When a platform flag is set, the network application is available as a program item at computers with the specified platform. When a platform flag is not set for a specific operating system or processor type, the network application is not available to computers with the specified platform—no program item is created and the application is not configured to run on that computer.

PLTFRM_WIN16
Windows version 3.1
PLTFRM_WIN95
Windows 95
PLTFRM_WIN32_X86
Windows NT with x86 processor.
PLTFRM_WIN32_MIPS
Windows NT with MIPS processor.
PLTFRM_WIN32_ALPHA
Windows NT with Alpha processor.
Configure script file
String. Modify access. The command line used to configure the network application on a computer. The command line contains the configuration program and the parameters required to run a configuration script or configuration program. This scalar has a limit of 255 characters.

When a network application is first configured on a computer, the Program Group Control program can use a setup program or script to configure the registry and initialization files for the application so that it can run over the network.

This entry enables you to specify custom programs or scripts. For example, this line can call a setup program that reads an STF file or a Microsoft Test script. Before distributing the package, you must copy all setup programs and their data files to the package source directory.

If no configuration script or setup program is required, you can set this scalar to NULL.

If you are using a script, type the script processor command (such as MTRUN.EXE or WBRUN20.EXE) followed by the name of the configuration file or script. You can place the script processor in the package source directory.

Note In order for Program Group Control to identify and locate a default script processing program (such as wbrun20.exe, mtrun.exe, and SMSINST.EXE), you must specify the script processor by using .EXE as the part of the command when creating the package (for example, MTRUN.EXE ACCEL.MST).

All other files, including supplied PDFs, must be in the package source directory.

Search local flag
Integer. Modify access. A flag that specifies that Program Group Control should search the local directories in the computer's path for the file specified in the Command line scalar. TRUE specifies that the local path should be searched. FALSE specifies that the application is always run from a server.

When you set this scalar to TRUE, Program Group Control starts the local version if it finds one; otherwise, it starts the network version. When you set this scalar to FALSE, Program Group Control always runs the network version.

Drive letter
String. Modify access. The drive letter used to connect to a network application's share. The length of this scalar is one character.

When the Drive mode scalar is set to PI_DRIVEMODE_SPECIFIC_LETTER, Program Group Control must connect using the drive letter specified by the Drive letter scalar. If the specified drive is already used, Program Group Control displays a message box that asks if the user wants to use the next available drive. If the user clicks OK, Program Group Control selects the next available drive and continues the execution of the application. If the user clicks Cancel, Program Group Control terminates without starting the application.

Drive mode
Integer. A value that specifies how the Program Group Control program should connect to the network application's share. There are three options:
PI_DRIVEMODE_UNC
Specifies that Program Group Control must execute the application using a UNC name (such as \\server\share\exename.exe). No drive letter is connected to the application share.
PI_DRIVEMODE_ANY_LETTER
Specifies that Program Group Control must connect using a drive letter—but Program Group Control can use any available drive letter on the local client.
PI_DRIVEMODE_SPECIFIC_LETTER
Specifies that Program Group Control must connect using a specific drive letter (for example, T). If you set this flag, you must specify the drive letter in the Drive letter scalar.
Registry name
String. Modify access. The registry name for a network application to be used in the registry of the SMS computer where the application resides. The Registry name scalar has a limit of 50 characters.

If this entry is left blank, the SMS package identifier number (the site code plus the package number) is used as the registry name. You should specify a recognizable registry name.

Registry names enable an application script to call a dependent application by using its registry name. For example, a Word for Windows script can call an MSAPPS application by using the MSAPPS registry key specified in the program item created for MSAPPS.

Display Icon in Program Group
Integer. Modify access. A flag that specifies that the Program Group Control program creates an icon in the program group on the computer that has been assigned the network application. TRUE specifies that the program item appears as an icon in the program groups where the program item has been added. FALSE specifies that the program item does not appear as an icon.


Remove Package From Server Job Folder Scalars

A Remove Package From Server job folder contains a set of scalars that store information about the job. Remove Package From Server folder scalars have both create and read access. Therefore, an application can create a Remove Package From Server job folder.

A Remove Package From Server job folder has the following scalars:

Job ID
String. Read-only access. Unique identifier for the job. The SMS system assigns the job a unique eight-character Job ID based on the site code (first three characters) and five characters (last five characters).
Job type
String. Read-only access. The type of job. For the F_REMPKGJOB folder, the Job type is always "microsoft\SMS\remove_package".
Job comment
String. Modify access. Text that describes the job. This text is viewed only by administrators of the SMS system. You can use this field to save comments about the job for yourself or other SMS administrators. You may want to include the package name, job target, or other information that helps you identify the job. Maximum length is 255 characters.
Activate time
Time. Create access. The time when you want SMS to activate the job.

The time specifies the date and time after which the Scheduler activates the job and begins sending the job to the target sites. Note that the Scheduler uses the SQL Server time to evaluate the activation time. Also note that this time is written directly to the site database, that is, no time zone conversion is done.

Left icon
String. Read-only access. A string that sets the left icon for the job in the Jobs window of the SMS Administrator.
Center icon
String. Read-only access. A string that sets the middle icon for the job in the Jobs window of the SMS Administrator.
Right icon
String. Read-only access. A string that sets the right icon for the job in the Jobs window of the SMS Administrator.
Priority
Integer. Modify access. Priority setting that you want the job to have relative to other jobs when being sent to target sites.

The priority setting is used to ensure that higher priority jobs are sent before lower priority jobs. A High priority tells the Scheduler to send the job to a target site before any other jobs with a lower priority.

For example, if a Sender is sending a Medium or Low priority job and the Sender detects a High priority job in one of its outboxes, the Sender will suspend the sending of the lower priority job and send the High priority job first. After the High priority job has completed, the Sender will resume sending the lower priority job that was suspended.

In addition, an outbox can be set to process all jobs, only higher priority jobs, or no jobs at specified days and times.

High has priority over Medium and Low; Medium has priority over Low.

JOBPRI_HIGH
High
JOBPRI_MEDIUM
Medium
JOBPRI_LOW
Low
Repeat mode
Integer. Modify access. Interval at which the job is repeated.

The intervals range from Daily (every 24 hours after the Activate time) to Monthly. The interval is based on the SMS system time. A repeated job generates a new job each time that interval elapses.

JOBRPT_NEVER
Never. Perform the job once.
JOBRPT_DAILY
Daily. Repeat every 24 hours after the Activate time.
JOBRPT_WEEKLY
Weekly. Repeat every 7 days after the Activate time.
JOBRPT_BIWEEKLY
Biweekly. Repeat every 14 days after the Activate time.
JOBRPT_MONTHLY
Monthly. Repeat every month.
Cancel mode
Integer. Modify access. When Cancel mode is set to JOBCANCEL_CANCEL, the SMS system attempts to cancel the job. Any other values for this scalar have no effect.
JOBCANCEL_DONT_CANCEL
Do not cancel the job.
JOBCANCEL_CANCEL
Cancel the job.
Package ID
String. Modify access. The package identifier for the package to remove. The package identifier is an eight-character identifier that the SMS system assigns to a package. Note that the first three characters are the site code for the site where the package was created.

Caution If your application is creating a Remove Package From Server job, your application must ensure that this scalar is set to a valid package identifier. Your application can get the package identifier through the package's folder in a populated package container.

Limit to sites
Integer. Modify access. Option that narrows down the job target to a site or site group.
JOBTGT_NOSITELIMIT
Specifies that the job target should be the current site and all sites beneath the current site.
JOBTGT_SITEGROUP
Enables your application to narrow down the job target to the sites in a site group.

When using this option, your application must also set Site limit name scalar to specify the site group to use.

JOBTGT_SITE
Enables your application to narrow down the job target to a specific site.

When using this option, your application must also set Site limit name scalar to specify the site to use.

Include subsites
Integer. Modify access. Option that specifies how a job is propagated to the subsites of the sites that you specified by Site limit name scalar. This scalar applies only if the Limit to sites scalar is set to JOBTGT_SITEGROUP or JOBTGT_SITE.
JOBTGT_NOSUBSITES
Specifies that only the sites specified in the Site limit name scalar are used.
JOBTGT_INCLUDESUBSITES
Enables your application to specify that the job target includes the subsites of the sites that you specfied in the Site limit name scalar.
Site limit name
String. Modify access. The name of the site or site group to which to limit the job target. This scalar applies only if the Limit to sites scalar is set to JOBTGT_SITEGROUP or JOBTGT_SITE.

If Limit to sites is set to JOBTGT_SITE, the Site limit name scalar specifies the name of the site to which to limit the job target.

If Limit to sites is set to JOBTGT_SITEGROUP, the Site limit name scalar specifies the name of the site group to which to limit the job target.

If the Include subsites scalar is set to JOBTGT_INCLUDESUBSITES, the job target is limited to the specified site or site group and its subsites.

Caution When creating a job, your application must ensure that this scalar is set to a valid site or site group name. Your application can get the site name through the site's site folder in a populated site container. Your application can get the site group name through the site group's site group folder in a populated site group container.

Package type
Integer. Modify access. Type of package to remove (Workstations or Sharing). You can select a single type or both.
RMPKGJOB_PKGTYPE_WKSTA
Specifies the package source directory defined by the package's Workstations properties. This is the package source directory that has been sent or distributed by a Run Command On Workstation job.
RMPKGJOB_PKGTYPE_SERVER
Specifies the package source directory defined by the package's Sharing properties. This is the package source directory that has been sent or distributed by a Share Package On Server job.
RMPKGJOB_PKGTYPE_BOTH
Specifies the package source directory for both types of packages: RMPKGJOB_PKGTYPE_WKSTA and RMPKGJOB_PKGTYPE_SERVER.
Job tasks
Integer. Modify access. Method used to specify the distribution servers where the package source directory will be removed. For the sharing version of a package, the package directory will be removed from these servers based on the share name that was set for the package. There are two methods for specifying the distribution servers. Your application can select one method.
RMPKGJOB_TASKS_RM_ALL
Removes the uncompressed version of the package from all distribution servers where the package source directory exists. This option also removes the compressed package from the site server in each target site.
RMPKGJOB_TASKS_RM_SELECTED
Removes the uncompressed package from the distribution servers specified by the Distribution servers scalar.

When the job is carried out, SMS removes the package from the specified distribution servers. If RMPKGJOB_TASKS_RM_ALL is set, the compressed files are also removed from the site server in each target site.

Distribution servers
String. Modify access. The name of the machine group that contains the distribution servers from which to remove the package.

When the Job tasks scalar is set to RMPKGJOB_TASKS_RM_SELECTED, this machine group specifies the distribution servers for the job.

To specify the Default Servers group, your application must set the Job tasks scalar to RMPKGJOB_TASKS_RM_SELECTED, and set the Distribution servers scalar to NULL. Default Servers is a special machine group created at each site (Default Servers are maintained using the Site Properties dialog box in the SMS Administrator). If default servers are used as distribution servers at a target site, the SMS Scheduler (at the site where the job is created) builds the list of target distribution servers for the target sites. Note that the list of default servers is read from the site database of the site where the job was created. This means that the default servers on the list are the default servers that were last reported to the site where the job was created.

Caution When creating a job, your application must ensure that this scalar is set to a valid machine group name or set to NULL (NULL specifies the Default Servers group). Your application can get the machine group name through the machine group's folder in a populated machine group container.

Job status
Integer. Indicates the overall status of the job across all target sites. There are six overall job states:
JOBSTAT_PENDING
Pending. Indicates that the job has not started and that the Scheduler is waiting to activate the job. When a job has this overall status, you can delete the job and prevent it from ever starting.
JOBSTAT_ACTIVE
Active. Indicates that the Scheduler has started the job and that SMS is currently carrying out the job without errors. The job may be complete or may still be in progress at the target sites or computers.
JOBSTAT_ACTIVE_FAILED
Retrying. Indicates that the job has failed at some target sites or target computers; however, SMS continues to attempt to complete the job at those sites or computers. The job may be complete or may still be in progress at other target sites or computers.
JOBSTAT_COMPLETE
Complete. Indicates that the job successfully completed its tasks at all target computers at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.

For Remove Package From Server jobs, the overall status becomes complete when the package has been successfully removed from all specified distribution servers.

JOBSTAT_CANCELLED
Canceled. Indicates that the job was successfully canceled at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.
JOBSTAT_FAILED
Failed. Indicates that the job has failed at some or all target sites or target computers and that SMS has stopped trying to complete the job. The job may have completed successfully at some target sites or computers. You can note the job identifier and check the event log to determine why the job failed.
Sending status
Integer. Read-only access. Indicates the status for sending the job's package and instructions to all target sites:
0
Indicates that a Sender has not processed the job's send request (the Scheduler has not created a *.SRQ file yet).
JOBSTAT_PENDING
Indicates that the send requests for the job have been placed in Sender outboxes but that the Senders have not started to send the job package and instructions to the target sites. The Senders may not have detected the send requests for the job yet.
JOBSTAT_ACTIVE
Indicates that one or more Senders are in the process of sending the job package and instructions to the target sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that at least one Sender has failed at an attempt to send the job to a target site; however, the Senders continue to attempt to send the job to the sites. You can note the job identifier and check the event log to determine why the job failed.
JOBSTAT_COMPLETE
Indicates that the Senders successfully sent the job package and instructions to all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled before it was sent to the target sites.
JOBSTAT_FAILED
Indicates that one or more Senders have failed to send the job to one or more target sites and that they have stopped trying to send the job to those sites.
Working status
Integer. Read-only access. Indicates the job's progress at all target sites:
JOBSTAT_PENDING
Indicates that no target site has received the job package and instructions yet.
JOBSTAT_ACTIVE
Indicates that the one or more target sites have received the package and are in the process of carrying out the job at those sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that the job has failed at one or more target computers at the target sites; however, the site components continue to attempt to complete the job at the target computers.
JOBSTAT_COMPLETE
Indicates that the job successfully completed at all target computers at all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled at all computers at all target sites.
JOBSTAT_FAILED
Indicates that the job has failed at some or all target computers at one or more target sites and that the site components have stopped trying to complete the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.
Cancel status
Integer. Read-only access. Indicates how SMS has progressed in canceling the job:
None
Indicates that the job has not been canceled.
JOBSTAT_PENDING
Indicates that the target sites have not received the instructions to cancel the job yet.
JOBSTAT_ACTIVE
Indicates that one or more target sites have received the cancel instructions and are in the process of canceling the job at those sites (without errors), but have not completed the cancellation.
JOBSTAT_ACTIVE_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites; however, the site components continue to attempt to cancel the job at those target computers.
JOBSTAT_COMPLETE
Indicates that the job was successfully canceled at all target computers at all target sites.
JOBSTAT_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites and that the site components have stopped trying to cancel the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.


Run Command On Workstation Job Folder Scalars

A Run Command On Workstation job folder contains a set of scalars that store information about the job. The scalars for Run Command On Workstation folders have both create and read access. Therefore, an application can create a Run Command On Workstation job folder.

A Run Command On Workstation job folder has the following scalars:

Job ID
String. Read-only access. Unique identifier for the job. The SMS system assigns the job a unique eight-character Job ID based on the site code (first three characters) and five characters (last five characters).
Job type
String. Read-only access. The type of job. For the F_INSTALLJOB folder, the Job type is always "microsoft\SMS\workstation_script".
Job comment
String. Modify access. Text that describes the job. This text is viewed only by administrators of the SMS system. You can use this field to save comments about the job for yourself or other SMS administrators. You may want to include the package name, job target, or other information that helps you identify the job. Maximum length is 255 characters.
Activate time
Time. Create access. The time when you want SMS to activate the job.

The time specifies the date and time after which the Scheduler activates the job and begins sending the job to the target sites. Note that the Scheduler uses the SQL Server time to evaluate the activation time. Also note that this time is written directly to the site database, that is, no time zone conversion is done.

Left icon
String. Read-only access. A string that sets the left icon for the job in the Jobs window of the SMS Administrator.
Center icon
String. Read-only access. A string that sets the middle icon for the job in the Jobs window of the SMS Administrator.
Right icon
String. Read-only access. A string that sets the right icon for the job in the Jobs window of the SMS Administrator.
Priority
Integer. Modify access. Priority setting that you want the job to have relative to other jobs when being sent to target sites.

The priority setting is used to ensure that higher priority jobs are sent before lower priority jobs. A High priority tells the Scheduler to send the job to a target site before any other jobs with a lower priority.

For example, if a Sender is sending a Medium or Low priority job and the Sender detects a High priority job in one of its outboxes, the Sender will suspend the sending of the lower priority job and send the High priority job first. After the High priority job has completed, the Sender will resume sending the lower priority job that was suspended.

In addition, an outbox can be set to process all jobs, only higher priority jobs, or no jobs at specified days and times.

High has priority over Medium and Low; Medium has priority over Low.

JOBPRI_HIGH
High
JOBPRI_MEDIUM
Medium
JOBPRI_LOW
Low
Repeat mode
Integer. Modify access. Interval at which the job is repeated.

The intervals range from Daily (every 24 hours after the Activate time) to Monthly. The interval is based on the SMS system time. A repeated job generates a new job each time that interval elapses.

JOBRPT_NEVER
Never. Perform the job once.
JOBRPT_DAILY
Daily. Repeat every 24 hours after the Activate time.
JOBRPT_WEEKLY
Weekly. Repeat every 7 days after the Activate time.
JOBRPT_BIWEEKLY
Biweekly. Repeat every 14 days after the Activate time.
JOBRPT_MONTHLY
Monthly. Repeat every month.
Cancel mode
Integer. Modify access. When Cancel mode is set to JOBCANCEL_CANCEL, the SMS system attempts to cancel the job. Any other value for this scalar has no effect.
JOBCANCEL_DONT_CANCEL
Do not cancel the job.
JOBCANCEL_CANCEL
Cancel the job.
Package ID
String. Modify access. The package identifier for the package used for the job. The package identifier is an eight-character identifier that the SMS system assigns to a package. Note that the first three characters are the site code for the site where the package was created.

Caution If your application is creating a Run Command On Workstation job, your application must ensure that this scalar is set to a valid package identifier. Your application can get the package identifier through the package's folder in a populated package container.

In addition, the Package identifier must be a package identifier for a package that has Workstations properties defined. For the set of scalars required for this type of package, see Creating a Package for Run Command On Workstation Jobs.

Your application must also specify for the WCL name scalar a workstation command line from this package only. Your application can get the workstation command lines for a package by retrieving the F_WCL folders in the package's folder.

Job target
Integer. Modify access. Method used to specify the computers where you want to run the package command. There are three ways to specify the target computers:
WKSTAJOB_TGT_QUERY
Specifies that the list of target computers is defined by the result of a query that is run when the job is activated.

When using this option, your application must also set the Query ID scalar to specify the query to use.

WKSTAJOB_TGT_MACHGROUP
Specifies that the list of target computers is defined by a machine group.

When using this option, your application must also set the Machine group name scalar to specify the machine group to use.

WKSTAJOB_TGT_MACHPATH
Specifies that the list of target computers is defined by a specified path.

When using this option, your application must also set the Machine path scalar to specify the path to use.

Note The actual job target computers are determined at the time the Scheduler activates the job. To see the actual target computers at each target site, look at the computers listed by machine folders with architecture JobDetails and with a Job ID scalar value equal to the job identifier of the job.

Query ID
String. Modify access. When WKSTAJOB_TGT_QUERY is set for the Job target scalar, Query ID specifies the identifier for the query whose results will be used to specify the target computers for the job. A query identifier is an eight-character identifier that the SMS system assigns to a query. Note that the first three characters are the site code for the site where the query was created.

Caution When creating a job, your application must ensure that this scalar is set to a valid query identifier. Your application can get the query identifier through the query's persistent filter in a populated filter container.

Machine group name
String. Modify access. When WKSTAJOB_TGT_MACHGROUP is set for the Job target scalar, Group name specifies the name of the machine group that will be used to specify the target computers for the job.

Caution When creating a job, your application must ensure that this scalar is set to a valid machine group name. Your application can get the machine group name through the machine group's folder in a populated machine group container.

Machine path
String. When WKSTAJOB_TGT_MACHPATH is set for the Job target scalar, Machine path specifies the target computers for the job by using an SMS system path.

The path has the following form:

site|domain|computername

You can use the * wildcard as a substitute for a whole group of sites, domains, or computer names.

For example, RED|FINANCE|* specifies all computers in the FINANCE domain at the Redmond site (with the site code RED), and RED|*|* specifies all computers in all domains at the Redmond site.

When you use a specific site for the Machine path scalar (such as RED|FINANCE|*), you can specify any of the domains and computers in that site, but you cannot specify any of the site's subsites.

To specify a site and its subsites, you must specify *|*|* for the Machine path scalar, set the Job target scalar to WKSTAJOB_TGT_MACHPATH, set the Limit to sites scalar to JOBTGT_SITE, set the Site limit name scalar to the site, and set the Include subsites scalar to JOBTGT_INCLUDESUBSITES.

To specify all computers at all sites, specify *|*|* for the Machine path scalar.

Limit to sites
Integer. Modify access. Option that narrows down the job target to only computers that satisfy both the job target and are within a particular site or site group.
JOBTGT_NOSITELIMIT
Specifies that the job target should be used with no site limiting.
JOBTGT_SITEGROUP
Enables your application to narrow down the job target to only computers that satisfy both the job target criteria and are within the sites in a site group.

When using this option, your application must also set the Site limit name scalar to specify the site group to use.

JOBTGT_SITE
Enables your application to narrow down the job target to only computers that satisfy both the job target criteria and are within a site.

When using this option, your application must also set the Site limit name scalar to specify the site to use.

Include subsites
Integer. Modify access. Option that specifies how a job is propagated to the subsites of the sites that you specified by Site limit name scalar. This scalar applies only if the Limit to sites scalar is set to JOBTGT_SITEGROUP or JOBTGT_SITE.
JOBTGT_NOSUBSITES
Specifies that only the sites specified by the Site limit name scalar are used.
JOBTGT_INCLUDESUBSITES
Enables your application to specify that the job target includes the subsites of the sites that you specfied in the Site limit name scalar.
Site limit name
String. Modify access. The name of the site or site group to which to limit the job target. This scalar applies only if the Limit to sites scalar is set to JOBTGT_SITEGROUP or JOBTGT_SITE.

If Limit to sites is set to JOBTGT_SITE, the Site limit name scalar specifies the name of the site to which to limit the job target.

If Limit to sites is set to JOBTGT_SITEGROUP, the Site limit name scalar specifies the name of the site group to which to limit the job target.

If the Include subsites scalar is set to JOBTGT_INCLUDESUBSITES, the job target is limited to the specified site or site group and its subsites.

Caution When creating a job, your application must ensure that this scalar is set to a valid site or site group name. Your application can get the site name through the site's site folder in a populated site container. Your application can get the site group name through the site group's site group folder in a populated site group container.

Send phase
Integer. Modify access. Method used to specify whether to send the package to target sites if those sites already have the package. There are two methods. You can select only one method.
WKSTAJOB_SEND_IF_NOT_SENT
Specifies that the package will be sent to the target sites only if SMS has not already sent the package to those sites.
WKSTAJOB_SEND_ALWAYS
Specifies that the package will be sent to all target sites even if those sites have already received the package. This selection causes the package to be recompressed (if it was previously sent). If you make a change to the package's source directory, you should set this flag.
Distribute phase
Integer. Modify access. Method used to specify the distribution servers where the compressed package is decompressed. The target computers will use one of the distribution servers to run the package command for the job. There are two methods for specifying the distribution servers. Your application can select one, both, or no method.
WKSTAJOB_DIST_EXISTING
Specifies that SMS overwrites the package source directory on the distribution servers where the package source directory already exists. The SMS system maintains a list of the locations where packages have been distributed.
WKSTAJOB_DIST_SPECIFIED
Specifies that SMS places the package source directory on the distribution servers specified by the machine group set in the Distribution servers scalar. If the machine group does not contain a server for a target site, the package source directory is placed on the servers in the Default Servers group at that target site.
Distribution servers
String. Modify access. The name of the machine group that contains the distribution servers on which to install the package.

When the Distribute phase scalar is set to WKSTAJOB_DIST_SPECIFIED, this machine group specifies the distributions servers for the job. If the machine group does not contain a server for a target site, the package source directory is placed on the servers in the Default Servers group at that target site.

To specify the Default Servers group, your application must set the Distribute phase scalar to WKSTAJOB_DIST_SPECIFIED, and set the Distribution servers scalar to NULL. Default Servers is a special machine group created at each site (Default Servers are maintained using the Site Properties dialog box in the SMS Administrator). If default servers are used as distribution servers at a target site, the SMS Scheduler (at the site where the job is created) builds the list of target distribution servers for the target sites. Note that the list of default servers is read from the site database of the site where the job was created. This means that the default servers on the list are the default servers that were last reported to the site where the job was created.

Caution When creating a job, your application must ensure that this scalar is set to a valid machine group name or set to NULL (NULL specifies the Default Servers group). Your application can get the machine group name through the machine group's folder in a populated machine group container.

Run workstation command
Integer. Modify access. This scalar specifies that the package command specified by WCL name scalar will be made available to the target computers for the job.

TRUE specifies that the package command will be made available at the target computers.

FALSE specifies that the job does not make a package command available to the target computers. You may want to set this scalar to FALSE if you only want to send the package to the site (where it is stored as a compressed package) or if you only want to place the package directory on distribution servers.

Note that if you set this scalar to TRUE and the Distribute phase scalar is set to NULL, the decompressed package is sent to default servers.

WCL name
String. Modify access. The name of the workstation command line for the package specified in the Package ID scalar.

When the user at a target computer chooses to run the package, the Package Command Manager executes this command line.

If the WCL name scalar is set to NULL, no package command is offered to the target computers. This is equivalent to clearing the Run Command check box in the Job Details dialog box for a Run Command On Workstation job in the SMS Administrator.

Offer time
Time. Modify access. The time after which the package command will be available on the target computers (that is, the time that the package appears in the computer's Package Command Manager).

When the time specified by the Offer time scalar expires at the target computer (according to the target computer's system time), the package appears in the Package Command Manager window.

Mandatory time
Time. Modify access. The time after which the package command will be mandatory on the target computers.

When the Use mandatory time scalar is set to TRUE, the package command will become mandatory after this date and time on the target computers.

Use mandatory time
Integer. Modify access. This scalar specifies that the package command to be run is mandatory. TRUE specifies mandatory. FALSE specifies optional. A mandatory package command is automatically started when the time specified by the Mandatory time scalar expires on the target computer.

When you set this scalar, use the Mandatory time scalar to set the time after which the Package Command Manager forces the package command to be executed—until that time the package command can be run optionally.

Force over slow link
Integer. Modify access. This scalar is used to ensure that a mandatory package is not forced to run across a slow communications link. TRUE specifies that the command will be run without regard for the speed of the link. FALSE specifies that the command will not be run across a slow link.

This flag can only be enabled when the Use mandatory time scalar is set to TRUE.

When the user logs on at the target computer, the Inventory Processor evaluates the link to the target computer's logon server. If the Force over slow link scalar is set to FALSE, and the link has a transmission rate that is slower than the rate specified with the Slow Networks Strategy setting (in the Inventory window of the Site Properties dialog box of the SMS Administrator), mandatory packages are not forced at the target computer.

Expire time
Time. Modify access. The time after which the package command will become unavailable (removed from the Package Command Manager window) at the target computers.

When you set the Use expire time scalar to TRUE, use the Expire time scalar to set the time when the package command is no longer available on the target computer.

Use expire time
Integer. Modify access. This scalar specifies that the package becomes unavailable (removed from the Package Command Manager window) at the target computers after the specified time. TRUE specifies that the package expires after the date specified by the Expire time scalar. FALSE specifies that the package is always available (never removed from the Package Command Manager window).

When you set this scalar to TRUE, use the Expire time scalar to set the time when the package command is no longer available on the target computer. When the time specified by the Expire time scalar expires at the target computer (according to the target computer's system time), the package is removed from the Package Command Manager window.

Job status
Integer. Read-only access. Indicates the overall status of the job across all target sites. There are six overall job states:
JOBSTAT_PENDING
Pending. Indicates that the job has not started and that the Scheduler is waiting to activate the job. When a job has this overall status, you can delete the job and prevent it from ever starting.
JOBSTAT_ACTIVE
Active. Indicates that the Scheduler has started the job and that SMS is currently carrying out the job without errors. The job may be complete or may still be in progress at the target sites or computers.
JOBSTAT_ACTIVE_FAILED
Retrying. Indicates that the job has failed at some target sites or target computers; however, SMS continues to attempt to complete the job at those sites or computers. The job may be complete or may still be in progress at other target sites or computers.
JOBSTAT_COMPLETE
Complete. Indicates that the job successfully completed its tasks at all target computers at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.

For Run Command On Workstation jobs, the overall status does not become Complete until every computer targeted in the job has successfully received the package and executed the job.

JOBSTAT_CANCELLED
Canceled. Indicates that the job was successfully canceled at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.
JOBSTAT_FAILED
Failed. Indicates that the job has failed at some or all target sites or target computers and that SMS has stopped trying to complete the job. The job may have completed successfully at some target sites or computers. You can note the job identifier and check the event log to determine why the job failed.
Sending status
Integer. Read-only access. Indicates the status for sending the job's package and instructions to all target sites:
None
Indicates that a Sender has not processed the job's send request (the Scheduler has not yet created a *.SRQ file).
JOBSTAT_PENDING
Indicates that the send requests for the job have been placed in Sender outboxes but that the Senders have not started to send the job package and instructions to the target sites. The Senders may not have detected the send requests for the job yet.
JOBSTAT_ACTIVE
Indicates that one or more Senders are in the process of sending the job package and instructions to the target sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that at least one Sender has failed at an attempt to send the job to a target site; however, the Senders continue to attempt to send the job to the sites. You can note the job identifier and check the event log to determine why the job failed.
JOBSTAT_COMPLETE
Indicates that the Senders successfully sent the job package and instructions to all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled before it was sent to the target sites.
JOBSTAT_FAILED
Indicates that one or more Senders have failed to send the job to one or more target sites and that they have stopped trying to send the job to those sites.
Working status
Integer. Read-only access. Indicates the job's progress at all target sites:
JOBSTAT_PENDING
Indicates that no target site has received the job package and instructions yet.
JOBSTAT_ACTIVE
Indicates that the one or more target sites have received the package and are in the process of carrying out the job at those sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that the job has failed at one or more target computers at the target sites; however, the site components continue to attempt to complete the job at the target computers.
JOBSTAT_COMPLETE
Indicates that the job successfully completed at all target computers at all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled at all computers at all target sites.
JOBSTAT_FAILED
Indicates that the job has failed at some or all target computers at one or more target sites and that the site components have stopped trying to complete the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.
Cancel status
Integer. Read-only access. Indicates how SMS has progressed in canceling the job:
None
Indicates that the job has not been canceled.
JOBSTAT_PENDING
Indicates that the target sites have not yet received the instructions to cancel the job.
JOBSTAT_ACTIVE
Indicates that one or more target sites have received the cancel instructions and are in the process of canceling the job at those sites (without errors), but have not completed the cancellation.
JOBSTAT_ACTIVE_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites; however, the site components continue to attempt to cancel the job at those target computers.
JOBSTAT_COMPLETE
Indicates that the job was successfully canceled at all target computers at all target sites.
JOBSTAT_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites and that the site components have stopped trying to cancel the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.


Share Package On Server Job Folder Scalars

A Share Package On Server job folder contains a set of scalars that store information about the job. Share Package On Server folder scalars have both create and read access. Therefore, an application can create a Share Package On Server job folder.

A Share Package On Server job folder has the following scalars:

Job ID
String. Read-only access. Unique identifier for the job. The SMS system assigns the job a unique eight-character Job ID based on the site code (first three characters) and five characters (last five characters).
Job type
String. Read-only access. The type of job. For the F_SRVINSTALLJOB folder, the Job type is always "microsoft\SMS\server_script".
Job comment
String. Modify access. Text that describes the job. This text is viewed only by administrators of the SMS system. You can use this field to save comments about the job for yourself or other SMS administrators. You may want to include the package name, job target, or other information that helps you identify the job. Maximum length is 255 characters.
Activate time
Time. Create access. The time when you want SMS to activate the job.

The time specifies the date and time after which the Scheduler activates the job and begins sending the job to the target sites. Note that the Scheduler uses the SQL Server time to evaluate the activation time. Also note that this time is written directly to the site database, that is, no time zone conversion is done.

Left icon
String. Read-only access. A string that sets the left icon for the job in the Jobs window of the SMS Administrator.
Center icon
String. Read-only access. A string that sets the middle icon for the job in the Jobs window of the SMS Administrator.
Right icon
String. Read-only access. A string that sets the right icon for the job in the Jobs window of the SMS Administrator.
Priority
Integer. Modify access. Priority setting that you want the job to have relative to other jobs when being sent to target sites.

The priority setting is used to ensure that higher priority jobs are sent before lower priority jobs. A High priority tells the Scheduler to send the job to a target site before any other jobs with a lower priority.

For example, if a Sender is sending a Medium or Low priority job and the Sender detects a High priority job in one of its outboxes, the Sender will suspend the sending of the lower priority job and send the High priority job first. After the High priority job has completed, the Sender will resume sending the lower priority job that was suspended.

In addition, an outbox can be set to process all jobs, only higher priority jobs, or no jobs at specified days and times.

High has priority over Medium and Low; Medium has priority over Low.

JOBPRI_HIGH
High
JOBPRI_MEDIUM
Medium
JOBPRI_LOW
Low
Repeat mode
Integer. Modify access. Interval at which the job is repeated.

The intervals range from Daily (every 24 hours after the Activate time) to Monthly. The interval is based on the SMS system time. A repeated job generates a new job each time that interval elapses.

JOBRPT_NEVER
Never. Perform the job once.
JOBRPT_DAILY
Daily. Repeat every 24 hours after the Activate time.
JOBRPT_WEEKLY
Weekly. Repeat every 7 days after the Activate time.
JOBRPT_BIWEEKLY
Biweekly. Repeat every 14 days after the Activate time.
JOBRPT_MONTHLY
Monthly. Repeat every month.
Cancel mode
Integer. Modify access. When Cancel mode is set to JOBCANCEL_CANCEL, the SMS system attempts to cancel the job. Any other values for this scalar have no effect.
JOBCANCEL_DONT_CANCEL
Do not cancel the job.
JOBCANCEL_CANCEL
Cancel the job.
Package ID
String. Modify access. The package identifier for the package used for the job. The package identifier is an eight-character identifier that the SMS system assigns to a package. Note that the first three characters are the site code for the site where the package was created.

Caution If your application is creating a Share Package On Server job, your application must ensure that this scalar is set to a valid package identifier. Your application can get the package identifier through the package's folder in a populated package container.

In addition, the Package ID must be a package identifier for a package that has Sharing properties defined. For the set of scalars required for this type of package, see Creating a Package for Share Package On Server Jobs.

Job status
Integer. Indicates the overall status of the job across all target sites. There are six overall job states:
JOBSTAT_PENDING
Pending. Indicates that the job has not started and that the Scheduler is waiting to activate the job. When a job has this overall status, you can delete the job and prevent it from ever starting.
JOBSTAT_ACTIVE
Active. Indicates that the Scheduler has started the job and that SMS is currently carrying out the job without errors. The job may be complete or may still be in progress at the target sites or computers.
JOBSTAT_ACTIVE_FAILED
Retrying. Indicates that the job has failed at some target sites or target computers; however, SMS continues to attempt to complete the job at those sites or computers. The job may be complete or may still be in progress at other target sites or computers.
JOBSTAT_COMPLETE
Complete. Indicates that the job successfully completed its tasks at all target computers at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.

For Share Package On Server jobs, the overall status becomes Complete when the package has been successfully distributed to all specified distribution servers.

JOBSTAT_CANCELLED
Canceled. Indicates that the job was successfully canceled at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.
JOBSTAT_FAILED
Failed. Indicates that the job has failed at some or all target sites or target computers and that SMS has stopped trying to complete the job. The job may have completed successfully at some target sites or computers. You can note the job identifier and check the event log to determine why the job failed.
Sending status
Integer. Read-only access. Indicates the status for sending the job's package and instructions to all target sites:
None
Indicates that a Sender has not processed the job's send request (the Scheduler has not yet created a *.SRQ file).
JOBSTAT_PENDING
Indicates that the send requests for the job have been placed in Sender outboxes but that the Senders have not started to send the job package and instructions to the target sites. The Senders may not have detected the send requests for the job yet.
JOBSTAT_ACTIVE
Indicates that one or more Senders are in the process of sending the job package and instructions to the target sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that at least one Sender has failed at an attempt to send the job to a target site; however, the Senders continue to attempt to send the job to the sites. You can note the job identifier and check the event log to determine why the job failed.
JOBSTAT_COMPLETE
Indicates that the Senders successfully sent the job package and instructions to all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled before it was sent to the target sites.
JOBSTAT_FAILED
Indicates that one or more Senders have failed to send the job to one or more target sites and that they have stopped trying to send the job to those sites.
Working status
Integer. Read-only access. Indicates the job's progress at all target sites:
JOBSTAT_PENDING
Indicates that no target site has received the job package and instructions yet.
JOBSTAT_ACTIVE
Indicates that the one or more target sites have received the package and are in the process of carrying out the job at those sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that the job has failed at one or more target computers at the target sites; however, the site components continue to attempt to complete the job at the target computers.
JOBSTAT_COMPLETE
Indicates that the job successfully completed at all target computers at all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled at all computers at all target sites.
JOBSTAT_FAILED
Indicates that the job has failed at some or all target computers at one or more target sites and that the site components have stopped trying to complete the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.
Cancel status
Integer. Read-only access. Indicates how SMS has progressed in canceling the job:
None
Indicates that the job has not been canceled.
JOBSTAT_PENDING
Indicates that the target sites have not received the instructions to cancel the job yet.
JOBSTAT_ACTIVE
Indicates that one or more target sites have received the cancel instructions and are in the process of canceling the job at those sites (without errors), but have not completed the cancellation.
JOBSTAT_ACTIVE_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites; however, the site components continue to attempt to cancel the job at those target computers.
JOBSTAT_COMPLETE
Indicates that the job was successfully canceled at all target computers at all target sites.
JOBSTAT_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites and that the site components have stopped trying to cancel the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.
Limit to sites
Integer. Modify access. Option that narrows down the job target to a site or site group.
JOBTGT_NOSITELIMIT
Specifies that the job target should be the current site and all sites beneath the current site.
JOBTGT_SITEGROUP
Enables your application to narrow down the job target to the sites in a site group.

When using this option, your application must also set the Site limit name scalar to specify the site group to use.

JOBTGT_SITE
Enables your application to narrow down the job target to a specific site.

When using this option, your application must also set the Site limit name scalar to specify the site to use.

Include subsites
Integer. Modify access. Option that specifies how a job is propagated to the subsites of the sites that you specified in the Site limit name scalar. This scalar applies only if the Limit to sites scalar is set to JOBTGT_SITEGROUP or JOBTGT_SITE.
JOBTGT_NOSUBSITES
Specifies that only the sites specified in the Site limit name scalar are used.
JOBTGT_INCLUDESUBSITES
Enables your application to specify that the job target includes the subsites of the sites that you specified in the Site limit name scalar.
Site limit name
String. Modify access. The name of the site or site group to which to limit the job target. This scalar applies only if the Limit to sites scalar is set to JOBTGT_SITEGROUP or JOBTGT_SITE.

If Limit to sites is set to JOBTGT_SITE, the Site limit name scalar specifies the name of the site to which to limit the job target.

If Limit to sites is set to JOBTGT_SITEGROUP, the Site limit name scalar specifies the name of the site group to which to limit the job target.

If the Include subsites scalar is set to JOBTGT_INCLUDESUBSITES, the job target is limited to the specified site or site group and its subsites.

Caution When creating a job, your application must ensure that this scalar is set to a valid site or site group name. Your application can get the site name through the site's site folder in a populated site container. Your application can get the site group name through the site group's site group folder in a populated site group container.

Send phase
Integer. Modify access. Method used to specify whether to send the package to target sites if those sites already have the package. There are two methods. You can select only one method.
SHAREJOB_SEND_IF_NOT_SENT
Specifies that the package will be sent to the target sites only if SMS has not already sent the package to those sites.
SHAREJOB_SEND_ALWAYS
Specifies that the package will be sent to all target sites, even if those sites already have received the package. This selection causes the package to be recompressed (if it was previously sent). If you make a change to the package's source directory, you should set this flag.
Distribute phase
Integer. Modify access. Method used to specify the distribution servers where the compressed package (Sharing version) is decompressed. The package directory will be shared from these servers using the share name and access permissions set for the package. There are two methods for specifying the distribution servers. Your application can select one, both, or no method.
SHAREJOB_DIST_EXISTING
Specifies that SMS overwrites the package source directory on the distribution servers where the package source directory already exists. The SMS system maintains a list of the locations where packages have been distributed.
SHAREJOB_DIST_SPECIFIED
Specifies that SMS places the package source directory on the distribution servers specified by the machine group set in the Distribution servers scalar. If the machine group does not contain a server for a target site, the package source directory is placed on the servers in the Default Servers group at that target site.
Distribution servers
String. Modify access. The name of the machine group that contains the distribution servers on which to install the package.

When the Distribute phase scalar is set to SHAREJOB_DIST_SPECIFIED, this machine group specifies the distribution servers for the job. If the machine group does not contain a server for a target site, the package source directory is placed on the servers in the Default Servers group at that target site.

To specify the Default Servers group, your application must set the Distribute phase scalar to SHAREJOB_DIST_SPECIFIED, and set the Distribution servers scalar to NULL. Default Servers is a special machine group created at each site (Default Servers are maintained using the Site Properties dialog box in the SMS Administrator). If default servers are used as distribution servers at a target site, the SMS Scheduler (at the site where the job is created) builds the list of target distribution servers for the target sites. Note that the list of default servers is read from the site database of the site where the job was created. This means that the default servers on the list are the default servers that were last reported to the site where the job was created.

Caution When creating a job, your application must ensure that this scalar is set to a valid machine group name or set to NULL (NULL specifies the Default Servers group). Your application can get the machine group name through the machine group's folder in a populated machine group container.


Site Folder Scalars

A site folder contains a set of scalars that store information about the site. Site folder scalars have read-only access. Therefore, an application cannot set scalar values for a site folder.

A site folder has the following scalars:

Site name
String. Read-only access. Name of the site. The site name is specified when the site is created and cannot be changed.
Parent site
String. Read-only access. Site code for the site's parent site. The parent site is directly above the child site in the site hierarchy. If the site has no parent site, the string is empty.
Depth
Integer. Read-only access. Number of levels that the site is nested beneath the current site. For example, a site directly beneath the current site would have a depth of 1, and a site directly below that site would have a depth of 2. The current site has a depth of 0.
Status
String. Read-only access. Last reported installation status for the site. Status can have the following values:
"Active"
Site is installed and running.
"Pending"
Site is in the process of being installed.
"Failed"
Site could not be installed.
"Deleted"
Site is in the process of being deleted.
"Upgrade"
Site is in the process of being upgraded.
Site type
String. Read-only access. Type of site. Site type can have the following values:
"Primary"
Site is a primary site.
"Secondary"
Site is a secondary site.


Site Group Folder Scalars

A site group folder contains a set of scalars that store information about the site group. Site group folder scalars have read access. Therefore, an application cannot create a site group folder.

A site group folder has the following scalars:

Name
String. Read-only access. Name of the site group. This is the alias you can use to refer to the set of sites defined in the site group. The name is not case-sensitive. Spaces are allowed.
Comment
String. Read-only access. Text that contains any comments used to describe the site group.


System Job Folder Scalars

A system job folder contains a set of scalars that store information about the system job. System folder scalars have read-only access. Therefore, an application cannot set scalar values for a system job folder.

A system job folder has the following scalars:

Job ID
String. A unique identifier for the job. When a job is created, the SMS system assigns the job a unique Job ID based on the site code (first three characters) and a number (last five characters).
Job type
String. The type of job. There are three general types of system jobs:

"microsoft\SMS\mini-job"

"microsoft\SMS\site_job"

"microsoft\SMS\nad_transfer"

Job comment
String. Text that indicates the specific type of system job and its action. For a list and description of each specific type of system job, see Types of System Jobs.
Activate time
Time. The time when you want SMS to activate the job.

The time specifies the date and time after which the Scheduler activates the job and begins sending the job to the target sites. Note that the Scheduler uses the SQL Server time to evaluate the activation time. Also note that this time is written directly to the site database, that is, no time zone conversion is done.

Left icon
String. A string that sets the left icon for the job in the Jobs window of the SMS Administrator.
Center icon
String. A string that sets the middle icon for the job in the Jobs window of the SMS Administrator.
Right icon
String. A string that sets the right icon for the job in the Jobs window of the SMS Administrator.
Priority
Integer. Priority setting that you want the job to have relative to other jobs when being sent to target sites.

The priority setting is used to ensure that higher priority jobs are sent before lower priority jobs. A High priority tells the Scheduler to send the job to a target site before any other jobs with lower priority.

For example, if a Sender is sending a Medium or Low priority job and the Sender detects a High priority job in one of its outboxes, the Sender will suspend the sending of the lower priority job and send the High priority job first. After the High priority job has completed, the Sender will resume sending the lower priority job that was suspended.

In addition, an outbox can be set to process all jobs, only higher priority jobs, or no jobs at specified days and times.

High has priority over Medium and Low; Medium has priority over Low.

JOBPRI_HIGH
High
JOBPRI_MEDIUM
Medium
JOBPRI_LOW
Low
Repeat mode
Integer. Interval at which the job is repeated.

The intervals range from Daily (every 24 hours after the Activate time) to Monthly. The interval is based on the SMS system time. A repeated job generates a new job each time that interval elapses.

JOBRPT_NEVER
Never. Perform the job once.
JOBRPT_DAILY
Daily. Repeat every 24 hours after the Activate time.
JOBRPT_WEEKLY
Weekly. Repeat every 7 days after the Activate time.
JOBRPT_BIWEEKLY
Biweekly. Repeat every 14 days after the Activate time.
JOBRPT_MONTHLY
Monthly. Repeat every month.
Cancel mode
Integer. When Cancel mode is set to JOBCANCEL_CANCEL, the SMS system attempts to cancel the job. All other values for this scalar have no effect.
JOBCANCEL_DONT_CANCEL
Do not cancel the job.
JOBCANCEL_CANCEL
Cancel the job.
Job status
Integer. Indicates the overall status of the job across all target sites. There are six overall job states:
JOBSTAT_PENDING
Pending. Indicates that the job has not started and that the Scheduler is waiting to activate the job. When a job has this overall status, you can delete the job and prevent it from ever starting.
JOBSTAT_ACTIVE
Active. Indicates that the Scheduler has started the job and that SMS is currently carrying out the job without errors. The job may be complete or may still be in progress at the target sites or computers.
JOBSTAT_ACTIVE_FAILED
Retrying. Indicates that the job has failed at some target sites or target computers; however, SMS continues to attempt to complete the job at those sites or computers. The job may be complete or may still be in progress at other target sites or computers.
JOBSTAT_COMPLETE
Complete. Indicates that the job successfully completed its tasks at all target computers at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.
JOBSTAT_CANCELLED
Canceled. Indicates that the job was successfully canceled at all target sites. When a job has this overall status, you can delete the job because the system does no further processing on the job.
JOBSTAT_FAILED
Failed. Indicates that the job has failed at some or all target sites or target computers and that SMS has stopped trying to complete the job. The job may have completed successfully at some target sites or computers. You can note the job identifier and check the event log to determine why the job failed.
Sending status
Integer. Read-only access. Indicates the status for sending the job's package and instructions to all target sites:
None
Indicates that a Sender has not processed the job's send request (the Scheduler has not yet created a *.SRQ file).
JOBSTAT_PENDING
Indicates that the send requests for the job have been placed in Sender outboxes but that the Senders have not started to send the job package and instructions to the target sites. The Senders may not have detected the send requests for the job yet.
JOBSTAT_ACTIVE
Indicates that one or more Senders are in the process of sending the job package and instructions to the target sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that at least one Sender has failed at an attempt to send the job to a target site; however, the Senders continue to attempt to send the job to the sites. You can note the job identifier and check the event log to determine why the job failed.
JOBSTAT_COMPLETE
Indicates that the Senders successfully sent the job package and instructions to all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled before it was sent to the target sites.
JOBSTAT_FAILED
Indicates that one or more Senders have failed to send the job to one or more target sites and that they have stopped trying to send the job to those sites.
Working status
Integer. Read-only access. Indicates the job's progress at all target sites:
JOBSTAT_PENDING
Indicates that no target site has received the job package and instructions yet.
JOBSTAT_ACTIVE
Indicates that one or more target sites have received the package and are in the process of carrying out the job at those sites (without errors), but have not completed.
JOBSTAT_ACTIVE_FAILED
Indicates that the job has failed at one or more target computers at the target sites; however, the site components continue to attempt to complete the job at the target computers.
JOBSTAT_COMPLETE
Indicates that the job successfully completed at all target computers at all target sites.
JOBSTAT_CANCELLED
Indicates that the job was successfully canceled at all computers at all target sites.
JOBSTAT_FAILED
Indicates that the job has failed at some or all target computers at one or more target sites and that the site components have stopped trying to complete the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.
Cancel status
Integer. Read-only access. Indicates how SMS has progressed in canceling the job:
None
Indicates that the job has not been canceled.
JOBSTAT_PENDING
Indicates that the target sites have not received the instructions to cancel the job yet.
JOBSTAT_ACTIVE
Indicates that one or more target sites have received the cancel instructions and are in the process of canceling the job at those sites (without errors), but have not completed the cancellation.
JOBSTAT_ACTIVE_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites; however, the site components continue to attempt to cancel the job at those target computers.
JOBSTAT_COMPLETE
Indicates that the job was successfully canceled at all target computers at all target sites.
JOBSTAT_FAILED
Indicates that the system has failed to cancel the job at some target computers at one or more target sites and that the site components have stopped trying to cancel the job. The job may have completed successfully at some target computers. You can note the job identifier and check the event log to determine why the job failed.


Types of System Jobs

There are different types of system jobs that perform different actions. The type of system job is identified by the Comment scalar in the system job folder.

Comment scalar values are as follows:

System job to resync client
The Inventory Data Loader creates a system job to initiate a resync (a full inventory scan) for a computer at the current site or at a child site. This system job is sent directly to the site containing the computer to be resynchronized. No package is created; all data for the resync is stored in an instruction file. Priority is Medium.
Applications Manager/ inventory rule replication
The Applications Manager creates this job to send package properties (for the current site and site above it) to the sites directly below it in the hierarchy. Package property information includes package and program group changes, including deletions. Priority is Medium.
Site preinstall job for secondary site code
The Site Hierarchy Manager initiates this job to create an installation directory at the secondary site, to install the Bootstrap service to that directory, and to start that service at the site server for the secondary site. The Scheduler passes the job to the Sender, which connects to the site server for the secondary site and carries out system job instructions. No package is created for this job. Priority is High.
Site install job for secondary site code
The Site Hierarchy Manager initiates this job to send a package containing SMS site components to a secondary site. The Bootstrap service at the secondary site receives the package, decompresses it, and creates the site directory structure on the secondary site server. Priority is High.
Site control job for secondary site code
The Site Hierarchy Manager uses this job to create a package to send the site control file to the secondary site. This file contains configuration information for the site. The site control file can contain site delete instructions as well as updates (delete instructions occur after the parent site initiates a job to delete a secondary site; they serve to delete the secondary site from sites above the immediate parent). Priority is High.
Site deinstall job for secondary site code
The Site Hierarchy Manager at the parent site creates this job when a secondary site is deleted by using the SMS Administrator. No package is created. Priority is High.
Site Configuration Manager system job for sending site control file from secondary to parent site
The Site Configuration Manager starts a system job to send the site control file from a secondary site to the parent site. The file is treated as a regular package: it is compressed by the Scheduler and placed in the SITE.SRV\SENDER.BOX\TOSEND directory. At the parent site, the Despooler decompresses the package and copies the file to the SITE.SRV\SITECFG.BOX using a unique name. Priority is High.
Site Configuration Manager system job for sending site control file from primary to parent site
The Site Hierarchy Manager starts a system job to send the site control file from a primary site to its parent site. The file is treated as a regular package. It is compressed by the Scheduler and placed in the SITE.SRV\SENDER.BOX\TOSEND directory. At the parent site, the Despooler decompresses the package and copies the file to the SITE.SRV\SITECFG.BOX using a unique name. Priority is High.
System job for Site Reporter send of status and inventory
The Site Reporter at a secondary site creates this job to send Delta-MIFs to the parent site. All Delta-MIFs in a directory are compressed into a single package by the Scheduler. The Despooler at the receiving site decompresses Delta-MIFs into a temporary directory and renames them to unique names (DEL*.MIF) in the SITE.SRV\DATALOAD.BOX\deltamif.coL directory. If any error event Delta-MIFs are involved, priority is Medium. Otherwise, priority is Low.


Workstation Command Line Folder Scalars

A workstation command line folder contains a set of scalars that store information about the workstation command line. Workstation command line folder scalars have both create and read access. Therefore, an application can create a workstation command line folder.

A workstation command line folder has the following scalars:

Name
String. Modify access. The name for the workstation command line. This scalar has a maximum length of 255 characters. Within a package folder, the Name scalar for a workstation command line folder must be unique, that is, no two workstation command line folders can have the same value for the Name scalar within a single package folder.

Note that the Name scalar is also used as the identifier for the folder. Your application should ensure that this scalar is not set to a string that is already being used by another workstation command line folder within the same package folder.

In the SMS Administrator, this name will identify the command in the package's Workstation Command Lines dialog box and in a Run Command On Workstation job's Run Command dialog box. If the command is used for a Run Command On Workstation job, this name will also appear in the Command Name field of the Package Command Manager window on the target computers.

Command
String. Modify access. Command line for the Package Command Manager to run when the package command is run at a target computer.

The command line is run from the package's root directory, which is located on a shared directory on a server. The command line has a limit of 255 characters.

The command line must specify an executable file or a batch file. It cannot contain MS-DOS or Windows NT commands. If you want to use operating-system commands, put them in a batch file and specify the batch file for the Command scalar.

Flags
Integer. Modify access. Flags that specify the execution requirements for the command line.

If you set this scalar to zero, the setting is equivalent to clearing the Automated Command Line check box in the Command Line Properties dialog box in the SMS Administrator. If the command line requires the user at the target computer to enter data or respond to prompts, your application should set this scalar to zero.

WCL_AUTOMATED_COMMAND_LINE
Indicates that no user input is required to complete the package command. This is equivalent to the Automated Command Line check box in the Command Line Properties dialog box in the SMS Administrator.

If the command completes without any response from the user, make sure the Automated Command Line check box is selected. This displays a No in the package's Requires Input field in the Package Command Manager window.

WCL_BACKGROUND_TASK
This enables the SMS Package Command Manager service for Windows NT to run the command in background mode (this option is useful for running maintenance jobs on unattended servers). Note that the Package Command Manager service is installed by default only on servers running Windows NT.

This is equivalent to the System Background Task check box in the Command Line Properties dialog box in the SMS Administrator.

Set this flag if the application you are installing runs under Windows NT and does not display windows or require user input during installation.

Note that setting this flag implicitly sets the WCL_AUTOMATED_COMMAND_LINE flag.

Platforms
Integer. Modify access. Flags that specify the operating systems on which the package command will be available—MS-DOS, Windows version 3.1, Windows NT (x86), Windows NT (Alpha), and so on.

Caution Your application must set at least one platform flag for the Platforms scalar. If your application does not set a platform flag, the workstation command line will not be available for jobs. To correct this problem, your application must delete the workstation command line folder and re-create the folder with the Platforms scalar set correctly.

You can select one or more operating systems. When a platform flag is set, the package command is available at target computers with the specified platform (the package appears in the Package Command Manager window). When a platform flag is not set, the package command is not available on computers with the specified platform (the package does not appear in the Package Command Manager window).

PLTFRM_WIN16
Windows version 3.1.
PLTFRM_WIN95
Windows 95.
PLTFRM_WIN32_X86
Windows NT with x86 processor.
PLTFRM_WIN32_MIPS
Windows NT with MIPS processor.
PLTFRM_WIN32_ALPHA
Windows NT with Alpha processor.
PLTFRM_DOS5
MS-DOS version 5.x.
PLTFRM_DOS6
MS-DOS version 6.x.
PLTFRM_MSDOS
MS-DOS version 5.x or MS-DOS version 6.x.
PLTFRM_MACINTOSH
Macintosh System 7.x.


Persistent Filter Scalars

A persistent filter has four scalars:

Query Key
String that corresponds to the identifier of the query. The identifier is an eight-character identifier that the SMS system assigns to the query when it is first added to the site database. Note that the default queries provided with SMS have a six-character identifier. When your application creates a persistent filter, this scalar is set by the SMS system. Your application cannot set this scalar.
Name
String that corresponds to the Query Name in the Query Properties of the query in the SMS Administrator. When your application creates a persistent filter, this scalar must be set by your application when adding a persistent filter to the site database.
Comment
String that corresponds to Comment in the Query Properties of the query in the SMS Administrator. When your application creates a persistent filter, this scalar is optional.
Architecture
String that corresponds to Architecture in the Query Properties of the query in the SMS Administrator. When your application creates a persistent filter, this scalar must be set by your application.

Unlike the scalars for folders, the scalars for persistent filters can be retrieved in sequence only.

To retrieve scalars in sequence, use the SmsGetNextScalar function. SmsGetNextScalar retrieves the next scalar in the list of scalars within the persistent filter and writes the scalar's information into a SCALAR structure. To start at the beginning of the list again, use SmsRewind to reset a filter's internal scalar index so that the filter's scalars can be reiterated.

Name and Architecture must be set by your application before a persistent filter is added to the site database by using SmsCommitFilter.

Use the SmsSetScalar function to set the value of a scalar.


Retrieving the Values of Scalars

After your application gets the handle to a folder, your application can retrieve the scalars for that folder. The SmsGetNextScalar and SmsGetScalarByName functions retrieve the specified scalar from the folder and write the scalar's information into a SCALAR structure. Using these two functions, your application can retrieve scalars in sequence or by the scalar name:

  • To retrieve scalars in sequence, use the SmsGetNextScalar function. SmsGetNextScalar retrieves the next scalar in the list of scalars within the folder and writes the scalar's information into a SCALAR structure.
  • To retrieve scalars by scalar name, use the SmsGetScalarByName function. SmsGetScalarByName retrieves the scalar with the specified scalar name from the folder and writes the scalar's information into a SCALAR structure.

Note that the SmsGetScalarCount function returns the count of scalars within a folder.

Example

There are four types of scalars: SCALAR_INT, SCALAR_STRING, SCALAR_TIME, and SCALAR_BINARY. The following examples show how to retrieve the value for each type of scalar:

Example of Retrieving a SCALAR_INT Scalar

Example of Retrieving a SCALAR_STRING Scalar

Example of Retrieving a SCALAR_BINARY Scalar

Example of Retrieving a SCALAR_TIME Scalar


Example of Retrieving a SCALAR_INT Scalar

The following example contains a function (ReadRepeatMode) that reads a SCALAR_INT scalar (Repeat mode) from a job folder (F_SYSTEMJOB, F_INSTALLJOB, F_SRVINSTALL, or F_REMPKGJOB) and prints it to the screen:

// Function to read the Repeat mode scalar for a job folder
// and use printf to display the scalar.
// This function uses SmsGetScalarByName.

SMS_STATUS ReadRepeatMode(HANDLE hFolder) // Handle to job folder.

{
SMS_STATUS stat;
SCALAR sc;
char szName[SMS_DATA_BUFF_SIZE];
sc.pszName = szName;
sc.scType = SCALAR_INT;
// Retrieve the scalar.
stat = SmsGetScalarByName(hFolder,      // Handle to folder.
                          "Repeat mode", // Name of scalar to
                                        // retrieve.
                          &sc           // Pointer to SCALAR to
                                        // place scalar data.
                          );
// Get a string equivalent for Repeat mode.
char *pszStringEquivalent;
char szStringBuffer[BUFF_SIZE];
pszStringEquivalent = szStringBuffer;

switch (sc.dwValue) {
    case JOBRPT_NEVER:
        pszStringEquivalent = "Never";
        break;
    case JOBRPT_DAILY:
        pszStringEquivalent = "Daily";
        break;
    case JOBRPT_WEEKLY:
        pszStringEquivalent = "Weekly";
        break;
    case JOBRPT_BIWEEKLY:
        pszStringEquivalent = "Biweekly";
        break;
    case JOBRPT_MONTHLY:
        pszStringEquivalent = "Monthly";
        break;
    default:
        wsprintf(pszStringEquivalent, "Unknown value %d", sc.dwValue);
        break;
}
// print the value.
printf("%s: %s\n", sc.pszName, pszStringEquivalent);
return(stat);
}


Example of Retrieving a SCALAR_STRING Scalar

The following example contains a function (ReadPackageID) that reads a SCALAR_STRING scalar (Package ID) from a job folder (F_SYSTEMJOB, F_INSTALLJOB, F_SRVINSTALL, or F_REMPKGJOB):

// Function to read the Package ID scalar for a job folder
// and use printf to display the scalar.
// This function uses SmsGetScalarByName.

SMS_STATUS ReadPackageID(HANDLE hFolder) // Handle to job folder.

{
SMS_STATUS stat;
SCALAR sc;
char szName[SMS_DATA_BUFF_SIZE]; //Buffer for scalar name.
char szValue[9]; //Buffer for string value. Package ID is 8 char.
sc.pszName = szName;
sc.pszValue = szValue;
sc.dwLen = sizeof(szValue)-1;
sc.scType = SCALAR_STRING;

// Retrieve the scalar.
stat = SmsGetScalarByName(hFolder,      // Handle to folder.
                          "Package ID", // Name of scalar to
                                        // retrieve.
                          &sc           // Pointer to SCALAR to
                                        // place scalar data.
                          );
// print the value.
printf("%s: %s\n", sc.pszName, sc.pszValue);
return(stat);
}


Example of Retrieving a SCALAR_BINARY Scalar

Currently, only program item folders contain a scalar of type SCALAR_BINARY. The Icon scalar in a program item folder is a binary scalar that specifies an icon resource that will be used as the icon for the program item.

The following example contains a function (GetProgItemIcon) that reads a SCALAR_BINARY scalar (Icon) from a program item folder (F_PROGITEM):

//***********************************************************
// Function to retrieve Icon binary scalar from
// a program item folder.
//***********************************************************

SMS_STATUS ReadIcon(HANDLE hFolder)

{
SMS_STATUS stat;
SCALAR sc;
char szName[SMS_DATA_BUFF_SIZE];  // buffer for name
char szValue[SMS_DATA_BUFF_SIZE]; // buffer for value
BYTE *pbyteValue;

sc.pszName  = szName;
sc.pszValue = szValue;
sc.pValue   = NULL;
sc.dwLen = NULL;
sc.scType = SCALAR_BINARY;

// Call SmsGetScalarByName with dwLen set to NULL
// to get length of binary data.
stat = SmsGetScalarByName( hFolder,
                           "Icon",
                           &sc);

// if length is returned, allocate memory for the
// data buffer .
if (stat == SMS_MORE_DATA) {
    printf("Binary scalar \"%s\" has length of %d bytes\n",
      sc.pszName, sc.dwLen);
    // Allocate memory for the binary data.
    sc.pValue = pbyteValue;
    pbyteValue = (BYTE *) malloc(sc.dwLen);
    // Call SmsGetScalarByName again
    // to retrieve the binary scalar.
    stat = SmsGetScalarByName( hFolder,
                               "Icon",
                               &sc);
}

if (stat == SMS_OK) {
    // Data retrieved successfully.
    printf("Binary scalar \"%s\" has %d bytes of binary data\n",
      sc.pszName, sc.dwLen);
    // Primitive dump of the data.
    for (DWORD dwI = 0; dwI < sc.dwLen; dwI++) {
        printf("%0X ", pbyteValue[dwI]);
    }
    printf("\n");
}
// if scalar cannot be retrieved,
// print status code.
else {
    printf("Cannot retrieve binary scalar \"%s\".", sc.pszName);
    printf("Error in SmsGetScalarByName: %d.\n", stat);
}

// Free allocated memory and return
// the status code.
free(pbyteValue);
return stat;

}


Example of Retrieving a SCALAR_TIME Scalar

The following example contains a function (ReadActivateTime) that reads a SCALAR_TIME scalar (Activate time) from a job folder (F_SYSTEMJOB, F_INSTALLJOB, F_SRVINSTALL, or F_REMPKGJOB):

// Function to read the Activate time scalar for a job folder
// and use printf to display the string equivalent of the time
// set for the scalar.
// This function uses SmsGetScalarByName.

SMS_STATUS ReadActivateTime(HANDLE hFolder)  // Handle to job folder.

{
SMS_STATUS stat;
char *pszTime;
SCALAR sc;
char szName[SMS_DATA_BUFF_SIZE]; //Buffer for scalar name.
char szValue[BUFF_SIZE]; //Buffer for string equivalent.
sc.pszName = szName;
sc.pszValue = szValue;
sc.dwLen = sizeof(szValue)-1;

// Retrieve the scalar.
stat = SmsGetScalarByName(hFolder,      // Handle to folder.
                          "Activate time", // Name of scalar to
                                        // retrieve.
                          &sc           // Pointer to SCALAR to
                          );            // place scalar data.

if (sc.bStringEquivalence)
    // if a string equivalent to time is provided,
    // print the value.
    printf("%s: %s\n", sc.pszName, sc.pszValue);
else {
    // if no string equivalent, convert to string and print.
    // Use ctime from C runtime library.
    pszTime = ctime( &sc.tValue );
    printf("%s: %s\n", sc.pszName, pszTime);
}

return(stat);
}


Setting the Values of Scalars

After a new folder has been created, the folder is empty, that is, it has no scalars set within it. Your application must use the SmsSetScalar function to set the scalars for the new folder.

To set the value of a scalar, both the scalar and its folder must have an access right of ACCESS_MODIFY or ACCESS_CREATE. If you do not have ACCESS_MODIFY or ACCESS_CREATE right to the scalar, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, the SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

To get information (such as name, data type, access rights, and so on) about all scalars within a folder, use the SmsDescribeFolder function.

The SmsSetScalar function takes two parameters:

  • The handle to the folder containing the scalar
  • A pointer to a SCALAR structure that contains the scalar data to be set

Example

There are four types of scalars: SCALAR_INT, SCALAR_STRING, SCALAR_TIME, and SCALAR_BINARY. The following examples show how to set the value for each type of scalar:

Example of Setting a SCALAR_INT Scalar

Example of Setting a SCALAR_STRING Scalar

Example of Setting a SCALAR_BINARY Scalar

Example of Setting a SCALAR_TIME Scalar


Example of Setting a SCALAR_INT Scalar

The following example contains a function (SetRepeatMode) that sets a SCALAR_INT scalar (Repeat mode) for a job folder (F_INSTALLJOB, F_SRVINSTALL, or F_REMPKGJOB):

// Function to set the Repeat mode scalar for a new job folder.

SMS_STATUS SetRepeatMode(HANDLE hFolder,  // Handle to job folder.
                         DWORD dwMode     // Scalar value.
                        )

{
    SMS_STATUS stat;
    SCALAR sc;
    // check if the value is valid for Repeat mode.
    switch (dwMode) {
       case JOBRPT_NEVER:
       case JOBRPT_DAILY:
       case JOBRPT_WEEKLY:
       case JOBRPT_BIWEEKLY:
       case JOBRPT_MONTHLY:
            break;
       case default:
            // Return a parameter error if it is an invalid value.
            return(SMS_PARAMETER_ERROR);
            break;
       }

    sc.pszName = "Repeat mode"; // Name of the scalar to set.
    sc.scType = SCALAR_INT; // Data type of scalar.
    sc.dwValue = dwMode;

    // Use SmsSetScalar to use the sc struct to set the
    // scalar for the folder.
    stat = SmsSetScalar( hFolder,   // Handle to folder containing
                                    // the scalar to set.
                         &sc        // Pointer to SCALAR struct
                                    // containing value to set.
                       );
    return(stat);
}


Example of Setting a SCALAR_STRING Scalar

The following example contains a function (SetPackageID) that sets a SCALAR_STRING scalar (Package ID) for a job folder (F_INSTALLJOB, F_SRVINSTALL, or F_REMPKGJOB):

// Function to set the Package ID scalar for a new job folder.

SMS_STATUS SetPackageIDScalar( char *pszPackageID, // Package ID.
                               HANDLE hJobFolder, // Job folder handle.
                               HANDLE hConnect) // Connection handle.

{

//***********************************************************
//****** Verify the package ID.
//***********************************************************
// The package ID must be for an existing package that has
// Workstation properties set. Therefore, open a package
// container and populate it with a Package filter set to Workstation.
// Use the package container to verify the package ID.

SMS_STATUS stat;
// Open a package container.
HANDLE hPackageContainer;
stat = SmsOpenContainer( C_PACKAGE,
                         hConnect,
                         &hPackageContainer);
// Create a package filter.
HANDLE hFilter;
stat = SmsCreateFilter( PACKAGE_FILTER, // Type of filter.
                        hConnect,   // Handle to database
                                    // connection.
                        &hFilter    // Assign handle to new filter
                      );            // to hFilter.

// Add a token to the package filter that
// finds all packages with Workstation properties set.
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );
// Set the expression token to
// "PackageType is equal to Workstation".

// Set the attribute name to PackageType.
strcpy( Token.szName, "PackageType");
// Set the operator used to evaluate the expression.
Token.dwOp = QOP_STR_EQ; // Use the equals operator.
// Set the value to evaluate.
strcpy( Token.szValue, "Workstation");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use the AND control token to connect
                             // the expression to adjacent expressions.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );

// Apply the filter to the container.
stat = SmsSetFilter ( hPackageContainer,  // Handle to container.
                      hFilter      // Handle to filter.
                    );

// Populate the container with the folders meeting the criteria set
// by the filter applied to the container. Retrieve folders
// synchronously.
stat = SmsPopulate( hPackageContainer,  // Handle to container.
                    POP_SYNC,    // Retrieve folders in
                                 // synchronous mode.
                    NULL         // NULL for synchronous.
                  );

// Use SmsGetFolderCount to get number of folders in package container.
DWORD ctFolders;
stat = SmsGetFolderCount( hPackageContainer, // Handle to package container.
                          F_PACKAGE,      // Get count of package folders
                                      // in package container.
                          &ctFolders  // Assign count to pctFolders.
                        );

// Loop to retrieve the handles to the
// package folders in the package container by using SmsGetNextFolder,
// retrieve the scalar value for the Package ID and Name scalars by using
// SmsGetScalarByID, and print the Package ID and Name.
HANDLE hFolder;

SCALAR scalar;
char *pszName;
char szScalarName[SMS_DATA_BUFF_SIZE];
char szScalarValue[SMS_DATA_BUFF_SIZE];
scalar.dwLen = sizeof(szScalarValue)-1;
scalar.pszName = szScalarName;
scalar.pszValue = szScalarValue;
scalar.scType = SCALAR_STRING;

//Loop to search for package with ID match in pszPackageID.
DWORD iLoop;
int iCompare;
BOOL bPackageExist = FALSE;
iLoop = 1;
while ( iLoop <= ctFolders) {
    stat = SmsGetNextFolder( hPackageContainer,
                             F_ANY,
                             &hFolder);
    // if folder is retrieved, check if pszPackageID matches
    // the folder's ID.
    if (stat == SMS_OK) {
        pszName = "Key";
        stat = SmsGetScalarByName(hFolder, pszName, &scalar);
        //compare package ID with ID of folder.
        iCompare = strcmp(pszPackageID , scalar.pszValue);
        // if package ID matches folder's ID,
        // then set bPackageExist to TRUE and break.
        if (iCompare == 0) {
               bPackageExist = TRUE;
            printf("Package ID verified.\n");
               break;
        }
    }
    // if end of folder list, package ID does not match;
    // therefore, reprompt for ID and check again.
    else if (stat == SMS_NO_MORE_DATA) {
        printf("Package ID specified does not exist.\n");
        // reset folder list to start of list.
        stat = SmsRewind(hPackageContainer, RW_ALL);
        // reset loop.
        iLoop=0;
        // prompt again for ID.
        printf("Enter package ID again:");
        gets(pszPackageID);
    }
    // if error retrieving folder, print status code
    // and break.
    else {
        printf("Could not retrieve folder: %d\n", stat);
        break;
    }
    iLoop++;
}

//***********************************************************
//****** Set the package ID scalar for the job folder.
//***********************************************************
// If the the package ID is valid, use it to set the
// Package ID scalar for the Run Command On Workstation job.
if (bPackageExist == TRUE) {
    SCALAR sc; // Declare SCALAR struct to hold scalar data.
    char *pszScalarName = "Package ID"; // Name of the scalar to set.
    SCALARTYPE scType = SCALAR_STRING; // Data type of scalar.

    // Assign the scalar data to the sc structure.
    sc.pszName = pszScalarName;
    sc.scType  = scType;
    sc.dwLen = sizeof(pszPackageID)-1; // -1 for terminating NULL.
    sc.pszValue = pszPackageID;

    // Use SmsSetScalar to use the sc struct to set the
    // scalar for the folder.
    stat = SmsSetScalar( hJobFolder, // Handle to folder containing
                                     // the scalar to set.
                         &sc);       // Pointer to SCALAR struct
                                     // containing value to set.
    if (stat == SMS_OK)
        printf("Package ID %s scalar set successfully.\n", sc.pszValue);
}
return stat;

}


Example of Setting a SCALAR_BINARY Scalar

Currently, only program item folders contain a scalar of type SCALAR_BINARY. The Icon scalar in a program item folder is a binary scalar that specifies an icon resource that will be used as the icon for the program item. The following example contains two functions (SetProgItemIcon and ReadICOFileImage) that load the icon resource and set the Icon scalar for a program item folder:

// Function to set the Icon scalar for a new program item folder.

SMS_STATUS  SetProgItemIcon(HANDLE hFolder, // Handle to program
                                            //item folder handle.
                            const char* pszIcoFile // Path to
                                            // icon file.
                            )

{
DWORD dwIconLen;
void* pImage = (void*) ReadICOFileImage(pszIcoFile, &dwIconLen);
if (pImage == NULL) {
    // The icon file could not be read.
    return(SMS_EMPTY);
}

SMS_STATUS stat;
SCALAR sc;
sc.pszName = "Icon";
sc.scType = SCALAR_BINARY;
sc.pValue = pImage;
sc.dwLen = dwIconLen;
stat = SmsSetScalar(hFolder, &sc);
return(stat);
}

// Function to read an .ICO file directly to an in memory image.
// Supports .ICO files that containonly one icon.

BYTE *ReadICOFileImage(const char *pFileName, // filename of .ICO file.
                   DWORD *pdwIconSize // Size of icon image.
                  )
// This function returns a pointer to the .ICO image in memory.
// If the function cannot load the .ICO image, it returns NULL.
{
*pdwIconSize = 0;
FILE *f = fopen(pFileName, "rb");
if (!f) return NULL;        // File missing
BYTE *pIconFileImage;
DWORD dwImageSize;
fseek(f, 0, SEEK_END);            // To determine file size
dwImageSize = (DWORD) ftell(f);   // Get file size
fseek(f, 0, SEEK_SET);            // Move back to start of file
pIconFileImage = (BYTE *) malloc(dwImageSize);

//pIconFileImage = new BYTE[dwImageSize];   // Set up icon buffer

DWORD dwResult = fread(pIconFileImage, sizeof(BYTE), dwImageSize, f);

// Verify that the whole file read into memory
if (dwResult != dwImageSize) {
    free (pIconFileImage);
    pIconFileImage = NULL;
}
fclose(f);
*pdwIconSize = dwImageSize;
return pIconFileImage;
}


Example of Setting a SCALAR_TIME Scalar

The following example contains a function (SetActivateTime) that sets a SCALAR_TIME scalar (Activate time) for a job folder (F_INSTALLJOB, F_SRVINSTALL, or F_REMPKGJOB):

// Function to set the Activate time scalar for a new job folder.

SMS_STATUS SetActivateTime(HANDLE hFolder,  // Handle to job folder.
                           time_t time      // Scalar value.
                        )

{
SMS_STATUS stat;
SCALAR sc;
char *pszTime;
sc.pszName = "Activate time"; // Name of the scalar to set.
sc.scType = SCALAR_TIME; // Data type of scalar.
sc.tValue = time;

// Use SmsSetScalar to use the sc struct to set the
// scalar for the folder.
stat = SmsSetScalar( hFolder,   // Handle to folder containing
                                // the scalar to set.
                     &sc        // Pointer to SCALAR struct
                                // containing value to set.
                   );
if (stat == SMS_OK) {
    pszTime = ctime( &sc.tValue );
    printf("Activate time %s scalar set successfully.\n", pszTime);
}
else {
    printf("Activate time scalar could not be set.\n");
    printf("SmsSetScalar error: %d.\n", stat);
}
return stat;
}


Filters

Before your application populates a container with objects from the site database, one or more filters can be set on the container. Filters define the criteria used to select the objects to retrieve from the site database.

There are eight types of filters available. The types of filters that your application can set are dependent on the container. For example, filters of type ARCHITECTURE_FILTER, MACHINE_FILTER, GROUP_FILTER, and ATTRIBUTE_FILTER can be set on a machine container.

Your application can configure a filter by adding tokens to the filter. There are two types of tokens: expression tokens and control tokens.

An expression token defines how to search for objects that have a specified relationship to a specified value for a specified attribute. An expression token is made up of an attribute, a relational operator, and a comparison value. A relational operator (such as "is equal to" or "is like") defines how the specified value should be compared with the actual value stored for the specified attribute. Depending on the type of filter that contains the token, an expression token's TOKEN structure uses the szName, szArchitecture, szGroupClass, and szAttributeName members to defined the attribute. For example, job filters (and most other filters) use the szName member to specify the attribute, whereas machine filters use the szArchitecture, szGroupClass, and szAttributeName members.

A control token can be a logical operator or parentheses. A logical operator connects two expression tokens, two subclauses, or a combination of an expression and a subclause. A logical operator defines the relationship between two adjacent expressions or subclauses. Parentheses enable expressions to be grouped together.

Your application can add expression tokens to a filter, using the SmsAddToken function. When an expression token is added to a filter, a control token for a logical operator is also implicitly added at the same time.

The SmsManipulateTokens function can be used to group, ungroup, delete, or exclude the specified tokens within a filter.

After your application sets the tokens for a filter, it can apply the filter to a container by using the SmsSetFilter function. When the container is populated, the set of filters applied to the container determine the objects that are retrieved from the site database.

There are also two classes of filters:

Transient filters
Filters that are created by your application and that exist only for the lifetime of the process that created them.
Persistent filters
Filters within a filter container that have been added to the site database. Persistent filters can be loaded by other processes. A persistent filter also contains scalars that are used to label the filter within the site database. Currently, only filters of type MACHINE_FILTER can be added to the site database through a filter container. MACHINE_FILTER filters are added as queries in the site database. Your application can also retrieve queries stored in the site database by opening a filter container. When the filter container is opened, it is populated with the queries stored in the site database. These queries are represented as filters in the filter container. Currently, the SMS API does not support deletion of persistent filters from the site database.


Filter Properties

The SmsEnumFilters function enables your application to retrieve information about all filter types supported by the SMS API. The properties for each filter type are stored in a FILTER_INFO structure.

By accessing the members of the FILTER_INFO structure, your application can get the following information about the filter type:

szTag
Specifies the string form of the filter's tag. The string has the length specified by NAME_SIZE.
filterType
Specifies the type of the filter. See filter types.
szName
Specifies the string label for the name of the value to be evaluated by an expression.

Note that szName is used by all filter types except machine filters (MACHINE_FILTER) and attribute filters (ATTRIBUTE_FILTER), which use the szAttributeName to specify the name of the attribute to use for the expression. For these two filters, szName is NULL.

szValue
Specifies the string label for the value to be compared using the operator specified by szOperator.
szOperator
Specifies the string label for the name of the operator to be evaluated by an expression.
szArchitecture
Specifies the string label for the name of the architecture of the object to search for. This member is used only for machine filters and attribute filters.
szGroupClass
Specifies the string label for the name of the group class of the attribute specified by szAttributeName. This member is used only for machine filters and attribute filters.
szAttributeName
Specifies the string label for the name of the attribute to evaluate against the value specified by szValue. This member is used only for machine filters and attribute filters.

Note that szName is used by all filter types except machine filters (MACHINE_FILTER) and attribute filters (ATTRIBUTE_FILTER); for all other filters, szAttributeName is NULL.


Filter Types

There are eight types of filters:

Type | Tag | Description
ARCHITECTURE_FILTER | Architecture filter | Specifies that machine folders of the specified architectures are retrieved in a site, site group, or machine container.
ATTRIBUTE_FILTER | Attribute filter | Specifies which attributes (represented as scalars within group folders) are retrieved for machine folders in a site, site group, or machine container.
GROUP_FILTER | Group filter | Specifies which group folders are retrieved for machine folders in a site, site group, machine, or machine group container.
JOB_FILTER | Job filter | Specifies which job folders are retrieved in a job container.
MACHINE_FILTER | Machine filter | Specifies which machine folders are retrieved in a site, site group, or machine container.
PACKAGE_FILTER | Package filter | Specifies which package folders are retrieved in a package container.
SITE_FILTER | Site filter | Specifies which site folders are retrieved in a site container.
SITELIMIT_FILTER | SiteLimit Filter | Specifies that machine folders within the specified site and/or domain are retrieved in a machine container.

The types of filters that your application can set are dependent on the container. For example, filters of type ARCHITECTURE_FILTER, MACHINE_FILTER, GROUP_FILTER, and ATTRIBUTE_FILTER can be set on a machine container.


Architecture Filters (ARCHITECTURE_FILTER)

An architecture filter specifies the machine folders within a container. When an architecture filter is set on a container, the machine folders in that container will be of the architecture specified by the architecture filter.

Architecture filters can be applied only to the following containers: site containers, site group containers, and machine containers.

Using the SmsAddToken function, your application can add tokens to an architecture filter. Each expression token represents an architecture. For architecture filters, the tokens can be connected only by using an OP_OR control token—this means that your application must pass OP_OR for the opAndOr parameter when calling the SmsAddToken function.

Note When an attribute filter or machine filter is applied to a container that also has an architecture filter set, the architectures specified in those filters are implicitly added to the list of architectures specified in the architecture filter.

The TOKEN structure that contains the expression token must have the following members:

szName
A string that specifies that the architecture name is used to evaluate the expression.

Currently, Architecture must be specified for this value.

DwOp
A DWORD value that specifies the operator used to evaluate the expression.

For architecture filters, this operator can only be QOP_STR_EQ.

SzValue
A string that specifies the architecture name of the machine folders to retrieve.

For example, most computers in the SMS system have architecture "Personal Computer".

Your application could create an architecture filter with a token for the Personal Computer architecture and set this filter as the only filter on a machine container. When your application populates the machine container, the container contains folders that represent all computers with the Personal Computer architecture.

Example

// Function to add a token to an architecture filter so that
// the filter retrieves the machine folders representing
// computers with the Personal Computer architecture.

SMS_STATUS AddTokenToArchitectureFilter(HANDLE hFilter)
                         //  Handle to architecture filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// szName = "Architecture"
// dwOp = QOP_STR_EQ
// szValue = "Personal Computer"

// Set the szName to Architecture.
strcpy( Token.szName, "Architecture");
// Set the operator to string equals.
Token.dwOp = QOP_STR_EQ;
// Set the type of architecture.
strcpy( Token.szValue, "Personal Computer");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_OR,   // Must use the OR control token to
                             // add a token to an Architecture filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


Attribute Filters (ATTRIBUTE_FILTER)

An attribute filter specifies the attributes (represented as scalars) that are retrieved for the machine folders within a container. If only an attribute filter is set on a container, the attribute filter also determines which group folders are retrieved.

Attribute filters can be applied only to the following containers: site containers, site group containers, and machine containers.

Note that an attribute filter does not determine the set of machine folders retrieved from the site database—a machine filter is used to specify the attributes used to select the machine folders that will populate a container. An attribute filter specifies the criteria used to select the group folders and attribute scalars that are retrieved for each machine folder in a container.

If both an attribute filter and a group filter are set, the folders for only the groups specified by both the attribute filter and the group filter are retrieved. The group folders specified by the attribute filter will contain only the attributes specified in the attribute filter.

Note When an attribute filter is applied to a container that also has an architecture filter set, the architectures specified in the attribute filter are implicitly added to the list of architectures specified in the architecture filter.

Using the SmsAddToken function, your application can add tokens to an attribute filter. Each expression token represents an attribute. For attribute filters, the tokens can be connected only by using an OP_OR control token—this means that your application must pass OP_OR for the opAndOr parameter when calling the SmsAddToken function. The TOKEN structure that contains the expression token must have the following members:

szArchitecture
A string that specifies the name of the architecture that contains the attribute.

For example, Personal Computer.

SzGroupClass
A string that specifies the name of the group class that contains the attribute.

For example, MICROSOFT|IDENTIFICATION|1.0.

szAttributeName
A string that specifies the name of the attribute that you want to retrieve for objects of the type specified by architecture.

For example, SMSLocation.

Your application could create an attribute filter with two tokens (one with Personal Computer architecture and MICROSOFT|IDENTIFICATION|1.0 group class with attribute SMSLocation, and the other with the same architecture and group class but with the attribute SystemRole) and set this filter as the only filter on a machine container. When your application populates the machine container, the container contains folders that represent all computers, and each of those machine folders will contain one group folder (for the MICROSOFT|IDENTIFICATION|1.0 group class) and the group folder will contain two scalars (SMSLocation and SystemRole).

Example

// Function to add a token to a attribute filter so that
// the filter retrieves the SMSLocation scalar for
// the Identification group within machine folders.

SMS_STATUS AddTokenToAttributeFilter(HANDLE hFilter)
                         //  Handle to attribute filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// Architecture = "Personal Computer"
// Group Class = "MICROSOFT|IDENTIFICATION|1.0"
// Attribute = "SMSLocation"

// Set the architecture name to Personal Computer.
strcpy( Token.szArchitecture, "Personal Computer");
// Set the group class.
strcpy(Token.szGroupClass, "MICROSOFT|IDENTIFICATION|1.0");
// Set the attribute.
strcpy( Token.szAttributeName, "SMSLocation");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_OR,   // Must use the OR control token to
                             // add a token to an Attribute filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Adds the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


Group Filters (GROUP_FILTER)

A group filter specifies the groups that are retrieved for the machine folders within a container.

Group filters can only be applied to containers that support machine folders: site container, site group container, machine container, and machine group container.

When a group filter is set on a container, the machine folders in that container will contain only the groups that have been specified in the group filter. However, all attributes within the specified groups will be retrieved if no attribute filter has been set.

If both an attribute filter and a group filter are set, the folders for only the groups specified by both the attribute filter and the group filter are retrieved. The group folders specified by the attribute filter will contain only the attributes specified in the attribute filter.

Using the SmsAddToken function, your application can add tokens to a group filter. Each expression token represents a group. For group filters, the tokens can be connected only by using an OP_OR control token—this means that your application must pass OP_OR for the opAndOr parameter when calling the SmsAddToken function. The TOKEN structure that contains the expression token must have the following members:

szName
A string that specifies that the group class name is used to evaluate the expression.

Currently, the string "GroupClass" must be specified for this value.

DwOp
A DWORD value that specifies the operator used to evaluate the expression.

For group filters, this operator can only be QOP_STR_EQ.

SzValue
A string that specifies the class name of the group to retrieve. A group class name has the following form:

organization:name:version.

For example, the Identification group for the Personal Computer architecture has a class name: "MICROSOFT|IDENTIFICATION|1.0".

Note that the SMS API engine does not validate the group specified by a group token. Your application is responsible for creating a token for a valid group class.

For example, your application could create a group filter with two tokens (one for MICROSOFT|IDENTIFICATION|1.0 group and the other for the MICROSOFT|DISK|1.0 group) and set this filter as the only filter on a machine container. When your application populates the machine container, the container contains folders that represent all computers, and each of those machine folders will contain two group folders: MICROSOFT|IDENTIFICATION|1.0 and MICROSOFT|DISK|1.0.

Example

// Function to add a token to a group filter so that
// the filter retrieves the Identification group
// within machine folders.

SMS_STATUS AddTokenToGroupFilter(HANDLE hFilter)
                         //  Handle to group filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// Group Class = "MICROSOFT|IDENTIFICATION|1.0"

// Set name to GroupClass.
strcpy( Token.szName, "GroupClass");

// Set the operator used to evaluate the expression.
// Must use the string equals operator.
Token.dwOp = QOP_STR_EQ;

// Set the group class name.
strcpy(Token.szValue, "MICROSOFT|IDENTIFICATION|1.0");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_OR,   // Must use the OR control token to
                             // add a token to a Group filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Adds the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


Job Filters (JOB_FILTER)

A job filter specifies the jobs that are retrieved for a job container. If no job filter is set on a job container, all jobs in the site database are retrieved for the container. Job filters can only be applied to job containers.

Using the SmsAddToken function, your application can add tokens to a job filter. Each expression token represents an attribute. For job filters, the tokens can be connected by using an OP_OR or OP_AND control token.

The TOKEN structure that contains the expression token must have the following members:

szName
A string that specifies the name of the job property to be evaluated by the expression.

Currently, three properties can be evaluated: JobType, JobStatus, and JobID.

For example, JobType specifies that the type of job is being evaluated.

DwOp
A DWORD value that specifies the operator used to evaluate the expression.

For job filters, this operator can only be QOP_STR_EQ.

SzValue
A string that specifies the value to be evaluated for the property specified by szName.

For example, if JobType is set for szName, the string "Install" would specify a Run Command On Workstation job type. For a list of values for each property, see the table below.

For example, your application could create a job filter with a token that specifies a JobStatus of Active. Your application could set this filter as the only filter on a job container. When your application populates the container, it contains folders that represent all jobs that have an active status.

The following table shows the values (szValue) that the available properties (szName) can have:

szName | szValue
JobStatus | "Pending" "Active" "Cancelled" "Complete" "Failed" "Active failed"
JobType | "Install" "Server" "Remove package" "System"
JobID | jobID. For example, "RTM00001". The Job ID is an eight-character identifier that the SMS system assigns to the job. Note that the first three characters are the site code for the site where the job was created.

Example

// Function to add a token to a job filter so that
// the filter retrieves only the folders for
// Run Command On Workstation jobs (F_INSTALLJOB).

SMS_STATUS AddTokenToJobFilter(HANDLE hFilter)
                         //  Handle to package filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// szName = "JobType"
// dwOp = QOP_STR_EQ
// szValue = "Install"

// Set the job property.
strcpy( Token.szName, "JobType");
// Set the operator to string equals.
Token.dwOp = QOP_STR_EQ;
// Set the type of job.
strcpy( Token.szValue, "Install");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use the AND control token to
                             // add a token to the job filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Adds the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


Machine Filter (MACHINE_FILTER)

Machine Filters (MACHINE_FILTER)

A machine filter specifies that the objects (machine folders) with the specified attributes should be retrieved.

Machine filters can be applied only to the following containers: site containers, site group containers, and machine containers. If no machine filter (or other filter type) is set on a site container or machine container, all machines in the site database are retrieved for the container.

Machine filters can also be stored in an SMS site database as persistent filters. Persistent machine filters are represented as queries in the SMS Administrator.

Although machine filters and attribute filters both handle attributes, the two filters are used for different purposes. A machine filter specifies the attributes used to select the machine folders that will populate a container. An attribute filter specifies the criteria used to select the group folders and attribute scalars that are retrieved for each machine folder in a container.

Note When a machine filter is applied to a container that also has an architecture filter set, the architectures specified in the machine filter are implicitly added to the list of architectures specified in the architecture filter.

Using the SmsAddToken function, your application can add tokens to a machine filter. Each expression token represents an attribute. For machine filters, the tokens can be connected using an OP_OR or OP_AND control token.

The TOKEN structure that contains the expression token must have the following members:

szArchitecture
A string that specifies the name of the architecture that contains the attribute to evaluate.

For example, Personal Computer.

SzGroupClass
A string that specifies the name of the group class that contains the attribute to evaluate.

For example, MICROSOFT|IDENTIFICATION|1.0.

szAttributeName
A string that specifies the name of the attribute that you want to evaluate.

For example, SMSLocation.

DwOp
A DWORD value that specifies the operator used to evaluate the expression.

The types of relational operators available depend on the data type of the attribute. The data types are numerical (integer), string, and date/time. See Expression Token Operators.

SzValue
A string that contains the value to evaluate for the specified attribute. Note that integers, dates, and times must also be specified as strings. For example, the integer 123 is specified as "123" and the date November 25, 1994 can be specified as a date format supported by Microsoft SQL Server such as "11/24/1994".

For example, your application could create a machine filter with a token with Personal Computer architecture and MICROSOFT|OPERATING_SYSTEM|1.0 group class with attribute Operating System Name is Microsoft Windows NT. Your application could set this filter as the only filter on a machine container. When your application populates the machine container, the container contains folders that represent all computers that have the Windows NT operating system.

Example

// Function to add a token to a machine filter so that the
// filter finds computers with 486 processors.
// Verifies filter handle type and prints all tokens
// set in the filter.

SMS_STATUS AddTokenToMachineFilter(HANDLE hFilter)
                              // Handle to machine filter.
{
SMS_STATUS stat;
char szTag[BUFF_SIZE];
char *pszTag = szTag;
DWORD filterType;
stat = SmsGetFilterType(
    hFilter, // Handle to filter.
    &filterType, // Pointer to DWORD that will receive the filter type.
    pszTag // Pointer to string that will receive the filter tag.
    );

// If SmsGetFilterType succeeds, check that the filter
// is a MACHINE_FILTER. If not, return parameter error.
if (stat == SMS_OK) {
    if (filterType != MACHINE_FILTER) {
        printf("Invalid filter type.\n");
        return SMS_PARAMETER_ERROR;
    }
}
else {
    printf("SmsGetFilterType error: %d\n", stat);
    return stat;
}

// Create a TOKEN structure containing the criteria for finding
// the 486 processors.
TOKEN Token;
memset( &Token, 0, sizeof (TOKEN) ); // Clear the Token structure.
// Set the expression token to "Processor Name is like
// %486%".

// Set the architecture to Personal Computer.
strcpy( Token.szArchitecture, "Personal Computer");

// Set the group class to MICROSOFT|PROCESSOR|1.0.
strcpy( Token.szGroupClass, "MICROSOFT|PROCESSOR|1.0");

// Set the attribute name to "Processor Name".
strcpy( Token.szAttributeName, "Processor Name");

// Set the operator used to evaluate the expression.
// Use the string is like operator so that you get
// all types, for example, 486SX, 486, and so on.
Token.dwOp = QOP_STR_LIKE;

// Set the value to evaulate. Use the % wildcard to
// to find any name containing 486.
strcpy( Token.szValue, "%486%");

// Add the token to the machine filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use AND control token to connect
                             // expression to adjacent expressions.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else {
    printf("SmsAddToken error: %d\n", stat);
    return stat;
}

// Print all tokens set in the filter.
DWORD ctTokens;
printf("The filter contains the following tokens:\n");
stat = SmsGetTokenCount( hFilter,    // Handle to filter.
                            &ctTokens    // Pointer to token count.
                          );
// If the filter contains tokens, print all tokens for the filter.
if (stat == SMS_OK) {
    for (DWORD iLoop = 0; iLoop < ctTokens; iLoop++) {
       stat = SmsGetToken( hFilter, // Handle to filter.
                        iLoop,    // Index of token to retrieve.
                        &Token );// Pointer to TOKEN.
           if (stat == SMS_OK)
               printf("%s\n", Token.szTokenString);
        else {
            printf("SmsGetToken error: %d\n", stat);
            return stat;
        }
    }
}
else
    printf("SmsGetTokenCount error: %d\n", stat);

return stat;
}


Package Filters (PACKAGE_FILTER)

A package filter specifies the packages that are retrieved for a package container. A package filter enables your application to retrieve packages with workstation, sharing, or inventory properties set. If no package filter is set on a package container, all packages in the site database are retrieved for the container. Package filters can only be applied to package containers.

Using the SmsAddToken function, your application can add tokens to a package filter. Each expression token represents an attribute. For package filters, the tokens can be connected by using an OP_OR or OP_AND control token.

The TOKEN structure that contains the expression token must have the following members:

szName
A string that specifies the name of the package property to be evaluated by the expression.

Currently, only one property can be evaluated: PackageType. PackageType specifies that the type of package is being evaluated.

DwOp
A DWORD value that specifies the operator used to evaluate the expression.

For package filters, this operator can only be QOP_STR_EQ.

SzValue
A string that specifies the value to be evaluated for the property specified by szName.

There are three values available for PackageType: Workstation, Server, and Inventory.

For example, if PackageType is set for szName, the string "Workstation" would specify a package with Workstation properties set.

For example, your application could create a package filter with a token that specifies a PackageType of Workstation. Your application could set this filter as the only filter on a package container. When your application populates the container, it contains folders that represent all packages that have Workstation properties defined.

Example

// Function to add a token to a package filter so that
// the filter retrieves the package folders that
// are available for Run Command On Workstation jobs.

SMS_STATUS AddTokenToPackageFilter(HANDLE hFilter)
                         //  Handle to package filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// szName = "PackageType"
// dwOp = QOP_STR_EQ
// szValue = "Workstation"

// Set the package property.
strcpy( Token.szName, "PackageType");
// Set the operator to string equals.
Token.dwOp = QOP_STR_EQ;
// Set the type of package.
strcpy( Token.szValue, "Workstation");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_OR,  // Use the OR control token to
                             // add a token to the package filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Adds the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


Site Filters (SITE_FILTER)

A site filter specifies the sites that are retrieved for a site container. If no site filter is set on a site container, all sites in the site database (the current site and all sites below it in the site hierarchy) are retrieved for the container. Site filters can only be applied to site containers.

Using the SmsAddToken function, your application can add tokens to a site filter. The TOKEN structure that contains the expression token must have the following members:

szName
A string that specifies whether all sites in the site database are retrieved, or a specific site is retrieved.

"RootSite" specifies that all sites in the site database (the current site and all sites beneath it in the site hierarchy) are retrieved for the site container.

"SiteByCode" specifies that a specified site is retrieved for the site container. The szValue member contains the site code for the site.

DwOp
A DWORD value that specifies the operator used to evaluate the expression.

For site filters, this operator can only be QOP_STR_EQ. Note that if RootSite is specified for szName, this member is ignored.

SzValue
If szName is set to RootSite, this value should be NULL. If szName is set to SiteByCode, this value is a string that specifies the three-character site code of the site to retrieve.

For example, "TIM".

For site filters, the tokens can be connected only by using an OP_OR control token—this means that your application must pass OP_OR for the opAndOr parameter when calling the SmsAddToken function. In addition, only tokens that specify SiteByCode for szName can be combined. By combining SiteByCode tokens, your application can populate a site container with only the specified sites. If SiteByCode tokens are combined with a RootSite token, the RootSite token (which specifies all sites in the site database) will override the SiteByCode tokens and all sites will be retrieved.

For example, your application could create a site filter with two tokens (one for a site with site code JS1 and the other for a site ASH) and set this filter on a site container. When your application populates the site container, the container contains folders that represent the specified sites.

Note There are two methods for retrieving all sites in a site database:

If no site filter is set on a site container, all sites in the site database are retrieved and each site is represented as a top-level site folder. This is a flat list of sites. Note that if a site contains subsites, the subsites are also represented as subfolders of that site (in addition to the subsites' representation as top-level folders).

If a site filter with RootSite specified for szName is set on a site container, all sites in the site database are retrieved, but the sites are represented in accordance with their hierarchy in the SMS system. This means that only the current site is represented as a top-level folder in the container, and that the subsites directly beneath the current site are represented as subfolders of the current site's folder. If those second-level subsites have their own subsites, third-level subsites are represented as subfolders of the second-level subsites, and so on.

Example

// Function to add a token to a Site filter so that
// the filter retrieves the folder for
// Tim World, which has a site code of TIM.

SMS_STATUS AddTokenToSiteFilter(HANDLE hFilter)
                         //  Handle to Site filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// szName = "SiteByCode"
// dwOp = QOP_STR_EQ
// szValue = "TIM"

// Set the method of collection.
strcpy( Token.szName, "SiteByCode");
// Set the operator to string equals.
Token.dwOp = QOP_STR_EQ;
// Set the site code to TIM.
strcpy( Token.szValue, "TIM");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_OR,   // Must use the OR control token to
                             // add a token to a Site filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


SiteLimit Filters (SITELIMIT_FILTER)

A SiteLimit filter specifies the machine folders that are retrieved for a machine container. When a SiteLimit filter is set on a machine container, the machine folders in that container will be from the site (and optionally the domain) specified by the SiteLimit filter.

SiteLimit filters can be applied only to machine containers. If your application applies a SiteLimit filter to a site container, it will have no effect.

If no SiteLimit filter is set on a machine container, all machine folders in the site database (the current site and all sites below it in the site hierarchy) are retrieved for the container.

Using the SmsAddToken function, your application can add one token to a SiteLimit filter. If your application adds additional tokens to a SiteLimit filter, only the first token will be used—the other tokens will be ignored.

For SiteLimit filters, the tokens can only be connected using an OP_OR control token—this means that your application must pass OP_OR for the opAndOr parameter when calling the SmsAddToken function.

The TOKEN structure that contains the expression token must have the following members:

szName
A string that specifies the three-character site code of the site containing the machines to retrieve.

For example, "TIM".

Note that your application must specify a site code if it is specifying a domain for szValue.

SzValue
To specify only the site containing the machines to retrieve, set this value to NULL. To specify a domain within the site specified by szName, specify the domain name for this value.

For example, your application could create a SiteLimit filter with a token that specifies the site JS1 and the domain JSDOM and set this filter on a machine container. When your application populates the machine container, the container contains only machine folders from JSDOM domain within the JS1 site.

Example

// Function to add a token to a Site Limit filter so that
// the filter retrieves machine folders for the
// JSDOM domain in the JS1 site.

SMS_STATUS AddTokenToSiteLimitFilter(HANDLE hFilter)
                         //  Handle to Site Limit filter.
{
SMS_STATUS stat;
TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// szName = "JS1"
// szValue = "JSDOM"

// Set the site code.
strcpy( Token.szName, "JS1");
// Set the domain to JSDOM.
strcpy( Token.szValue, "JSDOM");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_OR,   // Must use the OR control token to
                             // add a token to a SiteLimit filter.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );

if (stat == SMS_OK)
    printf("The token was successfully added to the filter.\n");
else
    printf("SmsAddToken error: %d\n", stat);

return stat;
}


How Filters Affect the Population of a Container

After your application has created a filter with one or more tokens defined in it, the filter can be applied to a container. For a filter to affect how the container is populated, the container must support the filter's type. If the container does not support the filter's type, the filter will simply be ignored when populating the container.

Multiple filters can be applied to a container. For example, your application can apply a SITE_FILTER, a MACHINE_FILTER, and a GROUP_FILTER to a site container. However, multiple filters of the same type cannot be applied to a container. For example, two filters of type SITE_FILTER cannot be applied to a single site container.

Note that not all filters may affect the top-level folders retrieved in a container. Some filters may have no effect on the top-level folders, but will affect subfolders or scalars. For example, when a MACHINE_FILTER and a GROUP_FILTER are applied to a machine container, the MACHINE_FILTER determines the machine folders retrieved at the top level of the container, and the GROUP_FILTER determines the group folders contained within each machine folder. The SmsDescribeFolder function enables your application to retrieve a list of all filter types that act directly on a specified folder or container type.


Creating Filters

To create a filter
  1. Use the SmsCreateFilter function to create a filter for use on the container. After your application uses the SmsCreateFilter function to create a filter, the filter is empty, that is, it has no tokens set. Your application should use the filter functions to set the tokens for the new filter.
  2. Configure the filter by adding tokens to the filter. There are two types of tokens: expression tokens and control tokens.

    An expression token defines how to search for objects that have a specified relationship to a specified value for a specified attribute. A TOKEN structure is used to specify the criterion for the expression. Note that each filter type has its own set of attribute types that can be evaluated. For example, a PACKAGE_FILTER evaluates only the package type (example: package type is equal to Workstation), whereas a MACHINE_FILTER evaluates any attribute for any group for a particular architecture (example: Processor Name attribute of the MICROSOFT|PROCESSOR|1.0 group class for the Personal Computer architecture is like 486). In addition, each filter type requires specific members of the TOKEN structure to be assigned. For example, to add an expression token to a PACKAGE_FILTER, the TOKEN structure must specify the szName, DwOp, and szValue members. For a MACHINE_FILTER, the TOKEN structure must specify the szArchitecture, szGroupClass, szAttributeName, DwOp, and szValue members.

    For information about the tokens required for each filter type, see the appropriate topic under Filter Types.

    A control token can be a logical operator or parentheses. A logical operator (AND and OR) defines the relationship between two adjacent expressions. Parentheses enable expressions to be grouped together. A TOKEN structure is used to specify the type of logical operator.

    To add expression tokens to a filter, use the SmsAddToken function. When an expression token is added to a filter, a control token for a logical operator is also added at the same time.

    To delete, exclude, group, or ungroup tokens within a filter, use the SmsManipulateTokens function.

    To get information about an existing token in a filter, use the SmsGetToken function.

    To get the count of existing tokens in a filter, use the SmsGetTokenCount function.

To use the filter, your application must use the SmsSetFilter function to apply the filter to a container that supports the filter type. After applying the filter to a container, your application must use the SmsPopulate function to query the site database for folders that meet the criteria set by the filters applied to the container.


Setting Filters

To use a filter to specify the objects to retrieve for a container, your application must set the filter on the container before the container is populated. Note that a filter cannot be removed from a container after the filter has been set.

To set a filter on a container, use the SmsSetFilter function to apply the filter to the container. You can set one or more filters on a container. If you do not set a filter, all objects for the container type will be returned when the container is populated.

The type of the filter must be supported by the container. If the filter type is not supported by the container, SmsSetFilter does not apply the filter and returns a status of SMS_INVALID_FILTER_TYPE.

For information about the types of filters supported by each container, see the appropriate topic under Container Types.

SmsSetFilter allows only one filter of each type to be applied to a container. For example, two machine filters cannot be applied to the same filter. If a filter of the same type has already been applied to the container, SmsSetFilter does not apply the filter and returns a status of SMS_DUPLICATE_FILTER.

After SmsSetFilter has been used to set a filter on a container, the container keeps a copy of the filter for its own use. This means that any changes made to that filter will not be reflected in the filter that has been set on the container. After your application applies a filter to a container, it can use the SmsCloseFilter function to free memory used by the filter.

To get the list of filters applied to a container, use the SmsGetAllFilters function.


Getting the List of All Filters Applied to a Container

Using the SmsGetAllFilters function, your application can retrieve the handles to all the filters applied to a container.

After calling SmsGetAllFilters, your application can access the tokens set for each filter applied to a container. The following functions access the tokens in a filter:

SmsGetFilterType retrieves the filter type.

SmsGetTokenCount retrieves the count of the number of tokens.

SmsGetToken retrieves a specific token within a filter.

Important After SmsGetAllFilters is called for a container, the instance count for each filter applied to the container is incremented by 1. To decrement the count to the previous count value for each filter, your application must explicitly call SmsCloseFilter for each filter applied to the container.


FILTER_INFO Structures for Filters

The information about each type of filter can be retrieved using SmsEnumFilters. SmsEnumFilters returns the information about all filter types supported by the SMS API in an array of FILTER_INFO structures. The SMS API supports the following filter types:

Architecture Filter

Attribute Filter

Group Filter

Job Filter

Machine Filter

Package Filter

Site Filter

SiteLimit Filter


FILTER_INFO for Architecture Filters

The FILTER_INFO structure for architecture filters has the following members and values:

Member | Value
szTag | "Architecture filter"
filterType | ARCHITECTURE_FILTER
szName | "Name"
szValue | "Architecture"
szOperator | "Operator"
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)


FILTER_INFO for Attribute Filters

The FILTER_INFO structure for attribute filters has the following members and values:

Member | Value
szTag | "Attribute filter"
filterType | ATTRIBUTE_FILTER
szName | NULL (unused)
szValue | NULL (unused)
szOperator | NULL (unused)
szArchitecture | "Architecture"
szGroupClass | "GroupClass"
szAttributeName | "Attribute name"


FILTER_INFO for Group Filters

The FILTER_INFO structure for group filters has the following members and values:

Member | Value
szTag | "Group filter"
filterType | GROUP_FILTER
szName | "Name"
szValue | "GroupClass"
szOperator | "Operator"
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)


FILTER_INFO for Job Filters

The FILTER_INFO structure for job filters has the following members and values:

Member | Value
szTag | "Job filter"
filterType | JOB_FILTER
szName | "Type"
szValue | "Value"
szOperator | "Operator"
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)

The FILTER_INFO structure for a job filter indicates that the TOKEN structure for an expression token must contain values for the szName, szValue, and szOperator members.


FILTER_INFO for Machine Filters

The FILTER_INFO structure for machine filters has the following members and values:

Member | Value
szTag | "Machine filter"
filterType | MACHINE_FILTER
szName | NULL (unused)
szValue | "Value"
szOperator | "Operator"
szArchitecture | "Architecture"
szGroupClass | "GroupClass"
szAttributeName | "Attribute name"


FILTER_INFO for Package Filters

The FILTER_INFO structure for package filters has the following members and values:

Member | Value
szTag | "Package filter"
filterType | PACKAGE_FILTER
szName | "PackageType"
szValue | "Value"
szOperator | "Operator"
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)


FILTER_INFO for Site Filters

The FILTER_INFO structure for site filters has the following members and values:

Member | Value
szTag | "Site filter"
filterType | SITE_FILTER
szName | "Type"
szValue | "Site code"
szOperator | "Operator"
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)


FILTER_INFO for SiteLimit Filters

The FILTER_INFO structure for SiteLimit filters has the following members and values:

Member | Value
szTag | "SiteLimit filter"
filterType | SITELIMIT_FILTER
szName | "Site"
szValue | "Domain"
szOperator | NULL (unused)
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)


Filter Containers

Using the SMS API, your application can manage the queries in a site database. In the SMS API, queries are represented as persistent machine filters in a filter container.

You manage persistent machine filters within a filter container by using the Filter Container functions. You handle persistent machine filters and their tokens by using the Filter functions.

Using the SmsOpenFilterContainer function, your application can open a filter container. When your application opens a filter container, the filter container is populated with persistent filters.

After a filter container has been opened, your application can read the contents of each filter in the filter container and the tokens within each filter.

After a filter container is opened, the order of the filters within that particular filter container is fixed. Using the SmsGetNextFilter function, your application can access the filters in the filter container sequentially. SmsGetNextFilter returns the handle to the next filter in the list of filters within a filter container. To start at the beginning of the list again, use SmsRewind to reset a filter container's internal filter index so that its filters can be reiterated.

Using the SmsGetFilterByID function, your application can access a particular filter by its identifier. The identifier uniquely identifies the filter. The identifier is an eight-character identifier that the SMS system assigns to the persistent filter (which represents a query).

The steps to create a persistent filter are the same as those for creating a transient machine filter, with the addition of two steps to:

  • Set the scalars for the persistent filter.
  • Commit the machine filter to the filter container (that is, write the machine filter to the site database).

After a machine filter is committed to a filter container, that filter becomes a persistent filter.

Currently, the SMS API does not support deletion of persistent filters from the site database.

For information about creating persistent filters (SMS queries), see General Steps for Using the SMS API to Manage Queries.


Tokens

Filters and inventory rules folders are composed of expression tokens that are combined by control tokens:

Expression token
For filters, an expression token defines how to search for objects that have a specified relationship to a specified value for a specified attribute. An expression token is made up of an attribute, a relational operator, and a comparison value. A relational operator (such as "is equal to" or "is like") defines how the specified value should be compared with the actual value stored for the specified attribute. Depending on the type of filter that contains the token, an expression token's TOKEN structure uses the szName, szArchitecture, szGroupClass, and szAttributeName members to define the attribute. For example, job filters (and most other filters) use the szName member to specify the attribute, whereas machine filters use the szArchitecture, szGroupClass, and szAttributeName members.

For inventory rules folders, expression tokens represent the rule for collecting inventory on the package. An expression token uses only the szTokenString member of the TOKEN structure. The szTokenString member specifies the attributes that identify the file.

Control token
For both filters and inventory rules folders, a control token can be a logical operator or parentheses. A logical operator connects two expression tokens, two subclauses, or a combination of an expression and a subclause. A logical operator defines the relationship between two adjacent expressions or subclauses. Parentheses enable expressions to be grouped together.

There are two logical operators:

AND
Finds all objects that satisfy both expression tokens or subclauses connected by AND. You can use AND to narrow the list of objects you want to find. For example, the following filter finds all computers that have an 80386 processor, 4 MB of extended memory, and Microsoft Excel:
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%386%'
AND
MICROSOFT|X86_PC_MEMORY|1.0:Extended Memory (KByte) is greater than '4000'
AND
MICROSOFT|SOFTWARE|1.0:Name is like '%Excel%'

This filter returns a list of computers that satisfied all three expression tokens.

OR
Finds all objects that satisfy either (or both) of the two expression tokens or subclauses connected by the OR. You can use OR to assemble a set of objects. For example, the following filter finds all computers that have an 80386 processor, 4 MB of extended memory, or Microsoft Excel—or any combination of the three:
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%386%'
OR
MICROSOFT|X86_PC_MEMORY|1.0:Extended Memory (KByte) is greater than '4000'
OR
MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'

This filter returns a list of all computers that satisfied any one (or any combination) of the three expression tokens.

For additional information about logical operators, see Handling Tokens.


Handling Tokens

When you create or edit a filter or an inventory rules folder, you handle the expression tokens as clauses or subclauses.

A clause is the combination of an expression token (or subclause) and its adjacent logical operator. You must add and delete expression tokens as clauses.

A subclause is a set of expression tokens that can be logically treated as a single expression token. A subclause starts and ends with an expression token. You can explicitly group subclauses with parentheses.

In addition to combining expression tokens with logical operators, you can group a set of expression tokens together. A group is a set of expression tokens that are explicitly grouped together with parentheses. You can group only a set of expression tokens that form a subclause.

By making a set of expression tokens a group, you ensure that the group's expression tokens are treated as a single entity. Groups have a higher operator precedence than the logical operators (AND and OR).

Groups make complex queries easier to read. You can also use groups to clarify how OR clauses will be evaluated.


Precedence of Control Tokens

The SMS API engine evaluates clauses from top to bottom, using the following operator precedence:

  1. ( ) Parentheses
  2. AND
  3. OR

For example, because AND has precedence over OR, the following query finds all computers with the Microsoft Excel package, and all computers that have both an 80486 processor and the Microsoft Word package:

MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'
OR
MICROSOFT|SOFTWARE|1.0:Software Name is like '%Word%'
AND
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%486%"

If you switched the AND and OR in the previous query, the query would find all computers that have both the Microsoft Excel package and the Microsoft Word package, and all computers that have an 80486 processor:

MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'
AND
MICROSOFT|SOFTWARE|1.0:Software Name is like '%Word%'
OR
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%486%"

By grouping the final OR subclause, the following query would find all computers that have the Microsoft Excel package and that also have the Microsoft Word package, an 80486 processor, or both:

MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'
AND
(
    MICROSOFT|SOFTWARE|1.0:Software Name is like '%Word%'
    OR
    MICROSOFT|PROCESSOR|1.0:Processor Name is like '%486%"
)


Deleting Tokens

When you add an expression token, you add it as a clause. When you want to delete an expression token, you must delete it as a clause. A clause can be one of the following combinations:

  • A single expression token with its adjacent logical operator
  • A subclause with its adjacent logical operator


Single and Multiple Object Machine Filters

For simple machine filters, you usually specify the criteria for a single type of object. For example, you could create a filter that searches for computers with Microsoft Excel and an 80486 processor:

MICROSOFT|SOFTWARE|1.0:Software Name is 'Microsoft Excel'
AND
MICROSOFT|PROCESSOR|1.0:Processor Name is '486'

You can also build complex machine filters that search for multiple types of objects. For example, you could create a filter that searches for the type of computer specified in the preceding filter and another type such as computers with an 80386 processor and more than 20 MB free on drive C:

MICROSOFT|SOFTWARE|1.0:Software Name is 'Microsoft Excel'
AND
MICROSOFT|PROCESSOR|1.0:Processor Name is '486'
OR
MICROSOFT|PROCESSOR|1.0:Processor Name is '386'
AND
MICROSOFT|DISK|1.0:Disk Index is 'C'
AND
MICROSOFT|DISK|1.0:Free Storage (MByte) is greater than '20'

This filter searches for two distinct types of objects. Each object type is distinguished from its adjacent object type by the OR operator.

You can also search for a type of object that has multiple occurrences of a single group. A single occurrence of a group in an object's inventory is called an instance. Some groups (such as Disk and Software) can have multiple instances on a single computer. For example, a computer can have multiple instances of the group Software—one for each package installed (such as a Microsoft Excel version 4.0 package, Microsoft Word version 2.0 package, and so on).

For example, the following filter finds all computers that have the Microsoft Excel package, the Microsoft Word package, and an 80486 processor:

MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'
AND
MICROSOFT|SOFTWARE|1.0:Software Name is like '%Word%'
AND
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%486%"

When you want to search for an object that has any or all of a set of multiple instances, you can use the OR operator—but you must group the subclause containing the instances. For example, the following filter finds all computers with an 80486 processor and either the Microsoft Excel or Microsoft Word package:

(
    MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'
    OR
    MICROSOFT|SOFTWARE|1.0:Software Name is like '%Word%'
)
AND
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%486%"

If you do not group multiple instances together, SMS interprets the OR clauses as separate objects. For example, the following filter finds all computers with the Microsoft Excel package, and all computers that have both an 80486 processor and the Microsoft Word package:

MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'
OR
MICROSOFT|SOFTWARE|1.0:Software Name is like '%Word%'
AND
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%486%"

Note that some groups logically or physically can have only a single instance (such as identification). If you specify multiple instances of these groups for an object, the filter will return a false result for that portion of the query. For example, the following filter would return a false result because the Identification group is a single instance group (an object cannot have more than one Identification group):

MICROSOFT|IDENTIFICATION|1.0:SMSID is 'RUS00001'
AND
MICROSOFT|IDENTIFICATION|1.0:SMSID is 'UKR00002'


Inventory Rules Folder Tokens

In addition to the Inventory this package scalar, an inventory rules folder contains one or more tokens that represent the rule for collecting inventory on the package.

The inventory rules folder uses expression tokens and control tokens in the same way that filters do—except that each expression token contains a string that specifies attributes that identify the file, and the NOT operator is not supported. In addition, expression tokens for an inventory rules folder use only the szTokenString member of the TOKEN structure. In all other respects, the tokens for an inventory rules folder have the same behavior as tokens in a filter—expression tokens are connected by AND or OR operators, expression tokens can be grouped and ungrouped, and they can be deleted.

Note that the inventory rules folder must contain at least one expression token. An inventory rules folder that does not contain one or more expression tokens cannot be committed to the site database.

Each expression token contains a string that begins with the file keyword, the file name, and the file's attributes (note that the file attributes are optional):

file "filename" [fileattributes]

where

filename
Is a string that specifies the name of the file. This can be a file name with eight characters plus a three-character extension, or a long file name. The filename must be enclosed within quotation marks.

When your application reads a token from an existing inventory rules folder in the site database, filename specifies only the name of the file—not an explicit path.

When your application adds a token, an explicit path can be specified (such as C:\GRAPE\FRUIT.EXE). By using an explicit path, the SMS API engine can retrieve a value from the specified file when the retrieve key word is specified for a value. If only the file name is specified, the SMS API engine searches for the file in your application's current directory. When the token is added to the inventory rules folder by using SmsAddToken, the SMS API engine retrieves the value from the specified file. For example, the following token will retrieve the CHECKSUM value at offset 20 and of length 200:

file "c:\winword\winword.exe" CHECKSUM 20 200 retrieve

If your application were to read the same token from the inventory rules folder, the token string would contain the file name only (without the explicit path) and the actual value for the attribute (instead of the retrieve keyword). For example, the CHECKSUM for Microsoft Word version 6.0 would be the following:

file "winword.exe" CHECKSUM 20 200 7232

If filename specifies a location that does not contain the file, SmsAddToken will not add the token to the inventory rules folder and will return a status of SMS_PARAMETER_ERROR.

fileattributes
Can be one or more attributes of the file. Each type of attribute begins with a keyword followed by the specific value (or values) for the attribute.

For example, the following line would specify a valid string that could be used for szTokenString:

char *pszRule = "file \"winword.exe\" CHECKSUM 20 200 7232";

Note that your application is responsible for specifying a string containing a valid format as well as valid attributes for szTokenString. It is recommended that your application use the retrieve keyword so that the SMS API engine can retrieve the attribute value directly from the file, or that you use the FILETOKN.EXE utility provided with SMS to retrieve the attribute value from the file. Because there are numerous methods for calculating a CRC value, it is particularly important that you use the retrieve keyword or FILETOKN.EXE to calculate the CRC value if you are unsure whether your CRC calculation uses the CCITT-CRC algorithm.

For more information about the file attributes for tokens in an inventory rules folder, see File Attributes for Inventory Rules Folder Tokens.


File Attributes for Inventory Rules Folder Tokens

File Attributes for Inventory Rules Tokens

The following file attributes are supported for tokens in an inventory rules folder:

BYTE
CHECKSUM
COLLECT
CRC
DATE
LONG
SIZE
STRING
TIME
WORD

For all attributes except STRING, you can specify only one attribute for each type. For example, you can specify only one BYTE attribute for a file. A file can have up to four STRING attributes. The set of attributes specified for a file can appear in any order.

Note that the keywords such as file and retrieve, and the attributes such as byte and checksum, are not case-sensitive.

File attributes that are numerical values (and offset values), such as BYTE, CHECKSUM, and so on, can be specified as a decimal or hexadecimal value. Hexadecimal values must be preceded by 0x or 0X (for example, 0x1234 or 0X1234).

When an explicit path is specified for the filename, the SMS API engine can retrieve the value from the specified file when the retrieve key word is specified for the attribute's value.

The file attributes have the following format:

BYTE
Is an 8-bit value stored at a specific location in the file.

BYTE offset value

where offset is the data offset from the start of file (in bytes); and value is the value (in decimal notation) stored at the location specified by offset. Note that value can be retrieved from the file by using the retrieve keyword.

CHECKSUM
Is the sum of all values stored at a specific set of bytes.

CHECKSUM offset length value

where offset is the data offset where the summed values begin (in bytes); length is the total number of bytes that are summed; and value is the summed value (in decimal notation) of all the values stored in the specified range of bytes. Note that value can be retrieved from the file by using the retrieve keyword.

COLLECT
Is a keyword that tells the Inventory Agent to collect the file and send it with the computer's inventory.
CRC
Is the sum (and sequence) of all values stored at a specific set of bytes. Unlike CHECKSUM, CRC takes into account the sequence of the summed bytes. This makes it a more reliable identification of a file.

CRC offset length value

where offset is the data offset where the summed values begin (in bytes); length is the total number of bytes that are summed; and value is the summed value (calculated with the CCITT-CRC algorithm and specified in decimal notation) of all the values stored in the specified range of bytes. SMS uses the CCITT-CRC standard to evaluate the CRC value. You must specify a CRC value computed with the CCITT-CRC algorithm. Note that value can be retrieved from the file by using the retrieve keyword.

DATE
Is the date of the file.

DATE mm/dd/yy

where mm is the decimal value for the month; dd is the decimal value for the day; and yy is the decimal value for the year. Note that the date can be retrieved from the file using the retrieve keyword (that is, DATE retrieve).

LONG
Is a 4-byte (32-bit) value stored at a specific location in the file.

LONG offset value

where offset is the data offset (in bytes); and value is the 32-bit value (in decimal notation) stored at the offset. Note that value can be retrieved from the file by using the retrieve keyword.

SIZE
Is the size (32-bit) of the file (in bytes).

SIZE filesize

where filesize is the size of the file in bytes. Note that filesize can be retrieved from the file by using the retrieve keyword.

STRING
Is a specific string value stored at a specific location in the file.

STRING offset "string"

where offset is the data offset in bytes; and string is the string value stored at the location starting at offset. The string value must be enclosed within quotation marks. A file can have up to four STRING attributes. Note that the string must be less than 245 bytes; however, it is strongly recommended that you do not use four STRING attributes of maximum length. If the retrieve keyword is used, the SMS API engine will truncate the retrieved value to the first 244 characters if the string length is greater than 244 bytes. Note that string can be retrieved from the file by using the retrieve keyword.

TIME
Is the time of the file.

TIME hh:mm

where hh is the decimal value (using the 24-hour clock) for hours; and mm is the decimal value for minutes. Note that the time can be retrieved from the file by using the retrieve keyword.

WORD
Is a 2-byte (16-bit) value stored at a specific location in the file.

WORD offset value

where offset is the data offset from the start of file (in bytes); and value is the 16-bit value (in decimal notation) stored at the location specified by offset. Note that value can be retrieved from the file by using the retrieve keyword.


Combining Tokens in an Inventory Rules Folder

In an inventory rules folder, the set of files used to identify a package are combined by using AND and OR operators.

The AND operator evaluates to true when both files connected by the AND are found in the same directory.

The OR operator evaluates to true when any (or both) of the files connected by the OR are found in a directory.

AND has precedence over OR.

Note that the Inventory Agent program searches for the list of files within each directory. For example, if a package is defined as two files connected by an AND operator and the two files exist in different directories, the package is not detected:

FILE "CONFIG.SYS"
  AND
  FILE "SYSTEM.INI"

A package with AND operators is detected on a computer when all the file rules evaluate to true within the same directory. The example package would be found if CONFIG.SYS and SYSTEM.INI existed in the same directory (for example, C:\BACKUP).

For files connected by an OR operator, one or both must exist in a directory for the package to be detected. For example, if a package is defined as two files connected by an OR operator and the two files exist in the same directory, one instance of the package is detected:

FILE "CONFIG.SYS"
  OR
  FILE "SYSTEM.INI"

If CONFIG.SYS is detected in C:\ and SYSTEM.INI is detected in C:\WINDOWS, two instances of the example package are detected because the file rule evaluates to true in both directories.


Grouping Tokens in an Inventory Rules Folder

In an inventory rules folder, you can use parentheses to group files together as a single entity. Note that groups have higher precedence than the AND and OR operators. You can use parentheses to clarify how a package rule with a mix of AND and OR operators will be evaluated.

FILE "CONFIG.SYS"
  AND
  (
    FILE "SYSTEM.INI"
    OR
    FILE "VER.DLL"
  )

The example package is detected if CONFIG.SYS is found in a directory and either SYSTEM.INI or VER.DLL is found in that same directory.

If you remove the parentheses, the package is detected if CONFIG.SYS and SYSTEM.INI are found in the same directory or if VER.DLL is found in a directory:

FILE "CONFIG.SYS"
  AND
  FILE "SYSTEM.INI"
  OR
  FILE "VER.DLL"


Creating an Application that Uses the SMS API

This section describes the general steps for managing SMS objects that are represented as folders (sites, domains, machines, jobs, packages, site groups, and machine groups) and for managing queries, which are represented as persistent filters within a filter container.

General Steps for Using the SMS API to Manage SMS Objects

General Steps for Using the SMS API to Manage Queries


General Steps for Using the SMS API to Manage SMS Objects

Except for queries (which are represented as persistent filters in a filter container), you manage all objects in an SMS site database in the same manner, using the same set of functions.

The following procedures describe the general steps for reading the properties of existing objects, creating new objects, and deleting objects. These procedures apply to the following types of objects:

  • Sites
  • Inventoried objects (machines)
  • Packages
  • Jobs
  • Machine groups
  • Site groups

For information about managing queries using the SMS API, see General Steps for Using the SMS API to Manage Queries.

To create an application that uses the SMS API to manage objects in a site database
  1. Include the header file.
  2. Connect to the site database.
  3. Open a container.
  4. Set a filter.
  5. Fill the container.
  6. Access folder contents.
  7. Create a new folder.
  8. Delete a folder.
  9. Close filters, folders, and containers.
  10. Disconnect from the site database.


Include the header file

Include the SMSAPI.H file in source files that use the SMS API.

The SMSAPI.H file is the header file for the SMS API. It is located in the \MSSDK\INCLUDE directory of the Microsoft® Platform SDK CD-ROM.

Note that SMSAPI.H includes three other header files: QRYCODES.H, OBJECTTY.H, and SMSINFO.H. These files are also located in the \MSSDK\INCLUDE directory of the Platform SDK CD-ROM.

When building your application, you must also statically link SMSAPI.LIB and OBJECTTY.LIB. These static libraries are located in the \MSSDK\LIB\platform directory of the Platform SDK CD-ROM, where platform is the processor type of your build environment and target processor platform.


Connect to the site database

Use the SmsDataSourceConnect function to connect to the site database that you want to access.

Currently, SMS supports one database type: Microsoft SQL Server. However, the SMS API is designed to allow support of other types of databases in the future.

The SmsDataSourceConnect function takes two parameters:

  • A pointer to a DATASOURCE structure that specifies the site database to which you want to connect
  • A pointer to a handle that is assigned the handle to the specified database connection. You use the handle to open containers, filter containers, and filters for that site database.

Note that your application can connect to one site database at a time.

Example:

// Function to make a datasource connection to
// a site database. This function prompts for
// SQL server, loginID, password, and database,
// and then calls SmsDataSourceConnect to get
// a connection handle.

SMS_STATUS ConnectToSiteDatabase (HANDLE *phConnect)
                              // Pointer to handle to receive
                              // connection handle.
{

SMS_STATUS stat;

//Structure that specifies the site database to connect to.
DATASOURCE dsParams;
// Create string buffers for connecting to the database.
char szServer[33];
char szDb[31]; //maximum length of SQL Server database name is 30.
char szUser[31]; //maximum length of SQL Server Login ID is 30.
char szPasswd[31];

// Get database information from user and establish connection.
printf("Connect to site database.\n");

printf("SQL Server: ");
gets( szServer );

printf("Database: ");
gets( szDb );

printf("SQL Server Login ID: ");
gets( szUser );

printf("Password: ");
gets( szPasswd );

// Assign connection information to dsParams structure.
// The type of database.
dsParams.sqlParams.ds          = DB_SQL;
// SQL Server name.
dsParams.sqlParams.pszServer   = szServer;
// Login ID.
dsParams.sqlParams.pszUserName = szUser;
// Password for Login ID.
dsParams.sqlParams.pszPasswd   = szPasswd;
// Name of the site database.
dsParams.sqlParams.pszDbName   = szDb;
// Pointer to encryption function.
// No function is used in this example.
dsParams.sqlParams.pFunc       = NULL;
//Encryption key. No encryption key is used in this example.
dsParams.sqlParams.pszKey      = "";

// Use SmsDataSourceConnect to make a connection to the site database
// and assign the connection handle to hConnect.
stat = SmsDataSourceConnect( &dsParams, phConnect );

if (stat == SMS_OK) {
    printf("Connected to database %s on SQL Server %s as %s.\n",
            szDb, szServer, szUser);
}
else {
    printf("Cannot connect to SQL Server. Error code: %d\n", stat);
}

return stat;

}


Open a container

Use the SmsOpenContainer function to open a container for the type of object that you want to access in the site database.

The SmsOpenContainer function takes three parameters:

  • The type of container
  • A handle to the specified database connection
  • A handle that is assigned the handle to the container. You use the handle to manage the container.

Note that you can open multiple containers. For example, you could open two job containers to handle two types of job folders independently—one with filters set to get Run Command On Workstation folders and another container with filters set to get Share Package On Server job folders.

Example:

// Use SmsOpenContainer to open a job container.
cType = C_JOB; // Set container type to job.

stat = SmsOpenContainer( cType,       // Type of container.
                         hConnect,   // Handle to database
                                     // connection.
                         &hContainer // Assign handle to
                                     // container to hContainer.
                       );


Set a filter

If you do not set a filter, all objects for the container type will be returned when the container is populated. You can set one or more filters on a container.

To set a filter on the container to specify the objects you want to find
  1. Use the SmsCreateFilter function to create a filter for use on the container.

    The SmsCreateFilter function takes three parameters:

    • The type of filter
    • A handle to the specified database connection
    • A pointer to a handle that is assigned the handle to the new filter. You use the handle to manage the filter.

    Example:

    // Create a job filter.
HANDLE hFilter;
stat = SmsCreateFilter( JOB_FILTER, // Type of filter.
                        hConnect,   // Handle to database
                                    // connection.
                        &hFilter    // Assign handle to new filter
                      );            // to hFilter.
  2. Use the token functions to add tokens to the filter. Each token represents an expression used to identify the objects to find.

    To add a token to a filter, use the SmsAddToken function.

    The SmsAddToken function takes four parameters:

    • The handle to the filter
    • The operator control token, which specifies how the expression token is connected to the adjacent expression token or subclause
    • A pointer to the structure containing the expression token
    • The location where the token is to be inserted.

    Example:

    // Add a token to the job filter that
// finds all Run Command On Workstation jobs.

TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// "JobType is equal to Install".

// Set the attribute name to JobType.
strcpy( Token.szName, "JobType");
// Set the operator used to evaluate the expression.
Token.dwOp = QOP_STR_EQ; // Use the equals operator.
// Set the value to evaluate.
strcpy( Token.szValue, "Install");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use the AND control token to
                             // connect the expression to
                             // adjacent expressions.
                    &Token,  // Specifies the structure
                             // containing the expression
                             // token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );
  3. Use the SmsSetFilter function to apply the filter to the container.

    The SmsSetFilter function takes two parameters:

    • The handle to the container to which you want to apply the filter
    • The handle to the filter to assign to the container.
    // Apply the filter to the container.
stat = SmsSetFilter ( hContainer,  // Handle to container.
                      hFilter      // Handle to filter.
                    );
  4. If the filter will not be applied to any other containers, use the SmsCloseFilter function to close the filter and decrement the usage count of the filter. When the usage count is zero, the memory used by the filter is deallocated.


Fill the container

Use the SmsPopulate function to fill the container with objects that satisfy the criteria specified by the filters. The objects are represented as folders. The SmsPopulate function can retrieve folders in one of two modes: synchronous and asynchronous.

Synchronous
Your application waits until all folders that satisfy the filter criteria are retrieved and then goes on to the next line of code. To retrieve folders in synchronous mode, use POP_SYNC.
Asynchronous
Your application goes immediately to the next line of code while the SMS API engine retrieves all folders that satisfy the filter criteria. You can set additional flags that specify that the SMS API engine should set an event handle or post a message to a window each time a specified number of objects is retrieved.

For package containers and job containers, only synchronous mode is supported.

For containers that contain machine folders (site containers, site group containers, machine containers, and machine group containers), both modes are supported.

The SmsPopulate function takes three parameters:

  • The handle to the container
  • A DWORD that specifies the flags for the retrieval mode and the type of retrieval notification
  • A pointer to a NOTIFY structure that the SMS API engine uses to report the type of retrieval specified by flags in the second parameter.

For detailed information on and examples of using asynchronous mode to populate machine, machine group, site, and site group containers, see Populating Containers in Asynchronous Mode.

The following example shows how to call SmsPopulate to populate a job container (note that a job container can be populated only in synchronous mode):

// Populate the job container with the job folders specified
// by the filters applied to the container. Retrieve folders
// synchronously.

HANDLE hContainer; //Handle to container.
stat = SmsOpenContainer (C_JOB, hConnect, &hContainer);
stat = SmsPopulate( hContainer, // Handle to container.
                    POP_SYNC,  // Job folders can only be
                               // retrieved in synchronous mode.
                    NULL       // NULL because synchronous
                               // retrieval is used.
                  );


Access the folder contents

Access folder contents

After a container is populated with the folders you want to find, you can read the contents of each folder in the container and the scalars within each folder.

For top-level folders in containers, your application can retrieve folders only in sequence. (Note that subfolders within folders, such as program item folders within a package folder, can be retrieved by identifier with the SmsGetFolderByID function.) After a container has been populated, the order of the folders within that particular container is fixed. Using the SmsGetNextFolder function, your application can access the folders in the container sequentially. SmsGetNextFolder returns the handle to the next folder in the list of folders within a container. To start at the beginning of the list, use the SmsRewind function.

Example:

// Get the handles to all top-level folders in the container.
DWORD numFolders;
SmsGetFolderCount( hContainer, F_ANY, &numFolders);
printf("Container has %d folders\n\n", numFolders );

// Allocate memory for the top-level folders.
HANDLE *phFolders = (HANDLE *)malloc(numFolders * sizeof(HANDLE));

HANDLE hFolder;
// Loop to get handles to all top-level folders
// and write them to the allocated array.
  for (DWORD dwI = 0; dwI < numFolders; dwI++) {
    stat = SmsGetNextFolder( hContainer,
                             F_ANY,  // For all folder types.
                             &hFolder
                           );
      if (stat != SMS_OK) {
          printf("Error in retrieving a folder: %d\n", stat);
          break;
      }

      phFolders[dwI] = hFolder; //Assign the folder handle to
                                //next handle in the array.
  }

If a folder has subfolders, your application can use these same methods to access those folders. Note that SmsEnumFolderTypes returns a list of the types of subfolders that a folder can contain. SmsGetFolderCount returns the count of the subfolders of a specified type within a folder.

After your application gets the handle to a folder, your application can retrieve the scalars for that folder. The scalars can be retrieved in sequence or by the scalar name:

  • To retrieve scalars in sequence, use the SmsGetNextScalar function. SmsGetNextScalar retrieves the next scalar in the list of scalars within the folder and writes the scalar's information into a SCALAR structure.

    Example:

    // Get the next scalar in the folder and print it on the screen.
SCALAR scalar;

char szName[50];   //Buffer for scalar name.
char szValue[100]; //Buffer for string or time value.
char *pszTime;     //Buffer for conversion of time scalars.

scalar.pszName  = szName;
scalar.pszValue = szValue;
scalar.dwLen = sizeof(szValue)-1;

stat = SmsGetNextScalar(hFolder,  // Handle to folder.
                        &scalar   // Pointer to SCALAR struct
                        );

// Check the scalar type, display accordingly.
        switch (scalar.scType) {
        case SCALAR_STRING:
            printf("\t%20s: %s\n",
                   scalar.pszName,
                   scalar.pszValue);
            break;

        case SCALAR_INT:
            printf("\t%20s: %ld\n",
                   scalar.pszName,
                   scalar.dwValue);
            break;

        case SCALAR_TIME:
            // If there is a string equivalence use it.
            if (scalar.bStringEquivalence) {
                printf("\t%20s: %s\n",
                       scalar.pszName,
                       scalar.pszValue);
            } else {
                pszTime = ctime( &scalar.tValue );
                printf("\t%20s: %s",
                       scalar.pszName,
                       pszTime);
            }
            break;

        case SCALAR_BINARY:
            printf("\t%20s: Length of binary data is %d\n",
                   scalar.pszName,
                   scalar.dwLen);
            break;
        }
    }
  • To retrieve scalars by scalar name, use the SmsGetScalarByName function, which retrieves the scalar with the specified scalar name from the folder and writes the scalar's information into a SCALAR structure.

    Example:

    // Get the scalar named "Package ID" from the job folder
// specified by hFolder and print it on the screen.

SCALAR scalar;

//Buffer for string value. Package ID is 8 char.
char szValue[9];
scalar.pszValue = szValue;
scalar.dwLen = sizeof(szValue)-1;

stat = SmsGetScalarByName(hFolder,      // Handle to folder.
                          "Package ID", // Name of scalar to
                                        // retrieve.
                          &scalar       // Pointer to SCALAR to
                                        // place scalar data.
                          );

printf("\t%20s: %s\n", scalar.pszName, scalar.pszValue);

Note that the SmsGetScalarCount function returns the count of scalars within a folder.

If a folder no longer needs to be accessed, use the SmsCloseFolder function to close the folder and deallocate the memory used by the folder.


Create a new folder

To create a folder
  1. Use the SmsCreateFolder function to create a new folder. The SmsCreateFolder function can create folders within a container (top-level folders) or a subfolder within a folder.

    The SmsCreateFolder function takes four parameters:

    • The handle to the parent of the new folder (the parent can be a container or a folder)
    • The type of folder to create
    • An identifier for the folder
    • A pointer to a handle that is assigned the handle to the new folder. You use the handle to manage the new folder.

    After a new folder has been created, the folder is empty, that is, it has no scalars set within it. Using the SmsSetScalar function, your application must set the scalars for the new folder. A new folder also does not contain any subfolders. In addition, a new folder created by SmsCreateFolder is not linked to its parent folder (you use the SmsLinkFolder function to link a new folder to its parent). A new folder also is not added to the site database until you use the SmsCommitFolder function to write the folder to the database.

    Example:

    // This example shows how to create a
// Run Command On Workstation job
// folder for a job container.

cType = C_JOB; // Set container type to job.
// Open the job container.
stat = SmsOpenContainer( cType,
                         hConnect,
                         &hContainer);

HANDLE hFolder; // Declare a handle for the new folder.
stat = SmsCreateFolder ( hContainer,
                         F_INSTALLJOB, // Folder type is Run
                                       // Command On
                                       // Workstation.
                         NULL,         // SMS system assigns
                                       // ID. Therefore, this
                                       // parameter is ignored.
                         &hFolder     // Handle to new folder.
                        );
  2. Set the scalars for the new folder.

    Use the SmsSetScalar function to set the value of a scalar.

    To set the value of a scalar, both the scalar and its folder must have an access right of ACCESS_MODIFY or ACCESS_CREATE. If you do not have ACCESS_MODIFY or ACCESS_CREATE right to the scalar, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, the SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

    To get information (such as name, data type, access rights, and so on) about all scalars within a folder, use the SmsDescribeFolder function.

    The SmsSetScalar function takes two parameters:

    • The handle to the folder containing the scalar
    • A pointer to a SCALAR structure that contains the scalar data to be set

    Example:

    // Set the Package ID scalar for
// a Run Command On Workstation job.
SCALAR sc;                  // Declare SCALAR struct to hold
                            // scalar data.
char *szScalarName = "Package ID"; // Name of the scalar to set.
SCALARTYPE scType = SCALAR_STRING; // Data type of scalar.
char *pszScalarValue = "TIM00001"; // Value to set.
// Assign the scalar data to the sc structure.
sc.pszName = szScalarName;
sc.scType  = scType;
sc.dwLen = sizeof(pszScalarValue)-1;
sc.pszValue = pszScalarValue;

// Use SmsSetScalar to use the sc struct to set
// the scalar for the folder.
stat = SmsSetScalar( hFolder, // Handle to folder containing
                              // the scalar to set.
                     &sc      // Pointer to SCALAR struct
                              // containing value to set.
                   );
  3. After setting the scalars, use the SmsLinkFolder function to link the folder to its parent (the parent is the container or folder within which the new folder was created). Note that linking a folder only associates the folder to its parent within the application's memory—the folder is not written to the site database.

    Example:

    // Link the new folder to its parent.
stat = SmsLinkFolder( hFolder );
  4. Use the SmsCommitFolder function to write the new folder to the site database.

    Some folders require their direct parent folders to be committed in order to be written to the site database. If a folder requires its parent to be committed, the SmsCommitFolder function will return a status of SMS_PARENT_NEEDS_COMMIT.

    Example:

    // Write the new folder to the site database.
stat = SmsCommitFolder( hFolder );

    Note that the new folder is not written to the site database until the application calls the SmsCommitFolder function for that folder. If you do not want to write the new folder into the database, you can use the SmsCloseFolder function to deallocate the memory used by the new folder.


Delete a folder

To delete a folder
  1. After getting the handle to the folder you want to delete, use the SmsUnlinkFolder function to unlink the folder from its parent (the parent is the container or folder that contains the folder to delete). Note that unlinking a folder only detaches the folder from its parent within the application's memory—the folder is not deleted from the site database.

    Example:

    // UnLink the folder from its parent.
stat = SmsUnLinkFolder( hFolder );

    If the parent folder's handle is still open, your application can link the folder to its parent again.

  2. Use the SmsCommitFolder function to remove the unlinked folder from the site database.

    Example:

    // Remove the folder from the site database.
stat = SmsCommitFolder( hFolder );

    Note that the folder is not deleted from the site database until the application calls the SmsCommitFolder function for that folder. If you do not want to delete the folder from the database, do not commit the unlinked folder.

    Important After your application deletes a folder from the site database by using the SmsCommitFolder function, the handle for the deleted folder can only be used for closing the folder with the SmsCloseFolder function.


Close filters, folders, and containers

When your application is done accessing all folders and containers, ensure that all filters, folders, and containers are closed so that their memory is freed.

To close a filter, use SmsCloseFilter.

To close a folder, use SmsCloseFolder.

To close a container, use SmsCloseContainer.


Disconnect from the site database

When your application is done accessing the site database, use the SmsDataSourceDisconnect function to disconnect from the site database.


General Steps for Using the SMS API to Manage Queries

Your application can use the SMS API to manage the queries in a site database. In the SMS API, queries are represented as persistent machine filters in a filter container.

You manage persistent machine filters within a filter container by using the Filter Container functions. You handle persistent machine filters and their tokens by using the Filter functions.

The following procedures describe the general steps for reading the properties of existing persistent machine filters, and for creating new persistent machine filters.

To create an application that uses the SMS API to manage persistent machine filters (queries) in a site database
  1. Include the header file.
  2. Connect to the site database.
  3. Open and populate a filter container.
  4. Retrieve persistent filters.
  5. Retrieve scalars for the persistent filters.
  6. Retrieve tokens for the persistent filters.
  7. Create a persistent filter.
  8. Close filters and filter containers.
  9. Disconnect from the site database.


Include the header file

Include the SMSAPI.H file in source files that use the SMS API.

The SMSAPI.H file is the header file for the SMS API. It is located in the \MSSDK\INCLUDE directory of the Platform SDK CD-ROM.

Note that SMSAPI.H includes three other header files: QRYCODES.H, OBJECTTY.H, and SMSINFO.H. These files are also located in the \MSSDK\INCLUDE directory of the Platform SDK CD-ROM.

When building your application, you must also statically link SMSAPI.LIB and OBJECTTY.LIB. These static libraries are located in the \MSSDK\LIB\platform directory of the Platform SDK CD-ROM, where platform is the processor type of your build environment and target processor platform.


Connect to the site database

Use the SmsDataSourceConnect function to connect to the site database that you want to access.

Currently, SMS supports one database type: Microsoft SQL Server. However, the SMS API is designed to allow support of other types of databases in the future.

The SmsDataSourceConnect function takes two parameters:

  • A pointer to a DATASOURCE structure that specifies the site database to which you want to connect
  • A pointer to a handle that is assigned the handle to the specified database connection. You use the handle to open containers, filter containers, and filters for that site database.

Note that your application can connect to only one site database at a time.

Example:

// Function to make a datasource connection to
// a site database. This function prompts for
// SQL server, loginID, password, and database,
// and then calls SmsDataSourceConnect to get
// a connection handle.

SMS_STATUS ConnectToSiteDatabase (HANDLE *phConnect)
                              // Pointer to handle to receive
                              // connection handle.
{

SMS_STATUS stat;

//Structure that specifies the site database to connect to.
DATASOURCE dsParams;
// Create string buffers for connecting to the database.
char szServer[33];
char szDb[31]; //maximum length of SQL Server database name is 30.
char szUser[31]; //maximum length of SQL Server Login ID is 30.
char szPasswd[31];

// Get database information from user and establish connection.
printf("Connect to site database.\n");

printf("SQL Server: ");
gets( szServer );

printf("Database: ");
gets( szDb );

printf("SQL Server Login ID: ");
gets( szUser );

printf("Password: ");
gets( szPasswd );

// Assign connection information to dsParams structure.
// The type of database.
dsParams.sqlParams.ds          = DB_SQL;
// SQL Server name.
dsParams.sqlParams.pszServer   = szServer;
// Login ID.
dsParams.sqlParams.pszUserName = szUser;
// Password for Login ID.
dsParams.sqlParams.pszPasswd   = szPasswd;
// Name of the site database.
dsParams.sqlParams.pszDbName   = szDb;
// Pointer to encryption function.
// No function is used in this example.
dsParams.sqlParams.pFunc       = NULL;
//Encryption key. No encryption key is used in this example.
dsParams.sqlParams.pszKey      = "";

// Use SmsDataSourceConnect to make a connection to the site database
// and assign the connection handle to hConnect.
stat = SmsDataSourceConnect( &dsParams, phConnect );

if (stat == SMS_OK) {
    printf("Connected to database %s on SQL Server %s as %s.\n",
            szDb, szServer, szUser);
}
else {
    printf("Cannot connect to SQL Server. Error code: %d\n", stat);
}

return stat;

}


Open and populate a filter container

Use the SmsOpenFilterContainer function to open a filter container and populate the filter container with persistent filters (currently, queries are the only type of persistent filter).

The SmsOpenFilterContainer function takes two parameters:

  • A handle to the specified database connection.
  • A pointer to a handle that is assigned the handle to the filter container. You use the handle to manage the filter container.

Note that you can open multiple filter containers.

Example:

// Use SmsOpenFilterContainer to open a filter container.
HANDLE hFContainer;
stat = SmsOpenFilterContainer( hConnect, // Handle to database
                                         // connection.
                               &hFContainer // Assign handle
                                            // to filter container.
                       );


Retrieve persistent filters

After a filter container is opened, it is populated with persistent filters. You can read the contents of each filter in the filter container and the tokens within each filter.

There are two methods for retrieving persistent filters from a filter container:

  • Retrieve filters in sequence. After a filter container is opened, the order of the filters within that particular filter container is fixed. The sequence is determined by the order of retrieval of the persistent filters. Using the SmsGetNextFilter function, your application can access the filters in the filter container sequentially. SmsGetNextFilter returns the handle to the next filter in the list of filters within a filter container. To start at the beginning of the list again, use the SmsRewind to reset a filter container's internal filter index so that the filter container's filters can be reiterated.

    Example:

    // Get the handles to first 30 filters in the filter container
// and put them into an array of handles.

HANDLE hFilter;
DWORD numFilters = 30;
DWORD dwI = 0;
// Allocate memory for the filter handles.
HANDLE *phFilters = (HANDLE *)malloc(numFilters * sizeof(HANDLE));

// Loop to get handles to all filters
// and write them to the allocated array.
  // Initial value for loop.
  stat = SMS_OK;
  while(stat = SMS_OK)
  {
    // Get the next filter in the filter container.
    stat = SmsGetNextFilter( hFContainer, // Handle to filter
                             F_MACHINE,   // For machine filters.
                             &hFilter     // Assign handle to
                                          // filter to hFilter.
                           );

      // Check if this is the last filter in the filter container.
      // If last, break.
      if (stat == SMS_NO_MORE_DATA) {
          //last filter
          break;
      }
      // Check if there is an error retrieving the filter.
      if (stat != SMS_OK) {
          printf("Error in retrieving a filter: %d\n", stat);
          break;
      }
      // Assign the filter handle to the next handle in the array.
      phFilters[dwI] = hFilter;
      dwi++;
  }
  • Retrieve filters by filter identifier. Using the SmsGetFilterByID function, your application can access a particular filter by its identifier. The identifier uniquely identifies the filter. The identifier is an eight-character identifier that the SMS system assigns to the persistent filter (which represents a query). Note that the default queries provided with SMS have a six-character identifier.

    Example:

    // Get the "TIM00001" filter for
// the filter container with handle hFContainer.
char *pszID = "TIM00001";
HANDLE hMyFilter;
stat = SmsGetFilterByID(hFContainer, // Handle to filter
                                     // container.
                        F_MACHNE,    // Type is machine.
                        pszID,       // ID to retrieve.
                        &hMyFilter   // Assign handle to
                                     // hMyFilter.
                        );


Retrieve scalars for the persistent filters

After your application gets the handle to a persistent filter, your application can retrieve the scalars for that filter. A persistent filter has four scalars:

Query Key
String that corresponds to the identifier of the query. The identifier is an eight-character identifier that the SMS system assigns to the query when it is first added to the site database. Note that the default queries provided with SMS have a six-character identifier.
Name
String that corresponds to the Query Name in the Query Properties of the query in the SMS Administrator.
Comment
String that corresponds to Comment in the Query Properties of the query in the SMS Administrator.
Architecture
String that corresponds to Architecture in the Query Properties of the query in the SMS Administrator.

Unlike the scalars for folders, the scalars for persistent filters can be retrieved in sequence only.

To retrieve scalars in sequence, use the SmsGetNextScalar function. SmsGetNextScalar retrieves the next scalar in the list of scalars within the persistent filter and writes the scalar's information into a SCALAR structure. To start at the beginning of the list again, use SmsRewind to reset a filter's internal scalar index so that the filter's scalars can be reiterated.

Example:

// Get the next scalar in the persistent filter
// and print it on the screen.

SCALAR scalar;
char szName[50];          //Buffer for scalar name.
char szValue[BUFF_SIZE];  //Buffer for string value.

scalar.pszName  = szName;
scalar.pszValue = szValue;
scalar.dwLen = sizeof(szValue)-1;

// Retrieve the next scalar.
stat = SmsGetNextScalar(hFilter,  // Handle to filter.
                        &scalar   // Pointer to SCALAR struct to
                                  // place data for the scalar.
                        );

// Print the scalar name and value.
printf("\t%20s: %s\n", scalar.pszName, scalar.pszValue);


Retrieve tokens for the persistent filters

After your application gets the handle to a filter, your application can retrieve the tokens for that filter.

The tokens can be retrieved by token index.

To get a token from a filter, use the SmsGetToken function. SmsGetToken retrieves the token at the specified index in the filter and writes the token's information into a TOKEN structure.

Example:

// Print all tokens in the hFilter
// and print the token on the screen.
TOKEN token;
DWORD ctTokens;
DWORD dwLoop;
// Get count of tokens in filter
SmsGetTokenCount (hFilter,  // Handle to filter.
                  &ctTokens // Points to DWORD
                            // to receive count.
                 );
printf("Filter contains %d tokens", ctTokens);
printf("Tokens:\n");
// Loop to get all tokens and display them.
for (dwLoop = 0; dwLoop < ctTokens; dwLoop++) {
  // Clear token.
  memset(&token, 0, sizeof(TOKEN));
  // Get the token.
  stat = SmsGetToken(hFilter,  // Handle to filter.
                     dwLoop,   // Index of the token.
                     &token    // structure for the token data.
                          );
  // Print the display string version of the token.
  printf("%s\n", token.szTokenString);
}

Note that the SmsGetTokenCount function returns the count of tokens within a filter.


Create a persistent filter

Machine filters are the only type of persistent filters currently supported by the SMS API. The steps to create a persistent filter are the same as the steps for creating a transient machine filter, with addition of two steps to:

  • Set the scalars for the persistent filter.
  • Commit the machine filter to the filter container (that is, write the machine filter to the site database). After a machine filter is committed to a filter container, that filter becomes a persistent filter.
To create a persistent filter
  1. Use the SmsCreateFilter function to create a machine filter.

    The SmsCreateFilter function takes three parameters:

    • The type of filter.
    • A handle to the database connection.
    • A pointer to a handle that is assigned the handle to the new filter. You use the handle to manage the filter.

    Example:

    // Create a machine filter to stored as
// a persistent filter, that is, a query.
HANDLE hNewFilter;
stat = SmsCreateFilter( MACHINE_FILTER, // Machine filter.
                        hConnect,   // Handle to database
                                    // connection.
                        &hNewFilter // Assign handle to new filter
                      );            // to hNewFilter.
  2. Use the token functions to add tokens to the machine filter. Each token represents an expression used to identify the objects to find.

    To add a token to a filter, use the SmsAddToken function.

    The SmsAddToken function takes four parameters:

    • The handle to the filter
    • The operator control token, which specifies how the expression token is connected to the adjacent expression token or subclause
    • A pointer to the structure containing the expression token
    • The location where the token is to be inserted

    Example:

    // Add a token to the machine filter that
// finds all computers with a 486 processor.

TOKEN Token;
// Clear the Token structure.
memset( &Token, 0, sizeof (TOKEN) );

// Set the expression token to
// "Attribute Processor Name from group MICROSOFT|PROCESSOR|1.0
// contains 486 (ie, Processor Name is like %486%)".

// Set the architecture, groupclass, and attribute.
strcpy( Token.szArchitecture, "Personal Computer");
strcpy( Token.szGroupClass, "MICROSOFT|PROCESSOR|1.0");
strcpy( Token.szAttributeName, "Processor Name");
// Set the operator used to evaluate the expression.
Token.dwOp = QOP_STR_LIKE; // Use the 'is like' operator.
// Set the value to evaluate.
strcpy( Token.szValue, "%486%");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use the AND control token to
                             // connect the expression to
                             // adjacent expressions.
                    &Token,  // Specifies the structure for
                              // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );
  3. Set the scalars for the persistent filter.

    A persistent filter has four scalars:

    Query Key
    An eight-character identifier that the SMS system assigns to the query when it is first added to the site database. This scalar must be set by the SMS system. Your application cannot set this scalar.
    Name
    Corresponds to the Query Name in the Query Properties of the query in the SMS Administrator. This scalar must be set by your application when adding a persistent filter to the site database.
    Comment
    Corresponds to Comment in the Query Properties of the query in the SMS Administrator. This scalar is optional.
    Architecture
    Corresponds to Architecture in the Query Properties of the query in the SMS Administrator. This scalar must be set by your application when adding a persistent filter to the site database.

    Name and Architecture must be set by your application before a persistent filter is added to the site database by using SmsCommitFilter.

    Use the SmsSetScalar function to set the value of a scalar.

    The SmsSetScalar function takes two parameters:

    • The handle to the filter
    • A pointer to a SCALAR structure that contains the scalar data to be set

    Example:

    // Set the Name of the persistent filter (query).
SCALAR sc;                  // Declare SCALAR struct to hold
                            // scalar data.
char *szScalarName = "Name"; // Name of the scalar to set.
SCALARTYPE scType = SCALAR_STRING; // Data type of scalar.
char *pszScalarValue = "Find all 486s"; // Value to set.
// Assign the scalar data to the sc structure.
sc.pszName = szScalarName;
sc.scType  = scType;
sc.dwLen = sizeof(pszScalarValue)-1;
sc.pszValue = pszScalarValue;

// Use SmsSetScalar to use the sc struct to
// set the scalar for the filter.
stat = SmsSetScalar( hFilter,   // Handle to filter containing
                                 // the scalar to set.
                     &sc         // Pointer to SCALAR struct
                                 // containing value to set.
                   );
  4. Use the SmsCommitFilter function to write the new filter to the site database.

    The SmsCommitFilter function takes two parameters:

    • The handle to the filter to commit
    • The handle to the filter container that contains the filter

    Example:

    // Write the machine filter to the site database.
stat = SmsCommitFilter( hFilter,     // Handle to filter.
                        hFContainer  // Handle to filter
                                     // container.
                      );

    Note that the new machine filter is not written to the site database until the application calls the SmsCommitFilter function for that filter.


Close filters and filter containers

When your application has finished accessing all persistent filters and filter containers, ensure that all filters and filter containers are closed so that their usage counts are zero.

To close a filter, use SmsCloseFilter.

To close a filter container, use SmsCloseFilterContainer.


Disconnect from the site database

When your application has finished accessing the site database, use the SmsDataSourceDisconnect function to disconnect from the site database.


Installing Your Application

To install and run applications by using the SMS API, you must follow these rules:

  1. To run the application, it must be installed on either a Windows NT-based computer that has the SMS Administrator installed, or a Windows NT Server-based computer that is a primary site server.

    The SMS API requires the SMS DLLs that are provided with the SMS Administrator or an SMS primary site server.

    Caution You should install your application in its own directory. Do not install your application in a purgeable SMS directory. When the SMS Setup program is used to upgrade site components, the SMS Setup program removes all files from the SMS directories marked with the SM_DIRECTORY_PURGEABLE flag in the SYSTEM.MAP file. These files are then replaced by SMS Setup with the files on the SMS CD-ROM. The following directories are purgeable SMS directories:

    sms_install_drive:\smsroot\SITE.SRV\platform.BIN

    sms_install_drive:\smsroot\SITE.SRV\CLIENT.SRC

    sms_install_drive:\smsroot\SITE.SRV\MAINCFG.BOX\CLIENT.SRC\platform.BIN

    Note that you can create subdirectories within purgeable directories. These subdirectories and their contents will not be removed during an upgrade. However, if Systems Management Server is removed from the computer, the entire SMS root directory and all of its subdirectories are removed.

  2. On the installation computer, make sure that the following directory is in the path:

    sms_install_drive:\smsroot\SITE.SRV\platform.BIN

    where sms_install_drive is the drive where SMS is installed, smsroot is the name of the SMS installation directory, and platform.BIN is the processor type of the computer—X86.BIN, ALPHA.BIN, or MIPS.BIN.

    This directory must be in the path so that your application can locate the required SMS DLLs.

  3. The DLLs for the SMS API must be installed in the application directory or in the computer's path. The following DLLs are required:
    • SMSAPI.DLL
    • OBJECTTY.DLL

    You must make sure that the correct version of the DLLs is installed. Applications compiled for a particular version of the DLLs may not run with earlier versions. Additionally, the DLLs are matched to a particular minor version of the SMS base DLLs and will only run with that version of SMS. See DLL Version Checking for ISV Application Installation for details.

  4. You may also need to install the following:
    • SMSADDIN.EXE, if you want to register the application for launch from the SMS Administrator console. See Console Application Integration for details.
    • VB4SMS32.OLB, if your application is written in Visual Basic. See Using the SMS API with Visual Basic for details.

Note that SMSAPI.DLL, OBJECTTY.DLL, SMSADDIN.EXE, and VB4SMS32.OLB are redistributable and can be shipped with your application.


Example Scenario

You could use the SMS API to automate the setup of an application for immediate distribution and installation through Systems Management Server. Your setup program could install a network version of your application on a server and then use the SMS API to create a package for the application, specifying the installation directory where your setup program just installed your application and the workstation command lines used to install the application on individual computers. You could further extend the functionality of your setup program by creating a query to find computers that have an older version of your application. Your setup program could then create a Run Command On Workstation job that uses an upgrade workstation command line for your application's package and targets the computers that were found with your query.


SMS API Functions

The Systems Management Server API functions can be grouped as follows:

Connection Functions

Overview

SmsDataSourceConnect

SmsDataSourceDisconnect

Container Functions

Overview

SmsCloseContainer

SmsGetNextFolder

SmsOpenContainer

SmsPopulate

SmsRewind

SmsSetFilter

Filter Functions

Overview

SmsAddToken

SmsCloseFilter

SmsCreateFilter

SmsGetAllFilters

SmsGetFilterType

SmsGetToken

SmsGetTokenCount

SmsManipulateTokens

Filter Container Functions

SmsCloseFilterContainer

SmsCommitFilter

SmsGetFilterByID

SmsGetFilterID

SmsGetNextFilter

SmsOpenFilterContainer

Folder Functions

Overview

SmsCloseFolder

SmsCommitFolder

SmsCreateFolder

SmsDupFolder

SmsEnumFolderTypes

SmsGetFolderByID

SmsGetFolderCount

SmsGetFolderID

SmsGetFolderType

SmsGetNextFolder

SmsLinkFolder

SmsRewind

SmsUnlinkFolder

Scalar Functions

Overview

SmsGetNextScalar

SmsGetScalarByName

SmsGetScalarCount

SmsSetScalar

Static Information Functions

Overview

SmsAPIVer

SmsDescribeFolder

SmsEnumContainers

SmsEnumFilters

SmsEnumFolders

SmsEnumObjects

SmsEnumObjectTypes


Connection Functions

The connection functions enable an application to connect to a site database and disconnect from a site database. The handle that is returned from SmsDataSourceConnect is used when accessing a container, accessing a filter container, or creating a filter.

Although SMS currently supports only Microsoft SQL Server as a datasource (that is, an SMS site database), the functions are designed to be independent of the type of the datasource so that other types of datasources can be supported in the future.

An application can connect to one database at a time.

SmsDataSourceConnect

SmsDataSourceDisconnect


SmsDataSourceConnect

The SmsDataSourceConnect function connects to the site database that your application will access.

SMS_STATUS SmsDataSourceConnect(
  DATASOURCE *pd, // Pointer to DATASOURCE union containing the
                  // connection information.
  HANDLE *phConn  // Pointer to handle to receive connection handle.
);

Parameters

pd
Specifies a DATASOURCE union that specifies the site database to which your application needs to connect. (DATASOURCE is a union of structures.) Before calling SmsDataSourceConnect, your application must set the appropriate values for the members in this structure. For Microsoft SQL Server, your application must set the server name, login identifier, password, database, public encryption key, and a pointer to a decryption function for the sqlParams structure within the DATASOURCE union. (The decryption function is a callback function that SmsDataSourceConnect uses to decrypt the pszUserName and pszPasswd members so that they can be used as the login identifier and password for connecting to the site database.) If the pointer to the decryption function is set to NULL or the encryption key is NULL, no decryption function is called.

For an example of encryption and decryption functions and how they are used with SmsDataSourceConnect, see Sample Decryption and Encryption Functions.

phConn
Specifies the handle that will receive the handle to the specified database connection. You use the handle to open, access, and close containers for that site database.

Return Values

The SmsDataSourceConnect function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_SQL_ERROR
The connect failed because of a SQL Server error.
SMS_INVALID_DATASOURCE
The connect failed because the datasource type could not be registered.
SMS_INVALID_HANDLE
The database connection could not be made because of a memory allocation failure.
SMS_ALREADY_CONNECTED
Your application has an existing connection to the site database. An application can have only one connection to a site database at one time.

Remarks

SmsDataSourceConnect assigns a connection handle to the specified handle. Your application uses the handle to open, access, and close containers for that site database.

Currently, SMS supports one database type: Microsoft SQL Server. However, the SMS API is designed to allow support of other types of databases in the future.

Note that your application can connect to one site database at a time. In addition, your application can have only one connection to that site database.

After your application has finished accessing the site database, it should free the connection by calling the SmsDataSourceDisconnect function.

Example

The following example connects to a SQL Server JS1 with a site database SMSBritain using login identifier jonathan and password hermes.

HANDLE hConnect;
DATASOURCE dsParams;

    dsParams.sqlParams.ds          = DB_SQL;
    dsParams.sqlParams.pszServer   = "JS1";
    dsParams.sqlParams.pszUserName = "jonathan";
    dsParams.sqlParams.pszPasswd   = "hermes";
    dsParams.sqlParams.pszDbName   = "SMSBritain";
    dsParams.sqlParams.pFunc       = NULL;
    dsParams.sqlParams.pszKey      = "";

stat = SmsDataSourceConnect( &dsParams, &hConnect );

See Also

SmsDataSourceDisconnect


SmsDataSourceDisconnect

The SmsDataSourceDisconnect function releases the site database connection that was established by SmsDataSourceConnect.

SMS_STATUS SmsDataSourceDisconnect(
  HANDLE hConn  // Handle to database connection.
);

Parameters

hConn
Specifies the handle to the database connection to be closed.

Return Values

The SmsDataSourceDisconnect function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The connection handle is not valid.

See Also

SmsDataSourceConnect


Container Functions

The container functions enable an application to open a container, apply a filter to a container, populate a container with folders, rewind folders in a container, retrieve the number of folders in a container, and close a container.

SmsCloseContainer

SmsOpenContainer

SmsPopulate

SmsRewind

SmsSetFilter

An application can also call the SmsEnumContainers function to retrieve a list of all the types of containers supported by the SMS API.

SmsGetNextFolder enables an application to retrieve the top-level folders in a container by sequence. The sequence of folders within a container is determined by the order in which the SMS API engine retrieved the folders from the site database. Note that SmsGetFolderByID cannot be used to retrieve a top-level folder in a container.


SmsCloseContainer

The SmsCloseContainer function closes an open container.

SMS_STATUS SmsCloseContainer(
  HANDLE hContainer  // Handle to container.
);

Parameters

hContainer
Specifies the handle to the container to close.

Return Values

The SmsCloseContainer function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The specified container handle is not valid.

Remarks

When your application closes a container, any open folders within the container are not closed automatically. Your application must explicitly close folders that have been opened using SmsCreateFolder, SmsGetNextFolder, or SmsGetFolderByID. Therefore, you can open a container's folders, close the container, and still have access to the folders.

See Also

SmsCreateFolder, SmsGetNextFolder, SmsGetFolderByID


SmsOpenContainer

The SmsOpenContainer function opens a container for the type of object that you want to access in the site database.

SMS_STATUS SmsOpenContainer(
  DWORD cType,         // Type of container.
  HANDLE hConnection,  // Handle to database connection.
  HANDLE *phContainer  // Pointer to the handle that will receive
                       // the pointer to the new container.
);

Parameters

cType
Specifies the type of container to open. See Container types.
hConnection
Specifies the handle to the database connection. A database connection is established using SmsDataSourceConnect.
phContainer
Points to the handle that is assigned the handle to the container. You use the handle to manage the container.

Return Values

The SmsOpenContainer function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified connection handle is not valid.
SMS_INVALID_CONTAINER_ID
An unknown container type was specified.

Remarks

Note that you can open multiple containers. For example, you could open two job containers to handle two types of job folders independently—one with a filter set to get Run Command On Workstation job folders (F_INSTALLJOB), and another container with a filter set to get Share Package On Server job folders (F_SRVINSTALL).

After your application uses the SmsOpenContainer function to open a container, the container is empty, that is, it contains no folders. Your application must use the SmsPopulate function to fill the container with objects from the site database. Before your application calls the SmsPopulate function, it can apply filters that specify criteria for retrieving objects (which are represented as folders within the container) from the database. Your application can create filters by using the SmsCreateFilter function, set tokens for the filter by using the SmsAddToken function, and apply the filter to the container by using the SmsSetFilter function. After applying filters to a container, your application must use the SmsPopulate function to query the site database for folders that meet the criteria set by the filters applied to the container. If no filters are applied to a container, all objects of the type supported by the container are retrieved by SmsPopulate.

After populating a container, your application can access the folders by using the SmsGetNextFolder function. For subfolders within a folder, SmsGetFolderByID can also be used to retrieve subfolders. Note that SmsGetFolderByID cannot be used to retrieve a top-level folder in a container.

After your application has finished using a container, it should free the memory used by the container by calling the SmsCloseContainer function.

If your application needs to open a filter container, it must call the SmsOpenFilterContainer function to open a filter container.

See Also

SmsDataSourceConnect, SmsPopulate, SmsCreateFilter, SmsSetFilter, SmsSetFilter, SmsGetNextFolder, SmsGetFolderByID, SmsCloseContainer, SmsOpenFilterContainer


SmsPopulate

The SmsPopulate function fills the container with objects from the site database.

SMS_STATUS SmsPopulate(
  HANDLE hContainer,  // Handle to container.
  DWORD dwOptions,    // Flags for retrieval mode and notification.
  NOTIFY *pNotify     // Pointer to NOTIFY structure for the
                      // retrieval notification.
);

Parameters

hContainer
Specifies the handle to the container to populate.
dwOptions
Specifies the flags for the retrieval mode and the type of retrieval notification.

For package containers and job containers, only synchronous mode is supported.

For containers that contain machine folders (site container, site group container, machine container, and machine group container), the SmsPopulate function can retrieve folders in one of two modes:

Synchronous
Your application waits until all folders that satisfy the filter criteria are retrieved and then goes on to the next line of code. To retrieve folders in synchronous mode, use POP_SYNC.
Asynchronous
Your application goes immediately to the next line of code while the SMS API engine retrieves all folders that satisfy the filter criteria. You can set additional flags that specify that the SMS API engine should set an event handle or post a message to a window each time a specified number of objects are retrieved. The frequency of retrieval notification, the event handle, and window handle and message are specified by the NOTIFY structure specified by pNotify.

Important An event is a type of synchronization object provided by the Win32 API. It is the responsibility of your application to create a valid event object and reset the event object by using the synchronization functions of the Win32 API. Given a handle to a valid event object through the NOTIFY structure, the SMS API engine sets the event to the signaled state when the specified number of folders have been retrieved.

To retrieve folders in asynchronous mode, set the POP_ASYNC flag.

If the POP_ASYNC and POP_EVENT flags are set for dwOptions, the SMS API engine sets the event specified by the hEvent member of pNotify structure to the signaled state. The SMS API engine sets an event handle to the signaled state each time a specified number of objects are retrieved and when all objects are retrieved. If the POP_ASYNC and POP_WINDOW flags are set for dwOptions, the SMS API engine posts the message specified by the uiMsg member of pNotify structure to the window specified by the hwnd member. The SMS API engine posts a message to a window each time a specified number of objects are retrieved and when all objects are retrieved.

Important Asynchronous retrieval can be used only on machine, machine group, site, and site group containers. Although the SmsPopulate function applies to containers, the asynchronous behavior goes into effect only when retrieving machine folders from their parent folders or containers. For machine containers, the asynchronous behavior is in effect when SmsPopulate is called, because machine folders are the top-level folder in the container.

However, the machine folders in a site container are lower-level folders contained within the domain folders within site folders. When your application uses asynchronous population on a site container, the asynchronous retrieval takes effect when your application accesses the folder containing the machine folders—that is, the domain folder. The site folders and the domain folders are not retrieved asynchronously. This means that your application should wait on an event only after machine retrieval in a domain folder or a machine container has been triggered—the event will never be set to the signaled state if no machines are retrieved, and the wait function (such as WaitForSingleObject) will time out.

In addition, when using asynchronous retrieval with events or window messages for site containers and site group containers, there are some special issues that need to be addressed (such as triggering machine retrieval in domain folders). For more detailed information, see Populating Containers in Asynchronous Mode.

If only the POP_ASYNC flag is set, SmsPopulate performs no notification.

POP_SYNC
Retrieve folders in synchronous mode.
POP_ASYNC
Retrieve folders in asynchronous mode.
POP_EVENT
Set an event handle each time the specified number of objects is retrieved and when all objects have been retrieved. In the pNotify structure, your application should specify a frequency and an event handle that will be set by the SMS API engine .
POP_WINDOW
Post a message to a window each time the specified number of objects is retrieved or when all objects have been retrieved. In the pNotify structure, your application should specify a frequency, a window handle, and the message to post to the window.
pNotify
Specifies a pointer to a NOTIFY structure that the SMS API engine uses to report retrieval notification.

If the POP_SYNC flag is specified for dwOptions, set this value to NULL.

This structure is only used if POP_ASYNC is specified in dwOptions. The dwFreq member specifies the frequency of retrieval notification. Each time the SMS API engine has retrieved the number of objects specified by dwFreq, it notifies your application by setting an event or by posting a message to a window. In addition, the SMS API engine notifies your application when all objects have been retrieved.

The type of notification depends on the flags set in the dwOptions parameter. If the POP_ASYNC and POP_EVENT flags are set for dwOptions, the SMS API engine sets the event specified by the hEvent member to the signaled state. If the POP_ASYNC and POP_WINDOW flags are set for dwOptions, the SMS API engine posts the message specified by the uiMsg member to the window specified by the hwnd member.

Note Your application is responsible for specifying a valid event handle for the hEvent member of the NOTIFY structure.

Return Values

The SmsPopulate function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified container handle is not a valid container handle.
SMS_CONTAINER_POPULATED
The specified container is already populated.
SMS_EMPTY
The container was populated but returned no folders—no objects of the type specified were found in the site database.
SMS_ERROR
An unexpected error occurred.

Note that an insufficient size for the tempdb on the SQL Server containing the site database can cause this error to occur.

To size the tempdb, you should allocate 2K per machine (that is, 2K for each inventoried object, including objects of all architectures such as Personal Computer, SMSEvent, UserGroups, and so on). The log device should be at least 20 percent of the size of the data device. For example, if you have 50,000 machines in your SMS database, you should allocate at least 100 MB total for the tempdb and at least 20 MB for the tempdb log.

SMS_INVALID_PARAMETER
Asynchronous population was specified for a container type that does not support asynchronous population. Note that job containers and package containers do not support asynchronous population.

—or—

An invalid window handle was specified in the hwnd member of the pNotify structure.

SMS_NOT_READY
SmsPopulate was used to retrieve folders in asynchronous mode and an attempt was made to access folders in a container before some or all folders were retrieved from the site database.

Remarks

SmsPopulate initiates the retrieval process, which is carried out by the SMS API engine—SmsPopulate does not perform the actual retrieval itself. For asynchronous population, SmsPopulate returns immediately while the SMS API engine retrieves folders from the site database. The SMS API engine uses the information in the NOTIFY structure passed to it by SmsPopulate to post a window message or signal an event each time the specified number of folders is retrieved and when all folders are retrieved.

SmsPopulate retrieves the objects (which are represented as folders within the container) that satisfy the criteria specified by the filters applied to the container.

Filters can only be applied to containers. However, a filter may not take effect on the first level of folders within a container. Filters are only applied to folders that accept the filter's filter type.

For example, if an attribute filter (ATTRIBUTE_FILTER) is applied to a site container, the attribute filter has no effect on the set of domain folders or site folders that are retrieved when the site container is populated. However, the attribute filter will be applied to the machine folders within the domain folders. For each machine folder, the attribute filter determines which group folders are retrieved.

If your application does not set a filter on the container by using the SmsSetFilter function, SmsPopulate fills the container with folders that represent all objects (of the type supported by the container) in the site database.

Note Folders retrieved by SmsPopulate represent the set of objects in the site database at the time when SmsPopulate is called by your application. Any objects added to the site database after SmsPopulate is called are not reflected in the list of folders within the container. Currently, containers cannot be refreshed. To get the latest information from the site database, your application must open and populate a new container, and then access the information in the new container.

Example

For examples of asynchronous population, see Populating Containers in Asynchronous Mode.


SmsRewind

The SmsRewind function resets the internal folder and/or scalar index of an object (container, folder, filter container, or filter) so that the object's subfolders and scalars can be reiterated.

SMS_STATUS SmsRewind(
  HANDLE hObject,  // Handle to the container, folder, filter, or
                   // filter container to rewind.
  DWORD dwOptions  // Items to rewind.
);

Parameters

hObject
Specifies the object to rewind. SmsRewind can be used to rewind the top-level folders within a container, the subfolders and/or scalars directly within a folder, the persistent filters within a filter container, or the scalars within a persistent filter.
dwOptions
Specifies the items to rewind within the object specified by hObject.

If hObject is a filter container, dwOptions specifies the type of persistent filter to rewind. See Filter Types. To rewind all filter types within the filter container, specify F_ANY as the filter type. Currently, MACHINE_FILTER is the only type of persistent filter supported by filter containers.

If hObject is a persistent filter, dwOptions must specify that the scalars be rewound with RW_ALL or RW_SCALAR.

If hObject is a container, dwOptions specifies whether to rewind a specific type of folder or all folders at the top level of the container. If RW_FOLDER or RW_ALL is specified, all subfolders that are directly beneath the object specified by hObject are rewound. A specific folder type can also be specified for dwOptions. See Folder Types. Note that only one specific folder type can be rewound by specifying a folder type (you cannot rewind multiple types with a single call to SmsRewind—unless you rewind all types).

If hObject is a folder, dwOptions specifies whether to rewind a specific type of folder, all folders, all scalars, or all folders and scalars directly beneath the folder.

RW_FOLDER
Rewind subfolders only.
RW_SCALAR
Rewind scalars only.
RW_ALL
Rewind both subfolders and scalars.
folder type
Rewind only a specific folder type within the folder. For the manifest constants for folders, see Folder Types.

Return Values

The SmsRewind function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.
SMS_INVALID_FILTER_ID
No filters of the specified filter type were found in the filter container.

Remarks

Because SmsGetNextFolder and SmsGetNextScalar read folders and scalars sequentially, your application must use SmsRewind to start at the beginning of the scalar or folder list again. SmsRewind enables your application to iterate the folders or scalars again from the beginning of the folder or scalar list. Note that SmsRewind also enables your application to rewind the persistent filters in a filter container or to rewind the scalars within a persistent filter.

When your application calls SmsGetNextFolder or SmsGetNextScalar and SMS_NO_MORE_DATA is returned, this means that your application has reached the end of the folder or scalar list and the folder needs to be rewound using SmsRewind.

The SmsRewind function is not recursive. If RW_ALL, RW_FOLDER, or RW_SCALAR is specified by dwOptions, only the count for the folders or scalars directly beneath the folder, container, filter container, or persistent filter specified by hObject are rewound.

If your application specifies a subfolder type with dwOptions, only folders of that specific folder type within that object are rewound. Note that the folder type must be directly beneath the specified object. By specifying the folder type, your application can rewind a single folder type (leaving the counts for the other folder types unaffected) rather than rewinding all folders. Specific folder types can only be rewound one type at a time.

See Also

SmsGetNextFilter, SmsGetNextFolder, SmsGetNextScalar


SmsSetFilter

The SmsSetFilter function applies the specified filter to a container.

SMS_STATUS SmsSetFilter(
  HANDLE hContainer,  // Handle to container.
  HANDLE hFilter      // Handle to filter.
);

Parameters

hContainer
Specifies the handle to the container to which you want to apply the filter.
hFilter
Specifies the handle to the filter to assign to the container.

Return Values

The SmsSetFilter function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified container or filter handle is not valid.
SMS_INVALID_CONTAINER_ID
An unknown container type was specified.
SMS_CONTAINER_POPULATED
The specified container is already populated.
SMS_INVALID_CONNECTION_HANDLE
The filter's connection handle does not match the container's connection handle.
SMS_DUPLICATE_FILTER
A filter of the specified type has already been set on the container.
SMS_INVALID_FILTER_TYPE
Your application has attempted to set a filter that is incompatible with the specified container.
SMS_EMPTY
Your application did not call SmsAddToken to add tokens to the filter.

Remarks

The type of the filter must be supported by the container. If the filter type is not supported by the container, SmsSetFilter does not apply the filter and returns a status of SMS_INVALID_FILTER_TYPE.

SmsSetFilter allows only one filter of each type to be applied to a container. For example, two machine filters cannot be applied to the same container. If a filter of the same type has already been applied to the container, SmsSetFilter does not apply the second filter and returns a status of SMS_DUPLICATE_FILTER.

After SmsSetFilter has been used to set a filter on a container, the container keeps a copy of the filter for its own use. This means that any changes made to the filter will not be reflected in the filter that has been set on the container. In addition, a filter cannot be removed from a container after it has been set.

To get the list of filters applied to a container, use the SmsGetAllFilters function.

After your application applies a filter to a container, it can close the filter (to free memory used by the filter) by using the SmsCloseFilter function. Note that the container maintains its own copy of a filter after the filter has been applied.

See Also

SmsGetAllFilters, SmsCloseFilter


Filter Functions

Before populating a container, your application can set filters on the container to specify criteria used to select the folders to retrieve from the site database.

Your application can configure a filter by adding tokens to the filter. There are two types of tokens: expression tokens and control tokens. An expression token defines how to search for objects that have a specified relationship to a specified value for a specified attribute. A control token can be a logical operator or parentheses. A logical operator defines the relationship between two adjacent expressions. Parentheses enable expressions to be grouped together.

The filter functions enable your application to create and close filters, add tokens to a filter, manipulate existing tokens (delete, exclude, group, and ungroup), get the count of tokens within a filter, and get the filter type. The SmsGetAllFilters function enables your application to retrieve the list of filters applied to a container.

Note that the token functions (SmsAddToken, SmsGetToken, SmsGetTokenCount, and SmsManipulateTokens) are also used to add and manage the tokens in an inventory rules folder (F_INVENTORY). In an inventory rules folder, each expression token represents the criteria used to identify a file. The set of tokens in an inventory rules folder represents the rule used to identify the package.

SmsAddToken

SmsCloseFilter

SmsCreateFilter

SmsGetAllFilters

SmsGetFilterType

SmsGetToken

SmsGetTokenCount

SmsManipulateTokens


SmsAddToken

The SmsAddToken function adds a token at the specified index in the specified filter or inventory rules folder.

SMS_STATUS SmsAddToken(
  HANDLE hFilter, // Handle to filter or inventory rules folder.
  ANDOR opAndOr,  // Control token for connecting the expression to
                  // adjacent expression.
  TOKEN *pTokenInfo,
                  // Pointer to token structure containing the
                  // expression token.
  INT iIndex      // Location to insert the control token and
                  // expression token.
);

Parameters

hFilter
Specifies the handle to the filter or inventory rules folder where the token will be added.
opAndOr
Specifies whether an OP_AND or OP_OR control token is used to connect to the adjacent expression token or subclause. See the ANDOR enumerated type.

Important For attribute filters, group filters, site filters, and architecture filters, tokens can only be connected using an OP_OR control token—this means that your application must pass OP_OR for the opAndOr parameter when calling the SmsAddToken function to add a token to one of these filter types. If your application passes OP_AND for the opAndOr parameter, a status of SMS_PARAMETER_ERROR is returned.

pTokenInfo
Specifies the TOKEN structure containing the information for the expression token to add to the filter or inventory rules folder.
iIndex
Specifies the location where the specified control token opAndOr and expression token pTokenInfo are inserted within the set of expressions contained in the specified filter or inventory rules folder. The new tokens are added after the token specified by iIndex. If any tokens follow the token specified by iIndex, the indexes for those tokens are incremented to account for the addition of the new tokens. There are also special index values that place the new tokens at the beginning or end of the set tokens within a filter or inventory rules folder.
AT_START
Specifies that the expression token will be inserted at the beginning of the filter or inventory rules folder, and the control token will be added after the expression token.
AT_END
Specifies that the control token will be inserted at the end of the filter or inventory rules folder, and the expression token will be added after the control token.

The index is an integer that represents a token's position within a filter or inventory rules folder. The index for the first token is always zero. If the filter or inventory rules folder is empty (that is, it contains no tokens), the expression token is added as the first token and no control token is added. If the index does not exist within the filter or inventory rules folder (that is, if the index is greater than the current number of tokens in the filter or inventory rules filter), the new tokens are added at the end of the filter or inventory rules filter.

Note Because the indexes of tokens following added tokens are modified to account for the new tokens, your application should not rely on the index to identify a token. Your application should use the SmsGetToken to verify the contents of the token. In addition, when your application is building a filter or inventory rules folder, it is recommended that your application use the AT_START or AT_END index values to add tokens to the filter or inventory rules folder sequentially.

When tokens are added or removed from a filter or inventory rules folder, the indexes of the tokens that follow the added or removed tokens are adjusted. For example, if a filter has five tokens (indexes 0, 1, 2, 3,and 4) and SmsAddToken is used to add a token at index 2, the new control token would be index 3 and the new expression would be index 4. The tokens that were previously at index 3 and 4 now have index 5 and 6.

Return Values

The SmsAddToken function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not a valid filter handle or inventory rules folder handle.
SMS_PARAMETER_ERROR
One or more of the parameters in the TOKEN structure is invalid, or the pointer to the TOKEN structure is NULL.

If your application attempted to add a token to an inventory rules folder and the szTokenString member of the TOKEN structure also uses the retrieve keyword, the szTokenString member may contain a file name that specifies an incorrect location for the file. SmsAddToken will not add the token to the inventory rules folder and will return a status of SMS_PARAMETER_ERROR.

If your application passes OP_AND for the opAndOr parameter for an attribute filter, group filter, site filter, or architecture filter, a status of SMS_PARAMETER_ERROR is returned.

Remarks

For filters of type GROUP_FILTER, the SMS API engine does not validate the existence of the group specified by a group token. Your application is responsible for creating a token for a valid group class.

Example

// Add a token to the end of an architecture filter.
TOKEN Token;
memset( &Token, 0, sizeof (TOKEN) ); // Clear the Token structure.

//**************************************************************
//******* Set the expression token to "Architecture is equal to
//******* Personal Computer".
// Set the name of the value to be evaluated.
strcpy( Token.szName, "Architecture");

// Set the operator used to evaluate the expression.
Token.dwOp = QOP_STR_EQ; // Use the equals operator.

// Set the value to evaulate.
strcpy( Token.szValue, "Personal Computer");

// Add the token to the filter.
stat = SmsAddToken( hFilter, // Specifies the handle to filter.
                    OP_AND,  // Use the AND control token to connect
                             // the expression.
                    &Token,  // Specifies the structure containing
                             // the expression token.
                    AT_END   // Add the token to the end of
                             // the filter.
                  );


SmsCloseFilter

The SmsCloseFilter function closes the specified filter.

SMS_STATUS SmsCloseFilter(
  HANDLE hFilter  // Handle to filter.
);

Parameters

hFilter
Specifies the handle to the filter to close.

Return Values

The SmsCloseFilter function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The specified handle is not valid.

Remarks

When SmsCloseFilter is used to close a transient filter, the memory associated with the filter is deallocated. Note that a transient filter is opened when you use SmsCreateFilter to create a filter.

When SmsCloseFilter is used to close a persistent filter, the usage count is decremented, but the memory associated with the filter is not deallocated until its usage count is zero. When your application calls SmsGetFilterByID or SmsGetNextFilter to retrieve a handle to a filter, that filter's usage count increases by 1. The memory allocated to that filter will not be freed until your application closes all handles to the filter and closes the filter container.

After a filter has been applied to a container using SmsSetFilter, your application can close it. The SMS API creates its own copy for the container, which is freed when it is no longer needed.

See Also

SmsCloseFilterContainer, SmsCreateFilter, SmsGetFilterByID, SmsGetNextFilter, SmsSetFilter


SmsCreateFilter

The SmsCreateFilter function creates a filter of a specified type.

SMS_STATUS SmsCreateFilter(
  DWORD frType,        // Type of filter.
  HANDLE hConnection,  // Handle to database connection.
  HANDLE *phFilter     // Pointer to handle to receive the filter
                       // handle.
);

Parameters

frType
Specifies the type of filter to create. See Filter Types for a list of all supported filter types.
hConnection
Specifies the handle to the database connection. To connect to a site database, use the SmsDataSourceConnect function.
phFilter
Receives the handle to the new filter.

Return Values

The SmsCreateFilter function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The specified connection handle is not a valid handle.

Remarks

After your application uses the SmsCreateFilter function to create a filter, the filter is empty, that is, it has no tokens set. Your application should use the filter functions to set the tokens for the new filter. To use the filter, your application must use the SmsSetFilter function to apply the filter to a container that supports the filter type. After applying the filter to a container, your application must use the SmsPopulate function to query the site database for folders that meet the criteria set by the filters applied to the container.

See Also

SmsAddToken, SmsDataSourceConnect, SmsGetToken, SmsGetTokenCount, SmsManipulateTokens, SmsSetFilter


SmsGetAllFilters

The SmsGetAllFilters function retrieves a list of handles to all the filters that have been applied to a specified container.

SMS_STATUS SmsGetAllFilters(
  HANDLE hContainer, // Handle to the container.
  HANDLE *pahFilters,
                     // Pointer to an array of HANDLE values.
  DWORD *pctFilters  // Number of filters applied to the container.
);

Parameters

hContainer
Specifies the handle to the container whose applied filters you want to retrieve.
pahFilters
Points to an array of HANDLE values. This array will receive the handles to the filters that have been applied to the container. Your application must ensure that the array specified by pahFilters is large enough to contain the number of filters applied to the container specified by hContainer. See the following remarks.
pctFilters
Specifies the number of filters applied to the container.

Return Values

The SmsGetAllFilters function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not a valid filter handle.
SMS_MORE_DATA
This status code can be caused by one of the following conditions:
  • The filter count pointer is NULL.
  • The filter handle array pointer is NULL.
  • The actual number of filters exceeds the specified number of entries in the filter handle array.

Remarks

The application must ensure that the array specified by pahFilters is large enough to contain the number of filters applied to the container specified by hContainer.

To get the correct size for the pahFilters array, call the SmsGetAllFilters function with pahFilters set to NULL or with pctFilters set to zero. SmsGetAllFilters will assign the count of applied filters to pctFilters and return a status of SMS_MORE_DATA. After getting the correct value for pctFilters, call the SmsGetAllFilters function again using the correct value for pctFilters, and a pahFilters array with a size that matches the count specified by pctFilters.

If the value for pctFilters is less than the number of applied filters, the function writes the number of filter handles specified by pctFilters to the pahFilters array and returns a status of SMS_MORE_DATA.

If the value for pctFilters is greater than or equal to the number of applied filters, the function writes all filter handles for the specified container to the pahFilters array and returns a status of SMS_OK.

Important After SmsGetAllFilters is called for a container, the instance count for each filter applied to the container is incremented by 1. To decrement the count to the previous count value for each filter, your application must explicitly call SmsCloseFilter for each filter applied to the container.

See Also

SmsCloseFilter


SmsGetFilterType

The SmsGetFilterType function retrieves the filter type and filter tag for the specified filter.

SMS_STATUS SmsGetFilterType(
  HANDLE hFilter,      // Handle to filter.
  DWORD *pfilterType,  // Pointer to DWORD that will receive the
                       // filter type.
  char *pszTag         // Pointer to string that will receive the
                       // filter tag.
);

Parameters

hFilter
Specifies the handle to the filter whose type you want to retrieve.
pfilterType
Points to a DWORD that receives the filter type.
pszTag
Points to a string buffer that receives the tag for the filter type.

Return Values

The SmsGetFilterType function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not a valid filter handle.
SMS_PARAMETER_ERROR
The pfilterType parameter is NULL.
SMS_MORE_DATA
The pszTag parameter is NULL.


SmsGetToken

The SmsGetToken function retrieves a token at the specified index from the specified filter or inventory rules folder.

SMS_STATUS SmsGetToken(
  HANDLE hFilter,    // Handle to filter or inventory rules folder.
  INT iIndex,        // Index of token to retrieve.
  TOKEN *pTokenInfo  // Pointer to TOKEN structure to receive the
                     // token information.
);

Parameters

hFilter
Specifies the handle to the filter or inventory rules folder from which you want to retrieve a token.
iIndex
Specifies the index of the token to retrieve.
pTokenInfo
Specifies a TOKEN structure that will receive the information about the specified token.

Return Values

The SmsGetToken function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not a valid filter handle or inventory rules folder handle.
SMS_RANGE_ERROR
The specified token index is outside of the range of tokens in the filter or inventory rules folder.

See Also

SmsGetTokenCount


SmsGetTokenCount

The SmsGetTokenCount function retrieves the number of tokens currently set in the specified filter or inventory rules folder.

SMS_STATUS SmsGetTokenCount(
  HANDLE hFilter,  // Handle to filter or inventory rules folder.
  DWORD *pctTokens // Pointer to DWORD that will receive the token
                   // count.
);

Parameters

hFilter
Specifies the handle to the filter or inventory rules folder whose token count you want to retrieve.
pctTokens
Points to a DWORD that receives the count of the number of tokens within the specified filter or inventory rules folder.

Return Values

The SmsGetTokenCount function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The specified handle is not a valid filter handle or inventory rules folder handle.


SmsManipulateTokens

The SmsManipulateTokens function deletes, excludes, groups, or ungroups tokens within a filter or an inventory rules folder.

SMS_STATUS SmsManipulateTokens(
  HANDLE hFilter, // Handle to filter or inventory rules folder.
  DWORD dwFlags,  // Flag that specifies the operation to perform on
                  // a range of tokens.
  INT iStart,     // Index of the token at the beginning of the
                  // range.
  INT iEnd        // Index of the token at the end of the range.
);

Parameters

hFilter
Specifies the handle to the filter or inventory rules folder where you want to perform the token operation.
dwFlags
Specifies the operation to perform on the specified range of tokens. Four operations are supported:
TOK_GROUP
Groups the specified range of tokens into a subclause grouped together with parentheses.
TOK_UNGROUP
Ungroups the the specified range of tokens. Note that iStart and iEnd must specify a range of tokens that is an existing group.
TOK_DELETE
Deletes the specified range of tokens.
TOK_GROUP_NOT
Groups the specified range of tokens into a subclause and selects the group of objects that do not satisfy the conditions in that subclause.
iStart
Specifies the index of the token at the beginning of the range of tokens. Note that the value AT_START can be used to specify the index for first token in a filter or inventory rules folder.

Note that the indexes for tokens within a filter or inventory rules folder start with zero.

iEnd
Specifies the index of the token at the end of the range of tokens. Note that the value AT_END can be used to specify the index for last token in a filter or inventory rules folder.

Return Values

The SmsManipulateTokens function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not a valid filter handle or inventory rules folder handle.
SMS_UNSUPPORTED
The TOK_GROUP_NOT flag is specified for a folder.
SMS_PARAMETER_ERROR
Value set for dwFlags is an unrecognized value.
SMS_RANGE_ERROR
The specified token indexes are outside of the range of tokens in the filter or the inventory rules folder. Or the operation specified by dwFlags cannot be performed on the specified range of tokens.

Remarks

The parameters iStart and iEnd must specify a range of tokens that is valid for the operation specified by dwFlags:

TOK_DELETE
To delete a range of tokens, iStart and iEnd must specify a range of tokens that constitutes a clause. A clause is the combination of an expression token (or subclause) and its adjacent logical operator. However, if the filter or inventory rules folder contains only one expression token, your application can delete the single token by specifying a range containing only that token (iStart equal to zero and iEnd equal to zero). To delete all tokens in a filter or inventory rules folder, your application can also use the range iStart equal to AT_START and iEnd equal to AT_END.

For example, the following tokens are in an inventory rules folder:

WINWORD.EXE
AND
WINWORD.INF
AND
WINWORD.INI

A range of iStart equal to 0 and iEnd equal to 1 leaves the following tokens:

WINWORD.INF
AND
WINWORD.INI

A range of iStart equal to AT_START and iEnd equal to AT_END deletes all the tokens.

A range of iStart equal to 3 and iEnd equal to 5 returns an SMS_RANGE_ERROR (and no tokens are removed) because if the specified range were removed, an invalid set of tokens would remain in the folder.

TOK_GROUP
To group a range of tokens, iStart and iEnd must specify a range of tokens that constitutes a subclause. A subclause is a set of expression tokens that can be logically treated as a single expression token. A subclause starts and ends with an expression token.

For example, the following tokens are in an inventory rules folder:

WINWORD.EXE
AND
WINWORD.INF
AND
WINWORD.INI

A range of iStart equal to 0 and iEnd equal to 2 groups the following tokens:

(
   WINWORD.EXE
   AND
   WINWORD.INF
)
AND
WINWORD.INI

A range of iStart equal to 1 and iEnd equal to 3 returns an SMS_RANGE_ERROR (and no tokens are grouped) because if the specified range were grouped, an invalid set of tokens would be formed in the folder.

TOK_UNGROUP
To ungroup a range of tokens, iStart and iEnd must specify a range of tokens that is an existing group. A group starts with a TOKEN_OPENPAREN token and ends with a TOKEN_CLOSEPAREN token. The range must have an iStart index that specifies a TOKEN_OPENPAREN token and an iEnd index that specifies a TOKEN_CLOSEPAREN token; otherwise, SmsManipulateTokens does not perform any action and returns SMS_RANGE_ERROR.

For example, if the following tokens are in an inventory rules folder:

WINWORD.EXE
AND
(
   WINWORD.INF
   AND
   WINWORD.INI
)

A range of iStart equal to 2 and iEnd equal to 6 results in the following set of tokens:

WINWORD.EXE
AND
WINWORD.INF
AND
WINWORD.INI

A range of iStart equal to 1 and iEnd equal to 3 returns an SMS_RANGE_ERROR (and no tokens are ungrouped) because if the specified range were ungrouped, an invalid set of tokens would be formed in the folder.

TOK_GROUP_NOT
The rules for the use of iStart and iEnd with TOK_GROUP_NOT are the same as for TOK_GROUP. TOK_GROUP_NOT groups the specified range of tokens and precedes them with NOT IN, which has the effect of inverting the selection criteria of the grouped tokens. This flag can only be used with persistent filters (currently, only filters of the type MACHINE_FILTER).

The indexes of the tokens within the filter or inventory rules folder are adjusted according to the operation performed. For example, a grouping of a range of tokens causes control tokens to be added for the opening and closing parentheses, and the indexes of the tokens following index iStart are adjusted to accommodate the addition of those control tokens. The indexes of the tokens starting at index iStart and ending at iEnd are incremented by 1. At the iStart index, the TOKEN_OPENPAREN token is added. After the iEnd token, the TOKEN_CLOSEPAREN is added. The indexes of tokens after iEnd are incremented by 2.


Filter Container Functions

Using the SMS API, your application can manage the queries in a site database. In the SMS API, queries are represented as persistent machine filters in a filter container.

Your application can manage persistent machine filters within a filter container by using the filter container functions. Your application can handle persistent machine filters and their tokens by using the filter functions.

The filter container functions enable your application to open and close filter containers, retrieve persistent filters from filter containers, retrieve the identifier for a persistent filter, and write machine filters (queries) to the site database.

SmsCloseFilterContainer

SmsCommitFilter

SmsGetFilterByID

SmsGetFilterID

SmsGetNextFilter

SmsOpenFilterContainer

Note that your application can use SmsRewind to rewind persistent filters within a filter container, and to rewind scalars within a persistent filter.


SmsCloseFilterContainer

The SmsCloseFilterContainer function closes the specified filter container.

SMS_STATUS SmsCloseFilterContainer(
  HANDLE hFContainer  // Handle to filter container.
);

Parameters

hFContainer
Specfies the handle to the filter container to close.

Return Values

The SmsCloseFilterContainer function returns a status code SMS_STATUS. The function always returns a status of SMS_OK.

Remarks

If there are no other references to the filters within the filter container, SmsCloseFilterContainer closes all filters within the filter container and frees the memory associated with them.

See Also

SmsOpenFilterContainer


SmsCommitFilter

The SmsCommitFilter function causes the specified transient filter to be written to the site database.

SMS_STATUS SmsCommitFilter(
  HANDLE hFilter,     // Handle to filter to commit.
  HANDLE hFContainer  // Handle to filter container.
);

Parameters

hFilter
Specifies the handle to the filter to be committed. The filter must be of a type that supports persistence, and all mandatory scalars for the filter must be set. Currently, only filters of the MACHINE_FILTER type support persistence.

Note that the Name and Architecture scalars for the specified filter must be set before a persistent filter can be added to the site database by using SmsCommitFilter.

In addition, your application cannot commit filters that have already been committed.

hFContainer
Specifies the handle to the filter container where the filter will be added.

Return Values

The SmsCommitFilter function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not valid.
SMS_INVALID_FILTER_ID
The filter type is not valid. Currently, only machine filters can be committed.
SMS_FILTER_NO_MODIFY
Your application attempted to commit a persistent filter. Only transient filters can be committed.

Remarks

When a filter is written to the site database, it becomes a persistent filter. In the SMS Administrator, persistent filters are represented as queries.

Note that the filter must be of a type that supports persistence. Currently, only filters of the MACHINE_FILTER type support persistence.

Only transient filters can be committed—your application cannot commit filters that have already been committed.

In addition, before a transient filter can be written to the site database by using SmsCommitFilter, your application must set the following scalars for the filter:

Name
Corresponds to the Query Name in the Query Properties of the query in the SMS Administrator. This scalar must be set when adding a persistent filter to the site database.
Architecture
Corresponds to Architecture in the Query Properties of the query in the SMS Administrator. This scalar must be set when adding a persistent filter to the site database.

See Also

SmsCreateFilter


SmsGetFilterByID

The SmsGetFilterByID function retrieves the handle to the persistent filter of the specified filter type and with the specified identifier.

SMS_STATUS SmsGetFilterByID(
  HANDLE hFContainer, // Handle to filter container.
  DWORD frType,       // Filter type.
  const char *pszID,  // Pointer to identifier string.
  HANDLE *phFilter    // Pointer to handle that receives the
                      // filter's handle.
);

Parameters

hFContainer
Specifies the handle to the filter container from which to retrieve the specified persistent filter.
frType
Specifies the filter type of the filter to retrieve. See Filter Types. A specific filter type must be specified—F_ANY is an invalid parameter for frType. Currently, MACHINE_FILTER is the only type of filter supported by filter containers. If your application specifies a filter type that is not MACHINE_FILTER, SmsGetFilterByID returns SMS_INVALID_FILTER_ID.
pszID
Specifies the identifier of the persistent filter to retrieve. The filter identifier is an eight-character identifier that the SMS system assigns to a query. Note that the first three characters are the site code for the site where the query was created. Also note that the default queries provided with SMS have a six-character identifier, which begins with the characters SMS.
phFilter
Receives the handle to the specified persistent filter.

Return Values

The SmsGetFilterByID function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_FILTER_ID
No filters of the specified filter type were found in the filter container.
SMS_NOT_FOUND
The filter with the specified identifier could not be found in the filter container.

Remarks

SmsGetFilterByID opens the specified filter in the filter container. This filter remains open until it is closed using SmsCloseFilter. The memory allocated for the filter is not deallocated until the usage count for the filter is zero, that is, when all handles to the filter are closed and the filter container itself is closed using SmsCloseFilterContainer.

Using the SmsGetNextFilter function, your application can access the filters in the filter container sequentially. After a filter container is opened, the order of the filters within that particular filter container is fixed. The sequence is determined by the order in which the persistent filters were retrieved.

See Also

SmsCloseFilter, SmsCloseFilterContainer, SmsGetNextFilter


SmsGetFilterID

The SmsGetFilterID function retrieves the identifier of the persistent filter specified by the filter handle.

SMS_STATUS SmsGetFilterID(
  HANDLE hFilter,
               // Handle to filter.
  char *pszID  // Pointer to buffer to receive identifier string.
);

Parameters

hFilter
Specifies the handle to the filter whose identifier will be retrieved.
pszID
Specifies the string buffer to receive the identifier string. The filter identifier is an eight-character identifier that the SMS system assigns to a query. Note that the first three characters are the site code for the site where the query was created. Also note that the default queries provided with SMS have a six-character identifier, which begins with the characters SMS.

Your application must ensure that the string specified by pszID is large enough to contain the filter's identifier. For persistent machine filters, the filter identifier contains up to eight characters. Note that SMS_DATA_BUFF_SIZE specifies the largest buffer required for any string stored in the SMS site database.

Return Values

The SmsGetFilterID function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_PARAMETER_ERROR
Your application attempted to get the filter identifier for a transient filter.

Remarks

SmsGetFilterID applies only to persistent filters in a filter container; transient filters have no identifier. If your application attempts to get the filter identifier for a transient filter, SmsGetFilterID will return SMS_PARAMETER_ERROR.


SmsGetNextFilter

The SmsGetNextFilter function retrieves the handle to the next persistent filter of the specified type from the specified filter container.

SMS_STATUS SmsGetNextFilter(
  HANDLE hFContainer,  // Handle to filter container.
  DWORD frType,        // Filter type.
  HANDLE *phFilter     // Pointer to handle that receives the next
                       // filter's handle.
);

Parameters

hFContainer
Specifies the handle to the filter container from which to retrieve the next persistent filter.
frType
Specifies the filter type. See Filter Types. A specific filter type must be specified—F_ANY is an invalid parameter for frType. Currently, MACHINE_FILTER is the only type of filter supported by filter containers. If your application specifies a filter type other than MACHINE_FILTER, SmsGetNextFilter returns SMS_INVALID_FILTER_ID.
phFilter
Receives the handle to the next persistent filter.

Return Values

The SmsGetNextFilter function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_FILTER_ID
No filters of the specified filter type were found in the filter container.
SMS_NO_MORE_DATA
No filter was retrieved because the end of the filter list was reached.

Remarks

After a filter container is opened, the order of the filters within that particular filter container is fixed. The sequence is determined by the order in which the persistent filters were retrieved. SmsGetNextFilter opens the next filter in the filter container.

Note that a filter opened by the SmsGetNextFilter remains open until it is closed by using SmsCloseFilter. The memory allocated for the filter is not deallocated until the usage count for the filter is zero, that is, when all handles to the filter are closed and the filter container itself is closed using SmsCloseFilterContainer.

Because SmsGetNextFilter reads filters sequentially, your application must explicitly reset the filter list to start at the beginning of the list again. When SmsGetNextFilter has reached the end of the filter list, it returns SMS_NO_MORE_DATA. To start at the beginning of the filter list again, your application can use SmsRewind. SmsRewind enables your application to iterate the filters again from the beginning of the filter list.

Using the SmsGetFilterByID function, your application can also access a particular filter by its identifier.

See Also

SmsCloseFilter, SmsCloseFilterContainer, SmsGetFilterByID, SmsRewind


SmsOpenFilterContainer

The SmsOpenFilterContainer function opens a filter container and populates the filter container with persistent filters. Currently, SMS queries (persistent machine filters) are the only type of persistent filter. SmsOpenFilterContainer returns the handle to the filter container in the phFContainer parameter.

SMS_STATUS SmsOpenFilterContainer(
  HANDLE hConnection,  // Handle to database connection.
  HANDLE *phFContainer // Receives handle to the filter container.
);

Parameters

hConnection
Specifies the handle to the database connection. A database connection is established by using SmsDataSourceConnect.
phFContainer
Points to the handle that will receive the handle to a filter container.

Return Values

The SmsOpenFilterContainer function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The attempt to open the filter container failed.

Remarks

After your application has finished using a filter container, it should free the memory used by the filter container by calling the SmsCloseFilterContainer function.

See Also

SmsDataSourceConnect, SmsCloseFilterContainer


Folder Functions

The SMS API accesses objects in the SMS site database as folders. The folder functions enable applications to create, open, modify, delete, and close folders. (Note that only some types of folders—such as package folders, job folders, and so on—support creation and deletion.) They also enable applications to obtain the information contained within the folders. Scalars and subfolders can be retrieved sequentially or by identifier. In addition, these functions allow retrieval of information about a folder, such as its identifier, name, type, number of subfolders, and the number of scalars.

SmsCloseFolder

SmsCommitFolder

SmsCreateFolder

SmsDupFolder

SmsEnumFolderTypes

SmsGetFolderByID

SmsGetFolderCount

SmsGetFolderID

SmsGetFolderType

SmsGetNextFolder

SmsLinkFolder

SmsRewind

SmsUnlinkFolder


SmsCloseFolder

The SmsCloseFolder function closes the specified folder.

SMS_STATUS SmsCloseFolder(
  HANDLE hFolder  // Handle to folder.
);

Parameters

hFolder
Specifies the handle to the folder to close.

Return Values

The SmsCloseFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.

Remarks

A folder remains open until it is closed using SmsCloseFolder. The memory allocated for the folder is deallocated when the folder is closed.

Closing a folder does not cause its subfolders to be closed automatically.


SmsCommitFolder

The SmsCommitFolder function writes any changes to a folder to the site database (that is, changes carried out by calls to SmsLinkFolder and SmsUnlinkFolder).

SMS_STATUS SmsCommitFolder(
  HANDLE hFolder  // Handle to folder to commit.
);

Parameters

hFolder
Specifies the folder to commit.

Remarks

SmsCommitFolder is the only function that modifies the SMS site database. SmsLinkFolder and SmsUnlinkFolder only modify folders within the application's memory. (Note that SmsCommitFilter also modifies the site database by adding machine filters to the database as queries.)

When your application creates a folder, it must call SmsCreateFolder to create the folder (within the application's memory), set the scalars for the new folder, call SmsLinkFolder to link the new folder to its parent (within the application's memory), and call SmsCommitFolder to write the folder to the site database.

When your application deletes a folder, it must call SmsUnlinkFolder to unlink the folder from its parent (within the application's memory) and call SmsCommitFolder to delete the folder from the site database.

Note Some types of folders require their parent folder to be committed. These folders are not written to the site database until their parent folders are committed. If a folder requires its parent to be committed, the SmsCommitFolder function returns SMS_PARENT_NEEDS_COMMIT.

Return Values

The SmsCommitFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_COMMIT_FAILED
For SmsCommitFolder, the folder could not be committed to the site database.
SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.
SMS_FOLDER_NOT_MODIFIED
Your application attempted to commit a newly-created folder whose scalars have not been set sufficiently to be added to the site database. Additional scalars may need to be set within the specified folder.
SMS_FOLDER_NO_UPDATE
The folder is of a type that has read-only access.
SMS_PARENT_NEEDS_COMMIT
Your application must also commit the parent folder of the specified folder in order to commit the specified folder to the site database.
SMS_INVALID_PARAMETER
One of the folder's scalars does not contain a valid value.
SMS_CONNECT_FAILED
The connection to the site database has been broken. The folder could not be committed to the database.
SMS_INVALID_FOLDER_ID
Your application has attempted to commit a folder with an invalid identifier.
SMS_ERROR
An unexpected error condition. Usually, this is a SQL Server error.

See Also

SmsCreateFolder, SmsLinkFolder, SmsUnlinkFolder


SmsCreateFolder

The SmsCreateFolder creates a new folder of the specified type.

SMS_STATUS SmsCreateFolder(
  HANDLE hParent,  // Handle to parent folder or container.
  DWORD fType,     // Type of folder to create.
  const char *pszFolderID,
                   // Identifier to assign to the new folder.
  HANDLE *phFolder // Pointer to handle to receive the folder handle.
);

Parameters

hParent
Specifies the container or folder in which the new folder will be created.
fType
Specifies the type of folder to create. The following folder types support creation and deletion:

F_PACKAGE
F_WCL
F_PROGITEM
F_INSTALLJOB
F_SRVINSTALLJOB
F_REMPKGJOB
F_INVENTORY

pszFolderID
Specifies the identifier to assign to the folder. SMS itself will assign the identifier. This parameter is not used. Your application can set this parameter to NULL.
phFolder
Receives a handle to the new folder.

Return Values

The SmsCreateFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified parent handle is not a valid folder handle or container handle.
SMS_NO_CREATE
The specified folder type does not support creation. The folder type is read-only.
SMS_PARENT_ALREADY_COMMITTED
Your application attempted to create a subfolder for a parent folder that has already been committed. After a folder is committed, modification is not allowed.
SMS_INVALID_FOLDER_TYPE
The specified folder type is not a valid subfolder type for the specified parent folder or container.

Remarks

Folders are created in the context of a parent, that is, folders are always created within a container or a parent folder. In addition, some folder types support creation and others do not (see the preceding list). Your application can create a new folder only if the folder's type supports creation.

After a new folder has been created, the folder is empty, that is, it has no scalars set within it. Your application must set the scalars for the new folder. Using the SmsDescribeFolder function, your application can retrieve the list of scalars for a folder. Using the SmsSetScalar function, your application can set the value for each scalar in the new folder. A new folder also does not contain any subfolders. Your application can use the SmsCreateFolder function to add subfolders to the new folder.

In addition, a new folder created by SmsCreateFolder is not linked to its parent folder (your application must use the SmsLinkFolder function to link a new folder to its parent). Linking associates the new folder to its parent within your application's memory—the folder is not written to the site database.

To add the new folder to the site database, your application must use the SmsCommitFolder function to write the folder to the database.

Note that when your application creates a folder, it has created an instance of a new folder. To deallocate the memory for the new folder, your application must use SmsCloseFolder to close the folder.

See Also

SmsCloseFolder, SmsCommitFolder, SmsDescribeFolder, SmsLinkFolder, SmsSetScalar


SmsDupFolder

The SmsDupFolder function copies a folder from one location to another in the container/folder hierarchy. The new location of the folder must be a folder or container in which folder duplication is valid.

SMS_STATUS SmsDupFolder(
  HANDLE hParent,      // Handle to parent folder in which the new
                       // folder will be inserted.
  HANDLE hFolder,      // Handle to the folder being duplicated.
  HANDLE *phNewFolder  // Pointer to new folder handle returned upon
                       // successful completion.
);

Parameters

hParent

Specifies the handle to the parent folder in which the new folder will be inserted.

hFolder
Specifies the handle to the folder being duplicated.
*phNewFolder

Upon successful completion, receives a pointer to the new folder handle.

Return Values

The SmsDupFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_NO_CREATE
The specified parent handle is not valid for this type of folder.
SMS_FOLDER_ALREADY_DELETED
The folder being duplicated has been deleted.

Remarks

SmsDupFolder is currently only valid for machine folders and can be used to populate machine group folders with existing machine folders.

A new folder created by SmsDupFolder is not linked to its parent folder. Your application must use the SmsLinkFolder function to link the new folder to its parent.

Linking associates the new folder to its parent within your application's memory—the folder is not written to the site database. Your application must use the SmsCommitFolder function to write the new folder to the database.

See Also

SmsCreateFolder, SmsDescribeFolder, SmsLinkFolder, SmsCommitFolder


SmsEnumFolderTypes

The SmsEnumFolderTypes function retrieves an array of DWORD values that indicate the types of subfolders supported by a folder or a container.

SMS_STATUS SmsEnumFolderTypes(
  HANDLE hFolder,  // Handle to a folder or container.
  DWORD *pfTypes,  // Points to an array of DWORD values to receive
                   // the folder types.
  DWORD *pctFolderTypes
                   // Points to the count of the folder types.
);

Parameters

hFolder
Specifies the handle to the folder or container to query.
pfTypes
Points to an array of DWORD values. This array will receive the folder type values for the folder types supported by the specified folder or container.

Note that your application is responsible for allocating enough memory for the pfTypes array.

pctFolderTypes
Points to a DWORD value that specifies the number of folder types that the specified folder or container contains.

Return Values

The SmsEnumFolderTypes function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified handle is not a valid folder handle or container handle.
SMS_MORE_DATA
The pfTypes parameter is NULL (returns count of folder types to pctFolderTypes), or the specified type count is less than the actual number of folder types (returns the number of items allocated for the pfTypes array). The operation completed successfully but more data is available.
SMS_PARAMETER_ERROR
The specified type count pctFolderTypes is greater than the actual number of folder types.

Remarks

The application must ensure that the array specified by pfTypes is large enough to contain the number of subfolder types for the folder specified by hFolder.

To get the correct size for the pfTypes array, call the SmsEnumFolderTypes function with pfTypes set to NULL or with pctFolderTypes set to zero. SmsEnumFolderTypes will assign the count of folder types to pctFolderTypes and return a status of SMS_MORE_DATA. After getting the correct value for pctFolderTypes, call the SmsEnumFolderTypes function again, using the correct value for pctFolderTypes and a pfTypes array with a size that matches the count specified by pctFolderTypes.

If the value for pctFolderTypes is less than the number of folders, the function writes the number of folder types specified by pctFolderTypes to the pfTypes array and returns a status of SMS_MORE_DATA.

If the value for pctFolderTypes is greater than the number of folder types, the function writes all folder types for the specified folder to the pfTypes array and returns a value of SMS_PARAMETER_ERROR.

Note the difference between the SmsEnumFolderTypes function and SmsGetFolderCount. SmsEnumFolderTypes returns a list of subfolder types that can be contained in the folder. SmsGetFolderCount returns a count of how many subfolders of a specified type actually are contained in a specific folder.

Example

This example calls the SmsEnumFolderTypes function twice to get an array that contains a list of the subfolder types supported by the folder. The first call gets the count of folder types for the folder. The second call uses the value received by pctFolderTypes to get the array.

// Call SmsEnumFolderTypes to get the count of folder types.

DWORD ctFolderTypes;
stat = SmsEnumFolderTypes(hFolder, // Handle to folder
                          NULL,    // Set array pointer to NULL to
                                   // return count to ctFolderTypes.
                          &ctFolderTypes // Receives folder type count.
                         );
// Call SmsEnumFolderTypes to retrieve the folder types in
// the pfTypes array.
DWORD *pfTypes;
pfTypes = new DWORD[ctFolderTypes];
stat = SmsEnumFolderTypes(hFolder, // Handle to folder
                          pfTypes, // Pointer to array of
                                   // return count to ctFolderTypes.
                          &ctFolderTypes // Receives folder type count.
                         );


SmsGetFolderByID

The SmsGetFolderByID function retrieves the handle to the folder with the specified identifier from the specified parent folder.

SMS_STATUS SmsGetFolderByID(
  HANDLE hFolder,     // Handle to parent folder.
  DWORD fType,        // Type of folder.
  char *pszFolderID,  // Pointer to folder identifier.
  HANDLE *phSubFolder // Pointer to handle that will receive the
                      // folder handle.
);

Parameters

hFolder
Specifies the handle to the parent folder from which to retrieve a folder with the specified identifier.
fType
Specifies the type of the folder whose handle you want to retrieve. See Folder Types. Note that your application must specify a specific folder type. F_ANY cannot be specified for this parameter.
pszFolderID
Specifies the folder's identifier. See the following remarks for descriptions of the identifiers for each type of folder.
phSubFolder
Receives the handle to the folder identified by pszFolderID.

Return Values

The SmsGetFolderByID function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified parent handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.
SMS_INVALID_FOLDER_TYPE
The folder type specified is not one of the subfolder types that may be contained in the specified folder.
SMS_NOT_FOUND
The folder with the specified identifier was not found.

Remarks

Note that your application can use only SmsGetNextFolder to retrieve top-level folders in a container. Top-level folders in a container can only be retrieved by sequence. The sequence of folders within a container is determined by the order in which the SMS API engine retrieved the folders from the site database. SmsGetFolderByID cannot be used to retrieve a top-level folder in a container.

The SmsGetFolderByID function retrieves the handle to the folder with the specified identifier. The nature of the identifier depends on the type of folder:

F_DOMAIN
Domain name. For example, TIMDOMAIN.
F_GROUP
Group class name. The identifier has the form organization|class name|version.
F_INVENTORY
An inventory rules folder always uses "Inventory rules" as the identifier.
F_MACHINE
For objects with the Personal Computer architecture, the identifier has the form site|domain|name. For objects with other architectures, the identifier is the string form of an integer.
F_PROGITEM
Program item identifier. For example, AUS00001.
F_SITE
Site code. For example, AUS.
F_WCL
Command name.


SmsGetFolderCount

The SmsGetFolderCount retrieves the number of folders of the specified type contained within the specified folder or container.

SMS_STATUS SmsGetFolderCount(
  HANDLE hFolder,    // Handle to a folder or container.
  DWORD fType,       // Type of folder.
  DWORD *pctFolders  // Pointer to DWORD value that will receive the
                     // count.
);

Parameters

hFolder
Specifies the handle to the folder or container whose first-level folders (that is, folders directly beneath the specified folder or container) you want to count.
fType
Specifies the type of folder you want to count. See Folder Types. To count the total of all types of first-level folders, specify F_ANY.
pctFolders
Receives the count of the folders specified by fType.

Return Values

The SmsGetFolderCount function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle or container handle.
SMS_NO_MORE_DATA
The specified hFolder is a folder type that cannot contain subfolders and the value specifed for fType is F_ANY.
SMS_INVALID_FOLDER_TYPE
The folder type specified is not one of the subfolder types that may be contained in the specified folder or container.
SMS_MORE_DATA
If SmsPopulate is used in asynchronous mode, the function is still retrieving folders from the site database, that is, not all folders have been retrieved yet.
SMS_NOT_READY
If SmsPopulate is used in asynchronous mode, the function has not yet retrieved any folders from the site database.

Remarks

SmsGetFolderCount retrieves the number of folders directly within the specified folder or container—this function does not do a recursive count of all folders, that is, the subfolders of the folders are not counted. For example, your application can use SmsGetFolderCount on a site container to retrieve the number of site folders at the top level of the container; however, SmsGetFolderCount does not count any site folders or domain folders within the top-level site folders.


SmsGetFolderID

The SmsGetFolderID function retrieves the identifier of the folder specified by the folder handle.

SMS_STATUS SmsGetFolderID(
  HANDLE hFolder,    // Handle to folder.
  char *pszFolderID  // Pointer to buffer to receive the folder
                     // identifier.
);

Parameters

hFolder
Specifies the handle to the folder whose identifier you want to retrieve.
pszFolderID
Points to the buffer that will receive the folder's identifier. Your application is responsible for ensuring that this buffer is large enough. If you are unsure of the correct buffer size, use SMS_DATA_BUFF_SIZE, which is the largest string size that SMS can currently store.

Return Values

The SmsGetFolderID function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.
SMS_NEW_FOLDER
The specified folder has only been created using the SmsCreateFolder function. No identifier value has been assigned to the folder yet. A folder is assigned an identifier after it is committed to the site database, using SmsCommitFolder.

Remarks

For the folder specified by the hFolder parameter, the SmsGetFolderID function returns the identifier for the folder in the character string specified by the pszFolderID parameter. The nature of the identifier depends on the type of folder:

F_DOMAIN
Domain name. For example, TIMDOMAIN.
F_GROUP
Group class name. The identifier has the form organization|class name|version.
F_INSTALLJOB
Job identifier. For example, AUS00001.
F_INVENTORY
An inventory rules folder always uses "Inventory rules" as the identifier.
F_MACHINE
For objects with the Personal Computer architecture, the identifier has the form site|domain|name. For objects with other architectures, the identifier is the string form of an integer.
F_MACHINEGROUP
Machine group name. For example, Leased Servers.
F_PACKAGE
Package identifier. For example, AUS00001.
F_PROGITEM
Program item identifier. For example, AUS00001.
F_REMPKGJOB
Job identifier. For example, AUS00001.
F_SITE
Site code. For example, AUS.
F_SITEGROUP
Site group name. For example, Europe Sites.
F_SRVINSTALLJOB
Job identifier. For example, AUS00001.
F_SYSTEMJOB
Job identifier. For example, AUS00001.
F_WCL
Command name.

Note that the identifiers for most new folders are available after they have been committed to the site database with SmsCommitFolder. If a new folder has been created using SmsCreateFolder or linked using SmsLinkFolder but has not been committed, SmsGetFolderID returns a status of SMS_NEW_FOLDER.

However, new workstation command line folders (F_WCL) and program item folders (F_PROGITEM) require some extra steps before their identifiers are available. For a new workstation command line folder, the identifier is available after the Name scalar is set for the folder (the Name scalar is used as the identifier) and after the folder has been linked and committed. For a new program item folder, the identifier is available after the folder itself and its parent folder have been linked and committed.


SmsGetFolderType

The SmsGetFolderType function retrieves a folder's type as both a DWORD value and as a character string.

SMS_STATUS SmsGetFolderType(
  HANDLE hFolder, // Handle to folder.
  DWORD *pfType,  // Pointer to a DWORD value to receive the folder
                  // type.
  char *pszfType  // Pointer to string buffer to receive the folder
                  // type.
);

Parameters

hFolder
Specifies the handle to the folder whose folder type you want to retrieve.
pfType
Receives the folder's type as a DWORD value. See Folder Types.
pszfType
Receives folder's type as a string. Your application is responsible for ensuring that this buffer is large enough. If you are unsure of the correct buffer size, use SMS_DATA_BUFF_SIZE, which is the largest string size that SMS can currently store.

Return Values

The SmsGetFolderType function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.


SmsGetNextFolder

The SmsGetNextFolder function retrieves the handle to the next folder in the container or to the next subfolder within a folder.

SMS_STATUS SmsGetNextFolder(
  HANDLE hParent,  // Handle to the parent container or folder
                   // containing the folder to get.
  DWORD fType,     // Type of folder.
  HANDLE *phFolder // Pointer to handle to receive the handle to the
                   // next folder.
);

Parameters

hParent
Specifies the handle to the parent container or to the parent folder containing the folder to retrieve.
fType
Specifies the type of folder to retrieve. See Folder Types.
phFolder
Receives the handle to the next folder of the type specified by fType in the parent container or folder.

Return Values

The SmsGetNextFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified container handle or folder handle is not valid.
SMS_NO_MORE_DATA
No folder was retrieved because the end of the folder list was reached.
SMS_INVALID_FOLDER_TYPE
The folder type specified was not one of the types that can be contained in the folder or container.
SMS_CONTAINER_NOT_POPULATED
The specified container is not populated.
SMS_NOT_READY
An asynchronous populate has completed and the SMS API engine has returned a "not ready" status while retrieving the next folder from the site database.
SMS_ERROR
An unexpected error occurred.

Remarks

After a container has been populated, the order of the folders within that particular container is fixed. The sequence of folders within a container or folder is determined by the order in which the SMS API engine retrieved those folders from the site database. Using the SmsGetNextFolder function, your application can access the folders in the container sequentially. SmsGetNextFolder returns the handle to the next folder in the list of folders within a container.

Before calling SmsGetNextFolder, your application must call SmsPopulate to populate the container. If the container is not populated, SmsGetNextFolder returns SMS_CONTAINER_NOT_POPULATED.

Because SmsGetNextFolder reads folders sequentially, your application must explicitly reset the folder list to start at the beginning of the list again. When SmsGetNextFolder has reached the end of the folder list, it returns SMS_NO_MORE_DATA.

To start at the beginning of the folder list again, use SmsRewind. SmsRewind enables your application to iterate the folders again from the beginning of the folder list.

Note that your application can use only SmsGetNextFolder to retrieve top-level folders in a container. Top-level folders in a container can only be retrieved by sequence. This means that SmsGetFolderByID cannot be used to retrieve a top-level folder in a container.

See Also

SmsPopulate, SmsRewind


SmsLinkFolder

The SmsLinkFolder function links the specified folder to its parent (the parent is the container or folder within which the specified folder was created).

SMS_STATUS SmsLinkFolder(
  HANDLE hFolder  // Handle to folder to be linked to its parent.
);

Parameters

hFolder
Specifies the handle to the folder to link.

Return Values

The SmsLinkFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_DUPLICATE_FOLDER
The specified folder is newly created and a folder with the same name already exists in the SMS database.
SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.
SMS_INVALID_PARAMETER
The specified folder contains one or more scalars that have not been set properly.
SMS_FOLDER_LINKED
The specified folder has already been linked to the parent.
SMS_PARENT_NOT_FOUND
The handle to the parent folder or container that was used to create the current folder has already been closed and it is not possible to insert the child into it.

Remarks

SmsLinkFolder inserts the specified folder at the beginning of the parent's folder list.

Note that linking a folder associates the folder to its parent only within the application's memory—the folder is not written to the site database. A new folder is not added to the site database until your application uses the SmsCommitFolder function to write the folder to the database.

See Also

SmsCommitFolder, SmsCreateFolder, SmsUnlinkFolder


SmsUnlinkFolder

The SmsUnlinkFolder function unlinks the specified folder from its parent (the parent is the container or folder within which the specified folder was created).

SMS_STATUS SmsUnlinkFolder(
  HANDLE hFolder  // Handle to folder to unlink from its parent.
);

Parameters

hFolder
Specifies the handle to the folder to unlink.

Return Values

The SmsUnlinkFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified folder handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.
SMS_PARENT_NOT_FOUND
The handle to the parent folder or container has already been closed and it is not possible to remove the child folder from it.

Remarks

SmsUnlinkFolder removes the specified folder from the parent's folder list within your application's memory.

An unlinked folder is not deleted from the site database until your application uses the SmsCommitFolder function to remove the folder from the database.

Important After your application deletes a folder from the site database by using the SmsCommitFolder function, the handle for the deleted folder can only be used for closing the folder with the SmsCloseFolder function.

See Also

SmsCommitFolder, SmsLinkFolder


Scalar Functions

The scalar functions enable an application to read and set the value of a scalar. Currently, scalars can be set only on folders that support creation and on machine filters that will be committed to the site database as persistent filters in a filter container.

SmsGetNextScalar

SmsGetScalarByName

SmsGetScalarCount

SmsSetScalar

Note that after scalars have been retrieved by using SmsGetNextScalar, the scalar list for a folder or persistent filter can be rewound by using SmsRewind. To get information (such as name, data type, access rights, and so on) about the scalars within a folder, use the SmsDescribeFolder function.


SmsGetNextScalar

The SmsGetNextScalar function retrieves the next scalar in the list of scalars within a folder or persistent filter and writes the scalar's information into a SCALAR structure.

SMS_STATUS SmsGetNextScalar(
  HANDLE hFolder,        // Handle to folder or persistent filter.
  SCALAR *pScalarStruct  // Pointer to SCALAR structure to receive
                         // scalar data.
);

Parameters

hFolder
Specifies the handle to the folder or persistent filter from which you want to retrieve the next scalar.

Note that scalars for persistent filters can be retrieved in sequence only by using SmsGetNextScalar. SmsGetScalarByName cannot be used to retrieve scalars from a persistent filter.

pScalarStruct
Points to a SCALAR structure that will receive the information for the scalar to be retrieved. Your application is responsible for allocating the memory for this structure.

If the scalar is of type SCALAR_STRING or SCALAR_BINARY, your application must ensure that the buffer for the string or binary is large enough for the value of the scalar. Note that the pszValue member points to a string buffer and the pValue member points to a buffer for a binary.

To get the correct size for the buffers, call the SmsGetNextScalar function with the dwLen member of the pScalarStruct structure set to NULL. SmsGetNextScalar will assign the size of the string or binary value and return a status of SMS_MORE_DATA. After your application gets the size of the value, it should create a buffer large enough for the value and assign a pointer to that buffer to the pszValue member for SCALAR_STRING or pValue for SCALAR_BINARY. Then call the SmsGetNextScalar function again using a pScalarStruct structure with the correct size for dwLen and a pointer to a sufficiently sized buffer for the pszValue (SCALAR_STRING) or pValue (SCALAR_BINARY).

Caution Some string scalars may contain embedded control characters. For example, the STRING_1 through STRING_10 attributes for folders with the SMSEvent architecture contain embedded newline and other control characters. Your application is responsible for detecting and handling these control characters.

Return Values

The SmsGetNextScalar function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified parent handle is not a valid folder handle or filter handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder or persistent filter that has already been deleted.
SMS_MORE_DATA
The dwLen member of the pScalarStruct structure was set to NULL. SmsGetNextScalar sets the dwLen member to the size of the SCALAR_STRING or SCALAR_BINARY scalar value.
SMS_NO_MORE_DATA
No scalar was returned because the end of the scalar list was reached.

Remarks

The scalars for a folder can be retrieved in sequence or by the scalar name. The sequence of scalars within a folder or persistent filter is fixed for each type of folder or persistent filter. The sequence is determined by the SMS API. To retrieve scalars in sequence, use the SmsGetNextScalar function. To retrieve scalars by scalar name, use the SmsGetScalarByName function. SmsGetScalarByName retrieves the scalar with the specified scalar name from the folder and writes the scalar's information into a SCALAR structure.

Note that scalars for persistent filters can be retrieved in sequence only (by using SmsGetNextScalar).

The SmsRewind function enables your application to start from the beginning of the scalar list again.

See Also

SmsGetScalarByName, SmsRewind


SmsGetScalarByName

The SmsGetScalarByName function retrieves the scalar with the specified scalar name from the specified folder and writes the scalar's information into a SCALAR structure.

SMS_STATUS SmsGetScalarByName(
  HANDLE hFolder,       // Handle to folder.
  const char *pszName,  // Pointer to string containing the name of
                        // the scalar.
  SCALAR *pScalarStruct // Pointer to SCALAR structure to receive
                        // scalar data.
);

Parameters

hFolder
Specifies the handle to the folder from which you want to retrieve the scalar.

Note that SmsGetScalarByName cannot be used to retrieve scalars from a persistent filter. Scalars for persistent filters can be retrieved in sequence only (by using SmsGetNextScalar).

pszName
Specifies the name of the scalar to retrieve. To get information (such as name, data type, access rights, and so on) about the scalars within a folder, use the SmsDescribeFolder function.
pScalarStruct
Points to a SCALAR structure that will receive the information for the scalar to be retrieved. Your application is responsible for allocating the memory for this structure.

If the scalar is of type SCALAR_STRING or SCALAR_BINARY, your application must ensure that the buffer for the string or binary is large enough for the value of the scalar. Note that the pszValue member points to a string buffer and the pValue member points to a buffer for a binary.

To get the correct size for the buffers, call the SmsGetScalarByName function with the dwLen member of the pScalarStruct structure set to NULL. SmsGetScalarByName will assign the size of the string or binary value and return a status of SMS_MORE_DATA. After getting the size of the value, create a buffer large enough for the value and assign a pointer to that buffer to the pszValue member for SCALAR_STRING or pValue for SCALAR_BINARY. Then call the SmsGetScalarByName function again using a pScalarStruct structure with the correct size for dwLen and a pointer to a sufficiently sized buffer for the pszValue (SCALAR_STRING) or pValue (SCALAR_BINARY).

Caution Some string scalars may contain embedded control characters. For example, the STRING_1 through STRING_10 attributes for folders with the SMSEvent architecture contain embedded newline and other control characters. Your application is responsible for detecting and handling these control characters.

Return Values

The SmsGetScalarByName function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified parent handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.
SMS_NOT_FOUND
The specified scalar was not contained in the folder.
SMS_MORE_DATA
The dwLen member of the pScalarStruct structure was set to NULL. SmsGetScalarByName sets the dwLen member to the size of a SCALAR_STRING or SCALAR_BINARY scalar.
SMS_NO_MORE_DATA
The specified folder does not contain any scalars.

Remarks

Scalars can be retrieved in sequence or by the scalar name. To retrieve scalars in sequence, use the SmsGetNextScalar function. To retrieve scalars by scalar name, use the SmsGetScalarByName function.

See Also

SmsDescribeFolder, SmsGetNextScalar


SmsGetScalarCount

The SmsGetScalarCount function returns the count of scalars in the specified folder. Note that SmsGetScalarCount cannot be used to retrieve the count of scalars from a persistent filter.

SMS_STATUS SmsGetScalarCount(
  HANDLE hFolder,    // Handle to folder.
  DWORD *pctScalars  // Pointer to DWORD value that will receive the
                     // count.
);

Parameters

hFolder
Specifies the handle to the folder whose scalars you want to count.
pctScalars
Receives the count of scalars.

Return Values

The SmsGetScalarCount function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified parent handle is not a valid folder handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder that has already been deleted.


SmsSetScalar

The SmsSetScalar function sets the value of a scalar within a new folder created by SmsCreateFolder. Or SmsSetScalar can be used to set a scalar within a persistent filter created by SmsCreateFilter.

SMS_STATUS SmsSetScalar(
  HANDLE hFolder,        // Handle to folder or filter in which to
                         // set the scalar.
  SCALAR *pScalarStruct  // Pointer to SCALAR structure containing
                         // the scalar value to set.
);

Parameters

hFolder
Specifies the handle to the folder or filter containing the scalar to set.
pScalarStruct
Points to a SCALAR structure that contains the scalar data to be set.

Return Values

The SmsSetScalar function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_HANDLE
The specified parent handle is not a valid folder handle or filter handle.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder or persistent filter that has already been deleted.
SMS_FOLDER_NO_UPDATE
The folder is of a type that has read-only access.
SMS_SCALAR_NO_UPDATE
The scalar is of a type that has read-only access.
SMS_NOT_FOUND
The specified folder does not contain the specified scalar.
SMS_PARAMETER_ERROR
A scalar of type SCALAR_TIME has an invalid time value specified.
SMS_SCALAR_WRONG_TYPE
The scType member specified in the SCALAR structure does not match the actual type of the specified scalar.

Remarks

To set the value of a scalar, both the scalar and its folder must have an access right of ACCESS_MODIFY or ACCESS_CREATE. If you do not have access to the scalar, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

In addition, the SmsSetScalar function compares the data being set by the pScalarStruct structure with the actual data type for the scalar. If your application attempts to set an integer value for a scalar with a string data type, the SmsSetScalar function does not set the scalar value and returns SMS_SCALAR_WRONG_TYPE.

To get information (such as name, data type, access rights, and so on) about the scalars within a folder, use the SmsDescribeFolder function.

Note For workstation command line folders (F_WCL), the Name scalar is also used as the identifier for the folder. When creating a new F_WCL folder, your application should ensure that this scalar is not set to a string that is already being used by another workstation command line folder within the same package folder. If the Name scalar for the folder is the same as the Name scalar for another F_WCL folder in the same package, your application will not be able to commit the new F_WCL folder.

See Also

SmsCreateFolder, SmsDescribeFolder, SmsLinkFolder, SmsCreateFilter, SmsCommitFilter


Static Information Functions

The static information functions enable an application to retrieve general information about containers, folders, filters, and objects. The SmsAPIVer function retrieves the version of the SMS API.

SmsAPIVer

SmsDescribeFolder

SmsEnumContainers

SmsEnumFilters

SmsEnumFolders

SmsEnumObjects

SmsEnumObjectTypes


SmsAPIVer

The SmsAPIVer function returns a version string that identifies the version of the SMS API that is currently in use.

SMS_STATUS SmsAPIVer(
  char **ppVersion  // Pointer to pointer to a string that contains
                    // the version.
);

Parameters

ppVersion
Specifies a pointer to a pointer that references the version string. Your application must not modify or delete this pointer; it is a static buffer inside the SMS API engine.

Return Values

The SmsAPIVer function returns a status code SMS_STATUS. The function always returns a status of SMS_OK.

Example

// Get version and print it.
char *pszVersion;
SmsAPIVer( &pszVersion );
printf("%s\n", pszVersion);


SmsDescribeFolder

The SmsDescribeFolder function retrieves information about the properties of a specific type of container or folder. SmsDescribeFolder retrieves a pointer to a pointer to a FOLDER_INFO structure that contains information about the container or folder.

SMS_STATUS SmsDescribeFolder(
  BASETYPE tObjectity,  // Type of object whose information you want
                        // to retrieve.
  DWORD dwTag,          // Tag for the container or folder type.
  FOLDER_INFO **ppFInfo // Pointer to pointer to FOLDER_INFO
                        // structure.
);

Parameters

tObjectity
Specifies the type of object whose information you want to retrieve. The object can be a container or a folder. See BASETYPE.
dwTag
Specifies the container or folder type. See Container Types or Folder Types.

Note that SmsDescribeFolder is not applicable to F_GROUP folders because the set of attributes for a group is dependent on the instance of the group itself within a specific machine folder. If F_GROUP is specified for SmsDescribeFolder, a status code of SMS_INVALID_FOLDER_ID is returned.

ppFInfo
Points to a pointer to a FOLDER_INFO structure that contains the information about the specified container or folder type.

Return Values

The SmsDescribeFolder function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_INVALID_CONTAINER_ID
The specified container type tag is an unknown container type.
SMS_INVALID_FOLDER_ID
The specified folder type tag is an unknown folder type.

If an F_GROUP folder is specified for SmsDescribeFolder, this status code is returned. The set of attributes for an F_GROUP folder is dependent on the instance of the group itself within a specific machine folder—there is no generic set of attributes for all F_GROUP folders.

Remarks

The FOLDER_INFO structure resides in the address space of the SMS API engine. This structure should not be modified or deallocated.

The FOLDER_INFO structure contains information that describes the properties of a type of container or folder. The container functions and folder functions are used to access specific containers and folders that represent objects in the SMS site database. In short, the FOLDER_INFO structure is used to get the general properties of a certain kind of container or folder, and the container and folder functions are used to access actual containers and folders.

Note that the SmsDescribeFolder function retrieves the information for only the specified folder or container type. The SmsEnumContainers function retrieves an array of all container types. The SmsEnumFolders function retrieves an array of all folder types.

Example

// Use SmsDescribeFolder to get information about
// a Run Command On Workstations job folder and its scalars.

FOLDER_INFO *pFInfo;
stat = SmsDescribeFolder( T_FOLDER, F_INSTALLJOB, &pFInfo );

See Also

FOLDER_INFO, SmsEnumContainers, SmsEnumFolders


SmsEnumContainers

The SmsEnumContainers function retrieves a pointer to an array of pointers to FOLDER_INFO structures that contain information about all the container types supported by the SMS API.

SMS_STATUS SmsEnumContainers(
  FOLDER_INFO **ppData,  // Pointer to an array of pointers to
                         // FOLDER_INFO structures.
  DWORD *pCount          // Count of all container types supported
                         // by the SMS API.
);

Parameters

ppData
Points to a pointer to an array of pointers to FOLDER_INFO structures that contain the information about the container types supported by the SMS API. Your application must ensure that the array specified by ppData is large enough to contain the number of container types supported by the SMS API. See the following remarks.
pCount
Points to the count of container types supported by the SMS API.

Return Values

The SmsEnumContainers function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_MORE_DATA
The buffer specified by ppData is not big enough and the function returns the count of container types in the DWORD specified by pCount. Or ppData or pCount were set to NULL and the count of container types was returned to pCount.

Remarks

Your application must ensure that the array specified by ppData is large enough to contain the number of container types supported by the SMS API.

To get the correct size for the ppData array, call the SmsEnumContainers function with ppData set to NULL or with pCount set to zero. SmsEnumContainers will assign the count of container types to pCount and return a status of SMS_MORE_DATA. After getting the correct value for pCount, call the SmsEnumContainers function again using the correct value for pCount and an ppData array with a size that matches the count specified by pCount.

If the value for pCount is less than the number of container types, the function assigns pointers for the number of container types specified by pCount to the ppData array and returns a status of SMS_MORE_DATA.

If the value for pCount is greater than the number of container types, the function assigns pointers for all container types to the ppData array and returns a status of SMS_OK.

The FOLDER_INFO structures reside in the address space of the SMS API engine. This structure should not be modified or deallocated.

The FOLDER_INFO structure contains information that describes the properties of a type of container or folder. The container functions and folder functions are used to access specific containers and folders that represent objects in the SMS site database. In short, the FOLDER_INFO structure is used to get the general properties of a certain kind of container or folder, and the container and folder functions are used to access actual containers and folders.

Note that the SmsEnumContainers function retrieves an array of information for all container types. The SmsDescribeFolder function retrieves the information for only the specified container type.

Example

// Get information about all container types.

DWORD ctContainers = 0;
static FOLDER_INFO **ppContainerList = NULL;

// Use SmsEnumContainers to get the number of container types.
SmsEnumContainers(NULL, &ctContainers);

// Allocate memory for the array of pointers to the
// FOLDER_INFO structures.
ppContainerList = new FOLDER_INFO *[ctContainers];

// Use SmsEnumContainers to get the information
// about the container types.
SmsEnumContainers(ppContainerList, &ctContainers);

See Also

FOLDER_INFO, SmsDescribeFolder, SmsEnumFolders


SmsEnumFilters

The SmsEnumFilters function retrieves an array of FILTER_INFO structures that contain information about each filter type supported by SMS API.

SMS_STATUS SmsEnumFilters(
  FILTER_INFO *paFI,
                 // Pointer to an array of FILTER_INFO structures.
  DWORD *pCount  // Pointer to the count of filter types supported
                 // by the SMS API.
);

Parameters

paFI
Specifies a pointer to an array of FILTER_INFO structures. This array will receive information about each filter type supported by the SMS API. Your application must ensure that the array specified by paFI is large enough to contain the number of filter types supported by the SMS API. See the following remarks.
pCount
Points to a DWORD that specifies the count of filter types supported by the SMS API.

Return Values

The SmsEnumFilters function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_MORE_DATA
The buffer specified by paFI is not big enough, and the function returns the count of container types in the DWORD specified by pCount. Or paFI or pCount were set to NULL and the count of container types was returned to the pCount.

Remarks

Your application must ensure that the array specified by paFI is large enough to contain the number of filter types supported by the SMS API.

To get the correct size for the paFI array, call the SmsEnumFilters function with paFI set to NULL or with pCount set to zero. SmsEnumFilters will assign the count of filter types to pCount and return a status of SMS_MORE_DATA. After getting the correct value for pCount, call the SmsEnumFilters function again using the correct value for pCount and a paFI array with a size that matches the count specified by pCount.

If the value for pCount is less than the number of filter types, the function writes the number of filter types specified by pCount to the paFI array and returns a status of SMS_MORE_DATA.

If the value for pCount is greater than the number of filter types, the function writes all filter types to the paFI array and returns a status of SMS_OK.

Example

// Get information about all filter types.

DWORD ctFilters = 0;
FILTER_INFO *pAvailFilterList = NULL;

// Use SmsEnumFilters to get the number of filter types.
SmsEnumFilters(0, &ctFilters);

// Allocate memory for the array of
// FILTER_INFO structures
pAvailFilterList = new FILTER_INFO[ctFilters];
SmsEnumFilters(pAvailFilterList, &ctFilters);

See Also

FILTER_INFO


SmsEnumFolders

The SmsEnumFolders function retrieves a pointer to an array of pointers to FOLDER_INFO structures that contain information about the folder types supported by the SMS API.

SMS_STATUS SmsEnumFolders(
  FOLDER_INFO **ppData,  // Pointer to an array of pointers to
                         // FOLDER_INFO structures.
  DWORD *pCount          // Count of all folder types supported by
                         // the SMS API.
);

Parameters

ppData
Points to a pointer to an array of pointers to FOLDER_INFO structures that contain the information about the folder types supported by the SMS API. Your application must ensure that the array specified by ppData is large enough to contain the number of folder types supported by the SMS API. See the following remarks.
pCount
Points to the count of folder types supported by the SMS API.

Return Values

The SmsEnumFolders function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns the following manifest constant:

SMS_MORE_DATA
The buffer specified by ppData is not big enough, and the function returns the count of folder types in the DWORD specified by pCount. Or ppData or pCount were set to NULL and the count of folder types was returned to the pCount.

Remarks

Your application must ensure that the array specified by ppData is large enough to contain the number of folder types supported by the SMS API.

To get the correct size for the ppData array, call the SmsEnumFolders function with ppData set to NULL or with pCount set to zero. SmsEnumFolders will assign the count of folder types to pCount and return a status of SMS_MORE_DATA. After getting the correct value for pCount, call the SmsEnumFolders function again using the correct value for pCount and a ppData array with a size that matches the count specified by pCount.

If the value for pCount is less than the number of folder types, the function assigns pointers for the number of folder types specified by pCount to the ppData array and returns a status of SMS_MORE_DATA.

If the value for pCount is greater than the number of folder types, the function assigns pointers for all folder types to the ppData array and returns a status of SMS_OK.

The FOLDER_INFO structures reside in the address space of the SMS API engine. This structure should not be modified or deallocated.

The FOLDER_INFO structure contains information that describes the properties of a type of container or folder. The container functions and folder functions are used to access specific containers and folders that represent objects in the SMS site database. In short, the FOLDER_INFO structure is used to get the general properties of a certain kind of container or folder, and the container and folder functions are used to access actual containers and folders.

Note that the SmsEnumFolders function retrieves an array of information for all folder types. The SmsDescribeFolder function retrieves the information for only the specified folder type.

Example

// Get information about all folder types.

DWORD ctFolders = 0;
static FOLDER_INFO **ppFolderList = NULL;

// Use SmsEnumFolders to get the number of folder types.
SmsEnumFolders(NULL, &ctFolders);

// Allocate memory for the array of pointers to the
// FOLDER_INFO structures.
ppFolderList = new FOLDER_INFO *[ctFolders];

// Use SmsEnumFolders to get the information about the folder types.
SmsEnumFolders(ppFolderList, &ctFolders);

See Also

FOLDER_INFO, SmsDescribeFolder, SmsEnumContainers


SmsEnumObjects

The SmsEnumObjects function enumerates objects.

SMS_STATUS SmsEnumObjects(
  HANDLE hConn,         // Handle to a connection that has been
                        // established via SmsDataSourceConnect.
  char *pszObjectType,  // Pointer to the object type you want to
                        // enumerate.
  SMSBUFF *pPredecessors,  // Pointer to an array of predecessor
                           // objects required for locating the
                           // requested object.
  DWORD ctPredecessors, // Size of the pPredecessors array.
  OJBDESCRIPTOR *pObjects,  // Pointer to an array containing the
                            // details of the requested object type.
  DWORD *pCtObjects     // On entry, points to the size of the
                        // pObjects array; on exit, points to the
                        // actual number of requested objects known to
                        // the system.
);

Parameters

hConn
Handle to a connection that has been established via the SmsDataSourceConnect function.
*pszObjectType
Points to the object type you want to enumerate.
*pPredecessors
For non-first-class objects, this parameter points to an array containing a list of the predecessor objects that must be given to the system in order to locate the requested object. For first-class objects, this parameter is not used and may be set to NULL.
ctPredecessors
Specifies the number of entries in the pPredecessors array.
*pObjects
Points to an array containing the details of the requested object type. Your application must ensure that the array specified by pObjects is large enough to contain the number of requested objects. See the following remarks.
*pCtObjects
On entry, this parameter points to a DWORD value that specifies the number of entries in the pObjects array. On exit, this parameter points to a DWORD value that contains the actual number of the requested objects known to the system.

Return Values

The SmsEnumObjects function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_MORE_DATA
The entry value of pCtObjects is less than the number of objects known to the system. The function returns this value in pCtObjects, but does not copy any information to the pObjects array.
SMS_PARAMETER_ERROR
The value of pszObjectType is NULL.
SMS_NOT_FOUND
Either the object type pointed to by pszObjectType or the predecessor objects pointed to by pPredecessors were not found.
SMS_ERROR
The internal object lists could not be found. This indicates a fundamental error related to the connection to the SMS database.

Remarks

The pPredecessor parameter is not used for first-class objects (that is, objects that are known directly by the API without any additional information). In this case, pPredecessor may be set to NULL.

To get the correct size for the pObjects array, call the SmsEnumObjects function with pObjects set to NULL or with pCtObjects set to zero. SmsEnumObjects will assign the count of the requested objects to pCtObjects and return a status of SMS_MORE_DATA. After getting the correct value for pCtObjects, call the SmsEnumObjects function again using the correct value for pCtObjects and a pObjects array with a size that matches the count specified by pCtObjects.

If the entry value of pCtObjects is less than the number of the requested objects known to the system, the function does not copy any information to the pObjects array and returns a status of SMS_MORE_DATA.

If the entry value of pCtObjects is greater than the number of the requested objects known to the system, the function writes all requested objects to the pObjects array and returns a status of SMS_OK.

See Also

SmsDataSourceConnect, SmsEnumObjectTypes


SmsEnumObjectTypes

The SmsEnumObjectTypes function returns a list of first-class objects that are known to the API.

SMS_STATUS SmsEnumObjectTypes(
  HANDLE hConnection, // Handle to a connection that has been
                      // established via SmsDataSourceConnect.
  SMSBUFF *pObjects,  // Pointer to an array of first-class objects
                      // known to the system.
  DWORD *pCtObjects   // On entry, points to the size of the
                      // pObjects array; on exit, points to the actual
                      // number of first-class objects known to the
                      // system.
);

Parameters

hConnection
Handle to a connection that has been established via the SmsDataSourceConnect function
*pObjects
Upon successful completion, points to an array containing the names of each first-class object known to the system. Your application must ensure that the array specified by pObjects is large enough to contain the number of first-class objects known to the system. See the following remarks.
*pCtObjects
On entry, this parameter points to a DWORD value that specifies the size of the pObjects array. On exit, this parameter points to a DWORD value that contains the actual number of first-class objects known to the system.

Return Values

The SmsEnumObjectTypes function returns a status code SMS_STATUS. If successful, the function returns a status of SMS_OK. Otherwise, it returns one of the following manifest constants:

SMS_MORE_DATA
The entry value of pCtObjects is less than the number of first-class objects known to the system. The function returns this value in pCtObjects, but does not copy any information to the pObjects array.
SMS_ERROR
The internal object list could not be found. This indicates a fundamental error related to the connection to the SMS database.

Remarks

A first-class object is one that is known directly to the API and does not require any additional information. For example, the system knows directly about architectures and platforms, but cannot know about attributes without first knowing about an architecture and a groupclass.

To get the correct size for the pObjects array, call the SmsEnumObjectTypes function with pObjects set to NULL or with pCtObjects set to zero. SmsEnumObjectTypes will assign the count of the first-class objects to pCtObjects and return a status of SMS_MORE_DATA. After getting the correct value for pCtObjects, call the SmsEnumObjectTypes function again using the correct value for pCtObjects and a pObjects array with a size that matches the count specified by pCtObjects.

If the entry value of pCtObjects is less than the number of first-class objects known to the system, the function does not copy any information to the pObjects array and returns a status of SMS_MORE_DATA.

If the entry value of pCtObjects is greater than the number of first-class objects known to the system, the function writes all first-class objects to the pObjects array and returns a status of SMS_OK.

See Also

SmsDataSourceConnect, SmsEnumObjects


Structures

The SMS API uses the following structures:

DATASOURCE

FILTER_INFO

FOLDER_INFO

NOTIFY

SCALAR

SCALAR_INFO

TOKEN


DATASOURCE Structure

DATASOURCE

DATASOURCE is a union of structures that specifies the site database to which your application needs to connect. The DATASOURCE union is used by the SmsDataSourceConnect function.

typedef union {
    GENERIC type;
    SQL_CONNECT_PARAMS sqlParams;
    DIR_PARAMS dirParams;
} DATASOURCE;

Before calling SmsDataSourceConnect, your application must set the appropriate values for the members in the DATASOURCE structure. For Microsoft SQL Server, your application must set the server name, login identifier, password, database, public encryption key, and a pointer to a decryption function for the sqlParams structure within the DATASOURCE union.

Currently, SMS supports one database type: Microsoft SQL Server. However, the SMS API is designed to allow support of other types of databases in the future.

Members

GENERIC
A structure used only by the SMS API for extracting the type of datasource, so that the particular datasource used does not need to be explicitly implied.
typedef struct _GENERIC {
    DATASOURCE_TYPE ds;
} GENERIC;

The DATASOURCE_TYPE enumerated type currently supports only DB_SQL (DB_OTHER and DIRECTORY are not implemented):

typedef enum { DB_SQL, DB_OTHER, DIRECTORY } DATASOURCE_TYPE;
SQL_CONNECT_PARAMS
A structure used to store the information used to connect to an SMS database on a Microsoft SQL Server.
typedef struct _SQL_CONNECT_PARAMS {
    DATASOURCE_TYPE ds;
    char *pszServer;
    char *pszUserName;
    char *pszPasswd;
    char *pszDbName;
    char *pszKey;
    PDECRYPTFUNC pFunc;
} SQL_CONNECT_PARAMS;
ds
Points to a string that specifies the datasource type of the SMS database.
pszServer
Points to a string that specifies the name of the SQL Server containing the SMS database.
pszUserName
Points to a string that specifies the login identifier used to connect to the SQL Server.
pszPasswd
Points to a string that specifies the password for the login identifier.
pszDbName
Points to a string that specifies the database name of the SMS site database.
pszKey
Points to a string that specifies the decryption key if the login identifier and password are encrypted.
pFunc
Points to a decryption function. PDECRYPTFUNC is a prototype for a decryption function.

When the SmsDataSourceConnect function is called, the login identifier and password can be passed in encrypted form. If pFunc is NULL, no encryption function is called. If the decryption function pointer is not NULL, the function will attempt to call the specified function both for the login identifier and password.

Your application must supply the decryption function that returns the decrypted data in the first parameter:

typedef void (*PDECRYPTFUNC)(char *pszBuffer, char *pszDecryptMe, char *pszKey);

Example

//Structure that specifies the site database to connect to.
DATASOURCE dsParams;

//Assign values to the structure
//The type of database
    dsParams.sqlParams.ds          = DB_SQL;
//SQL Server name
    dsParams.sqlParams.pszServer   = "Jonathan1";
//Login ID
    dsParams.sqlParams.pszUserName = "sa";
//Password for Login ID
    dsParams.sqlParams.pszPasswd   = "britain";
//Name of the site database
    dsParams.sqlParams.pszDbName   = "SMS";
//Pointer to encryption function. No function is used in this example.
    dsParams.sqlParams.pFunc       = NULL;
//Encryption key. No encryption key is used in this example.
    dsParams.sqlParams.pszKey      = "";

See Also

SmsDataSourceConnect, SmsDataSourceDisconnect


Sample Decryption and Encryption Functions

This sample contains three functions that show the usage of an example decryption function, an encryption function, and a connection function that uses the decryption and encryption functions when calling SmsDataSourceConnect.

// **************************************
// ConnectToSiteDatabase
// Function to make a datasource connection to
// a site database. This function prompts for
// SQL server, loginID, password, and database,
// and then calls SmsDataSourceConnect to get
// a connection handle.

SMS_STATUS ConnectToSiteDatabase (HANDLE *phConnect)
                              // Pointer to handle to receive
                              // connection handle.
{

SMS_STATUS stat;

char *pszKey = "ABCDEFGHIJ";
    char szBuffer[100];

//Structure that specifies the site database to connect to.
DATASOURCE dsParams;
// Create string buffers for connecting to the database.
char szServer[33];
char szDb[31]; //maximum length of SQL Server database name is 30.
char szUser[31]; //maximum length of SQL Server Login ID is 30.
char szPasswd[31];

// Get database information from user and establish connection.
printf("Connect to site database.\n");

printf("SQL Server: ");
gets( szServer );

printf("Database: ");
gets( szDb );

printf("SQL Server Login ID: ");
gets( szBuffer );
// Encrypt the login ID.
Encrypt( szBuffer, szUser, pszKey );
printf("Encrypted: <%s>\n", szUser);

printf("Password: ");
    gets( szBuffer );
    Encrypt( szBuffer, szPasswd, pszKey );
    printf("Encrypted: <%s>\n", szPasswd);

// Assign connection information to dsParams structure.
// The type of database.
dsParams.sqlParams.ds          = DB_SQL;
// SQL Server name.
dsParams.sqlParams.pszServer   = szServer;
// Login ID.
dsParams.sqlParams.pszUserName = szUser;
// Password for Login ID.
dsParams.sqlParams.pszPasswd   = szPasswd;
// Name of the site database.
dsParams.sqlParams.pszDbName   = szDb;
// Pointer to encryption function.
// Callback function for decryption is Decrypt.
dsParams.sqlParams.pFunc       = Decrypt;
//Encryption key. Encryption key is specified by pszKey.
dsParams.sqlParams.pszKey      = pszKey;

// Use SmsDataSourceConnect to make a connection to the site database
// and assign the connection handle to hConnect.
stat = SmsDataSourceConnect( &dsParams, phConnect );

if (stat == SMS_OK) {
    // Decrypt user name for display.
    char szPlainUser[31];
    Decrypt( szPlainUser, szUser, pszKey );
    printf("Connected to database %s on SQL Server %s as %s.\n",
            szDb, szServer, szPlainUser);
}
else {
    printf("Cannot connect to SQL Server. Error code: %d\n", stat);
}

return stat;

} /* ConnectToSiteDatabase */

// **************************************
// Encrypt
//  This function produces a 10-character encryption.
//  The key must be at least 9 characters.
//  The first byte of the encrypted string is the
//  length of the plain text plus 1.
//  After calculating and storing that, add together the
//  values of the plain text and the key. If the
//  plain text is shorter than the key, just
//  use the value of the key.
//  Note that the encrypted string doesn't contain
//  a terminating NULL byte.
//  This algorithm for illustrative purposes only.

void Encrypt( const char *pszPlain, char *pszEncrypted, const char *pszKey )
{
    // Clear encrypted buffer to zeros. Buffer is 10 bytes long.
    // ---------------------------------------------------------
    memset( pszEncrypted, 0, 10 );

    // First byte is the length of the plain text plus 1.
    // --------------------------------------------------
    *pszEncrypted++ = strlen(pszPlain) + 1;
    // Fill the remaining 9 bytes with encrypted data.
    // As long as you still have plain text, add the corresponding
    // byte values of the plain text and the key.
    // When you run out of plain text, just use the key byte value.
    // -------------------------------------------------------------
    for (int i = 0; i < 9; i++) {
        *pszEncrypted = *pszKey;
        if (*pszPlain != NULL) {
            *pszEncrypted += *pszPlain++;
        }
        pszEncrypted++;
        pszKey++;
    }
} /* Encrypt */

// **************************************
// Decrypt
//  This function is the decryption function for Encrypt.
//  It decrypts the encrypted string specified
//  by pszEncrypted using the key specified by pszKey.
//  The key must be at least 9 characters.

void Decrypt( char *pszPlain, char *pszEncrypted, char *pszKey )
{
    // Retrieve the length of the plain text.
    int len = *pszEncrypted++ - 1;

    // Only bother with the first 'len' bytes.
    for (int i = 0; i < len; i++) {
        *pszPlain++ = *pszEncrypted++ - *pszKey++;
    }
    *pszPlain = NULL;
}


FILTER_INFO

The FILTER_INFO structure contains information about a filter. This structure is used by the SmsEnumFilters function.

typedef struct _FILTER_INFO {
    char  szTag[NAME_SIZE];
    DWORD filterType;
    char szName[NAME_SIZE];
    char szValue[NAME_SIZE];
    char szOperator[NAME_SIZE];
    char szArchitecture[NAME_SIZE];
    char szGroupClass[NAME_SIZE];
    char szAttributeName[NAME_SIZE];
} FILTER_INFO;

The following members of this structure indicate whether the corresponding member in the TOKEN structure is required when adding an expression token to a filter of the type specified by the filterType member: szName, szValue, szOperator, szArchitecture, szGroupClass, szAttributeName. If the member contains a string, this indicates that the corresponding member in the TOKEN structure is required when your application adds an expression to a filter of that type. If the member is NULL, this indicates that the corresponding member in the TOKEN structure is not required for expression tokens in a filter of that type.

Members

szTag
Specifies the string form of the filter's tag. The string has the length specified by NAME_SIZE.
filterType
Specifies the type of the filter. See Filter Types.
szName
Specifies the string label for the name of the value to be evaluated by an expression.

Note that szName is used by all filter types except machine filters (MACHINE_FILTER) and attribute filters (ATTRIBUTE_FILTER). Machine and attribute filters use the szAttributeName to specify the name of the attribute to use for the expression. For these two filters, szName is NULL.

szValue
Specifies the string label for the value to be compared using the operator specified by szOperator.
szOperator
Specifies the string label for the name of the operator to be evaluated by an expression.
szArchitecture
Specifies the string label for the name of the architecture of the object to search for. This member is used only for machine filters and attribute filters.
szGroupClass
Specifies the string label for the name of the group class of the attribute specified by szAttributeName. This member is used only for machine filters and attribute filters.
szAttributeName
Specifies the string label for the name of the attribute to evaluate against the value specified by szValue. This member is used only for machine filters and attribute filters.

Note that szAttributeName is used only by machine filters (MACHINE_FILTER) and attribute filters (ATTRIBUTE_FILTER). For all other filters, szAttributeName is NULL.

Remarks

The following members indicate whether the corresponding member in the TOKEN structure is required: szName, szValue, szOperator, szArchitecture, szGroupClass, szAttributeName. The string labels provided by these members can be used as text labels for controls in your application. For example, a job filter has the following values for the FILTER_INFO structure:

Member | Value
szTag | Job filter
filterType | JOB_FILTER
fPersistent | FALSE
szName | "Type"
szValue | "Value"
szOperator | "Operator"
szArchitecture | NULL (unused)
szGroupClass | NULL (unused)
szAttributeName | NULL (unused)

The FILTER_INFO structure for a job filter indicates that the TOKEN structure for an expression token must contain values for the szName, szValue, and szOperator members.

For an example of how to use the FILTER_INFO structure, see the browser sample in the \MSSDK\SAMPLES\SYSMGMT\SMS\SMSAPI\BROWSER directory of the Microsoft® Platform SDK CD-ROM.

See Also

Filter Types


FOLDER_INFO

The FOLDER_INFO structure contains information that describes the properties of a folder or container.

typedef struct _FOLDER_INFO {
    BASETYPE tObjectity;
    char *pszTag;
    DWORD dwTag;
    DWORD ctFolders;
    DWORD *pFolderTags;
    DWORD ctFilters;
    DWORD *pFilterTags;
    DWORD ctScalars;
    SCALAR_INFO *pScalars;
    void *pNewFunc;
} FOLDER_INFO;

The FOLDER_INFO structure contains information about folders of a specific type, such as the tag, the number of types of subfolders that are supported, the list of scalars for the folder type, and so on. The FOLDER_INFO structure can also be used to store information about containers of a specific type.

The FOLDER_INFO structure is used by the SmsDescribeFolder, SmsEnumContainers, and SmsEnumFolders functions.

Members

tObjectity
Specifies the type of object: T_CONTAINER or T_FOLDER. See BASETYPE.

Because the FOLDER_INFO structure is used to describe both containers and folders, this member indicates which of these types is being described.

pszTag
Points to the string form of the object's tag. For example, a job container has a string tag of "Job Container".
dwTag
Specifies the integer form of the object's tag. For example, a job container has an integer tag of C_JOB, where C_JOB is a manifest constant defined in SMSAPI.H.
ctFolders
Specifies the number of folder types that the specified folder or container contains. Note that ctFolders specifies the types of folders that the specified folder or container is capable of containing—not the number of actual folders contained within a specific folder or container.
pFolderTags
Points to an array of DWORD values that indicate the types of subfolders supported by the folder or container.
ctFilters
Specifies the number of filter types that the specified folder or container supports.
pFilterTags
Points to an array of DWORD values that indicate the types of filters supported by the folder or container.
ctScalars
Specifies the number of scalars that the specified folder supports. This member is used only for folders.
pScalars
Points to an array of SCALAR_INFO structures that describes the scalars supported by the folder. This member is used only for folders.
pNewFunc
Specifies a function used by the SMS API to initialize a container. Reserved for use by the SMS API. Do not modify this member.

Remarks

When your application calls the SmsDescribeFolder engine API, a pointer to a pointer to a FOLDER_INFO structure is returned. This structure will have been created in the process of registering a folder (or container) with the engine. It contains global data about a folder of the specified type, rather than information about an instance of one of these folders. The information contained in this structure will be true for all folders of the specified type.

The returned pointer addresses memory inside the SMS API engine and should not be modified or deleted.

Note Machine folders currently do not register their scalars; therefore, the ctScalars member will be zero. This does not necessarily mean that these types of folders have no scalars. It simply indicates that the set of scalars is currently unknown.


NOTIFY

The NOTIFY structure contains information about retrieval notification for asynchronous population by the SmsPopulate function.

typedef struct _NOTIFY {
    DWORD dwFreq;
    HANDLE hEvent;
    HWND hwnd;
    UINT uiMsg;
} NOTIFY;

SmsPopulate uses this structure only if POP_ASYNC is specified in dwOptions. Event notification is enabled when the POP_ASYNC and POP_EVENT flags are set for dwOptions. Window notification is enabled when the POP_ASYNC and POP_WINDOW flags are set for dwOptions.

Members

dwFreq
Specifies frequency at which the SMS API engine should set an event handle or post a message to a window. Each time the SMS API engine has retrieved the number of objects specified by dwFreq, it notifies your application by setting an event or by posting a message to a window. In addition, the SMS API engine notifies your application when all objects have been retrieved. The type of notification depends on the flags set in the dwOptions parameter of SmsPopulate.

If dwFreq is set to zero, the default frequency of 500 is used.

hEvent
Specifies the handle to the event object to be set by the SMS API engine each time the number of objects specified by dwFreq is retrieved.

An event is a type of synchronization object provided by the Win32 API. It is the responsibility of your application to create a valid event object and reset the event object by using the synchronization functions of the Win32 API. Given a handle to a valid event object through the NOTIFY structure, the SMS API engine sets the event to the signaled state when the specified number of folders have been retrieved.

If the POP_EVENT flag is set for dwOptions, the SMS API engine sets the event specified by the hEvent member to the signaled state.

hwnd
Specifies the handle to the window to which the SMS API engine should post a message each time the number of objects specified by dwFreq is retrieved. The message is specified by the uiMsg member.

If the POP_WINDOW flag is set for dwOptions, the SMS API engine posts the message specified by the uiMsg member to the window specified by hwnd.

uiMsg
Specifies the message that the SMS API engine should post to a window each time the number of objects specified by dwFreq is retrieved. The window is specified by the hwnd member.

If the POP_WINDOW flag is set for dwOptions, the SMS API engine posts the message specified by uiMsg to the window specified by hwnd.

Remarks

Note that SmsPopulate performs asynchronous population and retrieval notification only for containers that contain machine folders (site container, site group container, machine container, and machine group container).

In addition, SmsPopulate initiates the retrieval process, which is carried out by the SMS API engine. For asynchronous population, SmsPopulate returns immediately while the SMS API engine retrieves folders from the site database. The SMS API engine uses the information in the NOTIFY structure passed to it by SmsPopulate to post a window message or signal an event.

Important Asynchronous retrieval can only be used on machine, machine group, site, and site group containers. Although the SmsPopulate function applies to containers, the asynchronous behavior goes into effect only when retrieving machine folders from their parent folders or containers. For machine containers, the asynchronous behavior is in effect when SmsPopulate is called, because machine folders are the top-level folder in the container.

However, the machine folders in a site container are lower-level folders that are contained within the domain folders within site folders. When your application uses asynchronous population on a site container, the asynchronous retrieval takes effect when it accesses the folder containing the machine folders—that is, the domain folder. The site folders and the domain folders are not retrieved asynchronously. This means your application should wait on an event only after machine retrieval in a domain folder or a machine container has been triggered—the event will never be set to the signaled state if no machines are retrieved and the wait function (such as WaitForSingleObject) will time out.

In addition, when using asynchronous retrieval with events or window messages for site containers and site group containers, there are some special issues that need to be addressed (such as triggering machine retrieval in domain folders). For more detailed information, see Populating Containers in Asynchronous Mode.


SCALAR

The SCALAR structure contains information about a specific scalar within a folder.

typedef struct _SCALAR {
    SCALARTYPE scType;
    char *pszName;
    char *pszValue;
    DWORD dwValue;
    time_t tValue;
    void *pValue;
    DWORD dwLen;
    BOOL bStringEquivalence;
    DWORD fAccess;
} SCALAR;

The SCALAR structure is used by the scalar functions to read or set scalars within folders (SmsSetScalar, SmsGetNextScalar, and SmsGetScalarByName).

Members

scType
Specifies a SCALARTYPE enumerated type that indicates the type of the scalar. The members used in the SCALAR structure are determined by the scalar type.
pszName
Points to a string buffer that specifies the name of the scalar. To get the list of all scalars within a folder (and the general properties of those scalars such as name, type, and access mode), use the SmsDescribeFolder function.

Your application must ensure that a buffer for the string is large enough for the name of the scalar. Your application can use the SMS_DATA_BUFF_SIZE value, which is the maximum allowable length for a string stored in a site database.

pszValue
Points to a string buffer containing the value of the scalar.

If the scalar's type is SCALAR_STRING, this member points to a string buffer to contain the string value.

If the bStringEquivalence member is set to TRUE and the scalar's type is SCALAR_INT or SCALAR_TIME, this member is the string equivalent for the value of the scalar.

Your application must ensure that a buffer for the string is large enough for the value of the scalar. To get the size of the value, call SmsGetNextScalar or SmsGetScalarByName with pszValue and dwLen set to zero. These functions will return a status of SMS_MORE_DATA and will set the dwLen member to the size of the value. Your application can also use the SMS_DATA_BUFF_SIZE value, which is the maximum allowable length for a string stored in a site database.

Caution Some string scalars may contain embedded control characters. For example, the STRING_1 through STRING_10 attributes for folders with the SMSEvent architecture contain embedded newline and other control characters. Your application is responsible for detecting and handling these control characters.

dwValue
Specifies the value of the scalar if the scalar's type is SCALAR_INT.
tValue
Specifies the value of the scalar if the scalar's type is SCALAR_TIME.
pValue
Points to a buffer that contains the binary value. Your application must ensure that the buffer for the binary is large enough for the value of the scalar. To get the size of the value, call SmsGetNextScalar or SmsGetScalarByName with dwLen set to NULL. These functions will return a status of SMS_MORE_DATA and will set the dwLen member to the size of the value.
dwLen
Specifies the size of the scalar value if the scalar type is SCALAR_STRING or SCALAR_BINARY.

When the SmsGetNextScalar or SmsGetScalarByName functions are called, this member specifies the size of the buffer receiving the scalar value.

If the SmsGetNextScalar or SmsGetScalarByName functions are called with this member set to zero, the length of the scalar value is returned in this member and the function returns a status of SMS_MORE_DATA.

bStringEquivalence
Specifies whether a string equivalent is available for a scalar with scalar type SCALAR_INT or SCALAR_TIME. TRUE specifies that a string exists. The string value is placed in the pszValue member. The bStringEquivalence member applies only to scalars with scalar type SCALAR_INT or SCALAR_TIME.
fAccess
Specifies the access right of the scalar. See Access Rights.

Note that the access right of each scalar is set by the SMS API engine—your application can read the access right of a scalar but it cannot set the access right.

To set the value of a scalar, the scalar must have access rights of ACCESS_CREATE or ACCESS_MODIFY and its folder must have access rights of ACCESS_CREATE or ACCESS_MODIFY. If the folder and scalar do not have these rights, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, the SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

Remarks

All scalars have a type, a name, a value, and an access mode.

The SCALAR structure contains separate members for the value for each scalar type. If the scalar's type is SCALAR_STRING or SCALAR_BINARY, the dwLen member specifies the size of the scalar value. For example, if your application retrieves a scalar of type SCALAR_STRING by using the SmsGetNextScalar function, the function sets the following members in the SCALAR structure that receives the scalar: scType to SCALAR_STRING, pszName to the name of the scalar, pszValue to the value of the scalar, dwLen to the length of the scalar value, and fAccess to the access mode for the scalar.

See Also

SmsSetScalar, SmsGetNextScalar, SmsGetScalarByName, SmsDescribeFolder


SCALAR_INFO

The SCALAR_INFO structure contains information that describes the properties of a scalar in a folder.

typedef struct _SCALAR_INFO {
    char szName[BUFF_SIZE];
    SCALARTYPE scType;
    DWORD fAccess;
} SCALAR_INFO;

The SCALAR structure contains information about a specific scalar within a folder (including its value and the specific properties of the value, such as the length of a string scalar). In short, the SCALAR_INFO structure is used to get the general properties of a certain kind of scalar, and the SCALAR structure is used to store the actual value of a specific scalar within a specific folder.

The SCALAR_INFO structure is used by the SmsDescribeFolder function to retrieve the set of scalars supported by the folder.

Members

szName
Specifies the name of the scalar. The string has the length specified by BUFF_SIZE.
scType
Specifies a SCALARTYPE enumerated type that indicates the type of the scalar.
fAccess
Specifies the access rights of the scalar. See Access Rights.

To set the value of a scalar, the scalar must have access rights of ACCESS_CREATE or ACCESS_MODIFY and its folder must have access rights of ACCESS_CREATE or ACCESS_MODIFY. If the folder and scalar do not have these rights, SmsSetScalar returns an SMS_SCALAR_NO_UPDATE value. If you do not have access to the folder, the SmsSetScalar returns an SMS_FOLDER_NO_UPDATE value.

See Also

SCALAR, SmsDescribeFolder


TOKEN

The TOKEN structure contains information about a token.

typedef struct _TOKEN {
    INT tokenType;
    char  szName[BUFF_SIZE];
    char  szValue[BUFF_SIZE];
    DWORD dwOp;
    char  szArchitecture[BUFF_SIZE];
    char  szGroupClass[BUFF_SIZE];
    char  szAttributeName[BUFF_SIZE];
    char  szTokenString[TOKEN_STRING_SIZE];
    BOOL  bIndent;
} TOKEN;

The TOKEN structure is used to add and read tokens in filters and inventory rules folders.

Members

tokenType
Specifies the type of the token. See token types.
szName
Specifies the name of the attribute to evaluate with the expression token.

Note that szName is used by all filter types except machine filters (MACHINE_FILTER) and attribute filters (ATTRIBUTE_FILTER). Machine and attribute filters use the szAttributeName to specify the name of the attribute to use for the expression. For these two filters, szName is NULL.

szValue
Specifies the comparison value used for the expression. The comparison value is used to evaluate the attribute specified by szName (or szAttributeName) using the operator specified by dwOp.

See Expression Token Values.

dwOp
Specifies a relational operator (such as "is equal to" or "is like") that defines how the comparison value specified by szValue should be compared with the actual value stored for the attribute specified by szAttributeName.

See Expression Token Operators.

szArchitecture
Specifies the architecture of the objects to find with the expression. This member is used only for machine filters and attribute filters.

An architecture is a standard structure used for inventorying a set of related objects. An architecture labels and groups together all objects of a specific type. For example, all personal computers use the Personal Computer architecture, and all SMS system events use the SMSEvents architecture.

szGroupClass
Specifies the class of the group that the attribute used for the expression is part of. This member is used only for machine filters and attribute filters.

A group defines the structure for inventorying an item within an object. A group is a set of attributes that describe a specific type of item. For example, SMS inventories disk drives by using the Disk group. The Disk group has attributes (such as Disk Index, Serial Number, Storage Size, and so on) used to identify and describe a disk drive. When SMS inventories a hard disk drive on a computer, the hard disk drive's inventory is stored as a set of attribute values (for example, Disk Index is C, Serial Number is 10F10470, Storage Size is 59 MB, and so on). A group also has a class name that is used by the SMS system to uniquely identify a group (for example, two groups both have the name Monitor, but have different class names—the different class names make them different groups). A class name is composed of the organization name (usually, the organization that defined the group), a name for the group, and the version number. For example, MICROSOFT|DISK|1.0 is the class name of the group used by the SMS system to inventory disks.

szAttributeName
Specifies the attribute to use in the expression. This member is used only for machine filters and attribute filters.

Note that szName is used by all filter types except machine filters (MACHINE_FILTER) and attribute filters (ATTRIBUTE_FILTER). For all other filters except machine and attribute filters, szAttributeName is NULL.

szTokenString
Specifies the string equivalent of the token. For example, a machine filter could have the following string equivalent: "Personal Computer:MICROSOFT|MOUSE|1.0 Number of Buttons is equal to 2".

For inventory rules folders, the szTokenString member specifies the attributes that identify the file. For example, "file "winword.exe" CHECKSUM 20 200 7232". For inventory rules folders, an expression token uses only the szTokenString member of the TOKEN structure. For information about the format of the expression string for szTokenString, see Inventory Rules Folder Tokens.

bIndent
Specifies whether the szTokenString string should be indented by using prepended space characters to represent groupings. TRUE specifies that the szTokenString should contain spaces to represent a grouping level. FALSE specifies that no spaces are added for indentation.

Remarks

For filters, each token represents a criterion for selecting an object or an operator that defines the relationship of the adjacent tokens.

For inventory rules folders, each token represents the criteria used to identify a file or an operator that defines the relationship of the adjacent tokens. For inventory rules folders, an expression token uses only the szTokenString member of the TOKEN structure.

There are two types of tokens:

Expression token
For filters, an expression token defines how to search for objects that have a specified relationship to a specified value for a specified attribute. An expression token is made up of an attribute, a relational operator, and a comparison value. A relational operator (such as "is equal to" or "is like") defines how the specified value should be compared with the actual value stored for the specified attribute. Depending on the type of filter that contains the token, an expression token's TOKEN structure uses the szName, szArchitecture, szGroupClass, and szAttributeName members to define the attribute. For example, job filters (and most other filters) use the szName member to specify the attribute, whereas machine filters use the szArchitecture, szGroupClass, and szAttributeName members.

For inventory rules folders, expression tokens represent the rule for collecting inventory on a package. An expression token uses only the szTokenString member of the TOKEN structure. The szTokenString member specifies the attributes that identify the file.

Control token
For both filters and inventory rules folders, a control token can be a logical operator or parentheses. A logical operator connects two expression tokens, two subclauses, or a combination of an expression and a subclause. A logical operator defines the relationship between two adjacent expressions or subclauses. Parentheses enable expressions to be grouped together.


Manifest Constants

The SMS API uses the following manifest constants:

Container types

Folder types

Access rights

Filter types

Token types

Expression token operators

Expression token values

Miscellaneous constants

SMS_STATUS

The manifest constants for SMS API are defined in the following header files: SMSAPI.H, OBJECTTY.H, QRYCODES.H, and SMSINFO.H


Container Types

Constant | Meaning
C_JOB | Job container.
C_MACHINE | Machine container.
C_MACHINEGROUP | Machine group container.
C_PACKAGE | Package container.
C_SITE | Site container.
C_SITEGROUP | Site group container.


Folder Types

Constant | Meaning
F_ANY | All folders.
F_DOMAIN | Domain folder (subfolder of site folder).
F_GROUP | Machine group folder (subfolder of machine folder).
F_INSTALLJOB | Workstation install job folder. Represents a Run Command On Workstation job.
F_INVENTORY | Inventory rules folder.
F_MACHINE | Machine folder.
F_MACHINEGROUP | Machine group folder.
F_PACKAGE | Package folder.
F_PROGITEM | Program item folder.
F_REMPKGJOB | Remove package job folder. Represents a Remove Package From Server job.
F_SITE | Site folder.
F_SITEGROUP | Site group folder.
F_SRVINSTALL | Server install job folder. Represents a Share Package On Server job.
F_SYSTEMJOB | System job folder.
F_WCL | Workstation command line folder.


Access Rights

Constant | Meaning
ACCESS_CREATE | Specifies create access to the specified folder or scalar.
ACCESS_DELETE | Specifies delete access to the specified folder or scalar.
ACCESS_MODIFY | Specifies modify access to the specified folder or scalar.
ACCESS_READ | Specifies read access to the specified folder or scalar.


Filter Types

Type | Tag | Description
ARCHITECTURE_FILTER | Architecture filter | Specifies that machine folders of the specified architectures are retrieved in a site, site group, or machine container.
ATTRIBUTE_FILTER | Attribute filter | Specifies the attributes (represented as scalars within group folders) that are retrieved for machine folders in a site, site group, or machine container.
GROUP_FILTER | Group filter | Specifies the group folders that are retrieved for machine folders in a site, site group, machine, or machine group container.
JOB_FILTER | Job filter | Specifies the job folders that are retrieved in a job container.
MACHINE_FILTER | Machine filter | Specifies the machine folders that are retrieved in a site, site group, or machine container.
PACKAGE_FILTER | Package filter | Specifies the package folders that are retrieved in a package container.
SITE_FILTER | Site filter | Specifies the site folders that are retrieved in a site container.
SITELIMIT_FILTER | SiteLimit filter | Specifies that machine folders within the specified site and/or domain are retrieved in a machine container.


Token Types

Constant | Meaning
TOKEN_AND | 0011 bit 1 always set for AND/OR.
TOKEN_CLOSEPAREN | 0101 bit 2 always set for PAREN.
TOKEN_OPENPAREN | 0100 bit 2 always set for PAREN.
TOKEN_OPERATOR | Detects either AND or OR.
TOKEN_OR | 0010 bit 1 always set for AND/OR.
TOKEN_PAREN | Detects either open or close parenthesis.
TOKEN_USER | 1000 bit 3 always set for user-token.


Expression Token Operators

An expression token contains a relational operator (such as "is equal to" or "is like") that defines how the expression's value should be compared with the specified attribute within the objects stored in the inventory. The relational operators are defined in QRYCODES.H.

The types of relational operators available depend on the data type of the attribute. The data types are numerical, string, and date/time.

Boolean Operators

Numerical Operators

Date and Time Operators

String Operators


Boolean Operators

When an expression token contains a value or attribute with a Boolean data type, the following operators can be used within those expression tokens:

Operator | Meaning
QOP_BOOL_EQ | is TRUE
QOP_BOOL_NEQ | is not TRUE


Numerical Operators

When an expression token contains a value or attribute with an integer data type, the following operators can be used within those expression tokens:

Operator | Meaning
QOP_NUMERIC_EQ | is equal to
QOP_NUMERIC_NEQ | is not equal to
QOP_NUMERIC_GT | is greater than
QOP_NUMERIC_LT | is less than
QOP_NUMERIC_GTE | is greater than or equal to
QOP_NUMERIC_LTE | is less than or equal to


Date and Time Operators

When an expression token contains a value or attribute with a date/time data type, the following operators can be used within those expression tokens. Note that there are time and date operators for date and time as a whole (date/time), and for each unit of time (date, time, year, month, day, hour, minute, second) separately:

Overall Date/Time Operators

Operator | Meaning
QOP_DATETIME_EQ | date and time is
QOP_DATETIME_NEQ | date and time is not
QOP_DATETIME_GT | date and time is after
QOP_DATETIME_LT | date and time is before
QOP_DATETIME_GTE | date and time is on or after
QOP_DATETIME_LTE | date and time is on or before

Date Operators

Operator | Meaning
QOP_DATE_EQ | date is
QOP_DATE_NEQ | date is not
QOP_DATE_GT | date is after
QOP_DATE_LT | date is before
QOP_DATE_GTE | date is on or after
QOP_DATE_LTE | date is on or before

Time Operators

Operator | Meaning
QOP_TIME_EQ | time is
QOP_TIME_NEQ | time is not
QOP_TIME_GT | time is after
QOP_TIME_LT | time is before
QOP_TIME_GTE | time is on or after
QOP_TIME_LTE | time is on or before

Year Operators

Operator | Meaning
QOP_YEAR_EQ | year is
QOP_YEAR_NEQ | year is not
QOP_YEAR_GT | year is after
QOP_YEAR_LT | year is before
QOP_YEAR_GTE | year is on or after
QOP_YEAR_LTE | year is on or before

Month Operators

Operator | Meaning
QOP_MONTH_EQ | month is
QOP_MONTH_NEQ | month is not
QOP_MONTH_GT | month is after
QOP_MONTH_LT | month is before
QOP_MONTH_GTE | month is on or after
QOP_MONTH_LTE | month is on or before

Day Operators

Operator | Meaning
QOP_DAY_EQ | day is
QOP_DAY_NEQ | day is not
QOP_DAY_GT | day is after
QOP_DAY_LT | day is before
QOP_DAY_GTE | day is on or after
QOP_DAY_LTE | day is on or before

Hour Operators

Operator | Meaning
QOP_HOUR_EQ | hour is
QOP_HOUR_NEQ | hour is not
QOP_HOUR_GT | hour is after
QOP_HOUR_LT | hour is before
QOP_HOUR_GTE | hour is on or after
QOP_HOUR_LTE | hour is on or before

Minute Operators

Operator | Meaning
QOP_MINUTE_EQ | minute is
QOP_MINUTE_NEQ | minute is not
QOP_MINUTE_GT | minute is after
QOP_MINUTE_LT | minute is before
QOP_MINUTE_GTE | minute is on or after
QOP_MINUTE_LTE | minute is on or before

Second Operators

Operator | Meaning
QOP_SECOND_EQ | second is
QOP_SECOND_NEQ | second is not
QOP_SECOND_GT | second is after
QOP_SECOND_LT | second is before
QOP_SECOND_GTE | second is on or after
QOP_SECOND_LTE | second is on or before


String Operators

When an expression token contains a value or attribute with a string data type, the following operators can be used within those expression tokens.

How the system evaluates expressions containing string attributes depends on the code page installed on the SQL Server containing the SMS site database.

To evaluate string expressions, SMS uses the character set determined by the SQL Server's code page. For more information about the SQL Server code page, see your Microsoft SQL Server documentation.

The code page can affect the operators that are available. The SMS API provides both case-sensitive and case-insensitive (uppercase) string operators. There is a case-sensitive and case-insensitive (uppercase) version of each string operator. The uppercase version enables you to make case-insensitive comparisons of string attribute values. Before SMS evaluates the clause for a stored value and the comparison value, both values are converted to uppercase using the SQL UPPER function. Otherwise, the uppercase version performs the same operation as the non-uppercase operator.

The string operators are:

QOP_STR_EQ
QOP_UPCASE_EQ
"Is" operator. Finds any object whose attribute value exactly matches the value string.
QOP_STR_NEQ
QOP_UPCASE_NEQ
"Is not" operator. Finds any object whose attribute value does not exactly match the value string.
QOP_STR_GT
QOP_UPCASE_GT
"Comes after" operator. Finds any object whose attribute value follows (is greater than) the value string. The "comes after" operator acts on the sort order of all the values for the attribute specified for the clause. For example, if you specify the following clause:
MICROSOFT|SOFTWARE|1.0:Software Name comes after Microsoft Excel 3.0

SMS would find all computers with all software packages that have package names that follow Microsoft Excel version 3.0 in the package name attribute sort order—such as Microsoft Excel version 4.0, Microsoft Excel version 4.0a, Microsoft Project version 1.0a, Microsoft Word version 2.0, WordPerfect version 3.0, and so on.

To find only Microsoft Excel packages later than version 3.0, you would combine the previous clause with another clause that finds only package names that begin with Microsoft Excel. You combine the two clauses using an AND operator:

MICROSOFT|SOFTWARE|1.0:Software Name comes after Microsoft Excel 3.0
AND
MICROSOFT|SOFTWARE|1.0:Software Name is like Microsoft Excel%
QOP_STR_LT
QOP_UPCASE_LT
"Comes before" operator. Finds any object whose attribute value precedes (is less than) the value string. The "comes before" operator acts on the sort order of all the values for the attribute specified for the clause. For example, if you specify the following clause:
MICROSOFT|SOFTWARE|1.0:Software Name comes before Microsoft Word 2.0c

SMS would find all computers with all software packages that have package names that precede Microsoft Word version 2.0c in the package name attribute sort order—such as Microsoft Word version 2.0b, Microsoft Word version 2.0a, Microsoft Word version 2.0, Microsoft Word version 1.1, Microsoft Excel version 4.0, Asymetrix Toolbook version 1.0, and so on.

To find only Microsoft Word packages earlier than version 2.0c, you would combine the previous clause with another clause that finds only package names that begin with Microsoft Word. You combine the two clauses using an AND operator:

MICROSOFT|SOFTWARE|1.0:Software Name comes after Microsoft Word 2.0c
AND
MICROSOFT|SOFTWARE|1.0:Software Name is like Microsoft Word%
QOP_STR_GTE
QOP_UPCASE_GTE
"Is same as or comes after" operator. Finds any object whose attribute value exactly matches or follows (is greater than) the value string. This operator is a combination of the "is" and "comes after" operators.
QOP_STR_LTE
QOP_UPCASE_LTE
"Is same as or comes before" operator. Finds any object whose attribute value exactly matches or precedes (is less than) the value string. This operator is a combination of the "is" and "comes before" operators.
QOP_STR_LIKE
QOP_UPCASE_LIKE
"Is like" operator. Finds any object whose attribute value matches the pattern in the value string. For all relational operators that perform LIKE comparisons, you can use wildcards to specify the string pattern that you want to compare. For a list of wildcards, see Wildcards for LIKE Operators.
QOP_STR_NOTLIKE
QOP_UPCASE_NOTLIKE
"Is not like" operator. Finds any object whose attribute value does not match the pattern in the value string. For all relational operators that perform LIKE comparisons, you can use wildcards to specify the string pattern that you want to compare. For a list of wildcards, see Wildcards for LIKE Operators.


Expression Token Values

When you create an expression token, you must specify an attribute that the filter can use to evaluate the expression. Each attribute stores data by using a specific data type. For example, the Personal Computer architecture stores the SMSLocation attribute as a string and the Disk Storage Size attribute as an integer.

Note that the value used as the comparison value in an expression token (szValue in the expression's TOKEN structure) is passed in as a string. If necessary, the SMS API converts the string to the actual data type of the attribute in the expression token when the filter is evaluated.

This section describes the rules you should follow when you specify the expression value in the szValue member of the structure for an expression token. The SMS site database supports three data types:

Numerical Values (integers)

Date and Time Values

String Values


Numerical Values

If the attribute used for an expression token uses a numerical data type, you must specify a numeral that the SMS API engine can use to evaluate the expression.

Numerical entries can be specified as decimal (specify the decimal value) or hexadecimal (start the hexadecimal number with 0x).

If you type a nonnumerical character (such as z or !), SMS will not be able to evaluate the expression and complete the query.


Date and Time Values

If the attribute used for an expression uses a date/time data type, you must specify a date that the SMS API engine can use to evaluate the expression. You must specify the value according to the units specified by the date/time operator. For example, if you used the "year is after" operator, you would specify the year by using four digits (for example, 1994). The dates and times must be entered using the date and time formats supported by Microsoft SQL Server. For more information about date and time formats for Microsoft SQL Server, see the Microsoft SQL Server documentation.


String Values

If the attribute used for an expression token uses a string data type, you must specify a string that the SMS API engine can use to evaluate the expression.

For strings, SMS uses exactly the string you specify.

For relational operators that perform LIKE comparisons (is like and is not like), you can use wildcards within the comparison value. See Wildcards for LIKE Operators.


Wildcards for LIKE Operators

If you use operators that perform LIKE comparisons (is like and is not like) within an expression token, you can use wildcards within the comparison value in that token. A wildcard acts as a substitute for a character or string of characters. The wildcards have the same behavior and syntax as the ANSI SQL LIKE comparison operator.

Wildcard | Meaning
% | Any string of zero or more characters.
_ (underscore) | Any single character.
[ ] | Any single character within the specified range (for example, [a-f]) or set (for example, [abcdef]).
[^ ] | Any single character not within the specified range (for example, [^a-f]) or set (for example, [^abcdef]).


Miscellaneous Constants

The following constants are used by the SMS API for sizing string buffers for retrieving data from the site database. SMS_REG_ROOT is a string that contains the location of the SMS key in the registry.

Value | Meaning
BUFF_SIZE | Maximum size of buffer for character string data returned by the SMS API.
SMS_DATA_BUFF_SIZE | Maximum length of character string data retrieved from the site database by the SMS API.
NAME_SIZE | Maximum size of SMS names, such as the character string buffers in the FILTER_INFO structure.
SMS_REG_ROOT | Location of the SMS key in the registry of a Windows NT computer.
TOKEN_STRING_SIZE | Maximum size of szTokenString member of the TOKEN structure. Note that a token represents the inventory rule for a specific file. A rule can contain up to four string attributes (in addition to other types of attributes). Each string attribute can be up to 1 kilobyte in length.


SMS_STATUS

All SMS API functions return a value of type SMS_STATUS. The functions can return the following values:

SMS_ALREADY_CONNECTED
Your application has an existing connection to the site database. An application can have only one connection to a site database at one time.
SMS_COMMIT_FAILED
For SmsCommitFolder, the folder could not be committed to the site database.
SMS_CONNECT_FAILED
For SmsCommitFolder, the connection to the site database has been broken. The folder could not be committed to the database.
SMS_CONTAINER_NOT_POPULATED
For SmsGetNextFolder, the specified container is not populated.

An action was attempted on a container before the container was populated. The container must be populated before this action can be processed.

SMS_CONTAINER_POPULATED
For SmsPopulate and SmsSetFilter, the specified container is already populated.

An action was attempted on a container after the container was populated. The action must be taken before the container is populated.

SMS_DUPLICATE_FILTER
For SmsSetFilter, a filter of the specified type has already been set on the container.
SMS_DUPLICATE_FOLDER
For SmsLinkFolder, the specified folder is newly created and a folder with the same name already exists in the SMS database.
SMS_EMPTY
For SmsPopulate, the container was populated but returned no folders—no objects of the type specified were found in the site database.

For SmsSetFilter, the application did not call SmsAddToken to add tokens to the filter.

SMS_ERROR
An unexpected error occurred. Usually, this is a SQL Server error.

Note that an insufficient size for the tempdb on the SQL Server containing the site database can cause this error to occur.

To size the tempdb, you should allocate 2K per machine (that is, 2K for each inventoried object, including objects of all architectures such as Personal Computer, SMSEvent, UserGroups, and so on). The log device should be at least 20 percent of the size of the data device. For example, if you have 50,000 machines in your SMS database, you should allocate at least 100 MB total for the tempdb and at least 20 MB for the tempdb log.

SMS_FILTER_NO_MODIFY
For SmsCommitFilter, the application attempted to commit a persistent filter. Only transient filters can be committed.
SMS_FOLDER_ALREADY_DELETED
An action was attempted on a folder or persistent filter that has already been deleted.
SMS_FOLDER_LINKED
For SmsLinkFolder, the specified folder has already been linked to the parent.
SMS_FOLDER_NO_UPDATE
For SmsCommitFolder and SmsSetScalar, the folder is of a type that has read-only access.

In order to set a scalar or commit a folder, the parent folder or container of the scalar or folder must also have ACCESS_MODIFY or ACCESS_CREATE permissions.

SMS_FOLDER_NOT_MODIFIED
For SmsCommitFolder, your application attempted to commit a newly-created folder whose scalars have not been set sufficiently to be added to the site database. Additional scalars may need to be set within the specified folder.
SMS_INVALID_CONNECTION_HANDLE
For SmsSetFilter, the filter's connection handle does not match the container's connection handle.
SMS_INVALID_CONTAINER_ID
An unknown container type was specified. The SMS API engine could not locate a container of the specified type.
SMS_INVALID_DATASOURCE
The attempt to connect to the site database failed because the datasource type could not be registered. Or the SMS API engine could not access the database.
SMS_INVALID_FILTER_ID
For SmsRewind and SmsGetNextFilter, no filters of the specified filter type were found in the filter container.

For SmsCommitFilter, the filter type is not valid. Currently, only machine filters can be committed.

For SmsGetFilterByID, no filters of the specified filter type were found in the filter container.

SMS_INVALID_FILTER_TYPE
For SmsSetFilter, your application has attempted to set a filter that is incompatible with the specified container.
SMS_INVALID_FOLDER_ID
For SmsCommitFolder, your application has attempted to commit a folder with an invalid identifier.

For SmsDescribeFolder, the specified folder type tag is for an unknown folder type. If an F_GROUP folder is specified, this status code is returned. The set of attributes for an F_GROUP folder is dependent on the instance of the group itself within a specific machine folder—there is no generic set of attributes for all F_GROUP folders.

SMS_INVALID_FOLDER_TYPE
The specified folder type is not a valid subfolder type for the specified parent folder or container.
SMS_INVALID_HANDLE
An invalid handle was used to access an object.

For SmsDataSourceConnect, the database connection could not be made because of a memory allocation failure.

For SmsOpenFilterContainer, the attempt to open the filter container failed.

SMS_INVALID_PARAMETER
For SmsPopulate, asynchronous population was specified for a container type that does not support asynchronous population. (Note that job containers and package containers do not support asynchronous population.) Or an invalid window handle was specified in the hwnd member of the pNotify structure.

For SmsCommitFolder, one of the folder's scalars does not contain a valid value.

For SmsLinkFolder, the specified folder contains one or more scalars that have not been set properly.

SMS_MORE_DATA
For SmsEnumFolderTypes, the type pfTypes parameter is NULL (returns count of folder types to pctFolderTypes) or the specified type count is less than the actual number of folder types (returns the number of items allocated for the pfTypes array). The operation completed successfully but more data is available.

For SmsGetFolderCount, if SmsPopulate is used in asynchronous mode, the function is still retrieving folders from the site database, that is, not all folders have been retrieved yet.

For SmsGetNextScalar and SmsGetScalarByName, the dwLen member of the pScalarStruct structure was set to NULL. If dwLen is NULL, these functions will set the dwLen member to the size of the SCALAR_STRING or SCALAR_BINARY scalar value.

For SmsGetAllFilters, this status code can be caused by one of the following conditions:

  • The filter count pointer is NULL.
  • The filter handle array pointer is NULL.
  • The actual number of filters exceeds the specified number of entries in the filter handle array.

For SmsGetFilterType, the pszTag parameter is NULL.

For SmsEnumContainers, the buffer specified by ppData is not big enough and the function returns the count of container types in the DWORD specified by pCount. Or either ppData or pCount was set to NULL and the count of container types was returned to the pCount.

For SmsEnumFilters, the buffer specified by paFI is not big enough and the function returns the count of container types in the DWORD specified by pCount. Or either paFI or pCount was set to NULL and the count of container types was returned to pCount.

For SmsEnumFolders, the buffer specified by ppData is not big enough, and the function returns the count of folder types in the DWORD specified by pCount. Or either ppData or pCount was set to NULL and the count of folder types was returned to the pCount.

For SmsEnumObjects, the entry value of pCtObjects is less than the number of objects known to the system. The function returns this value but does not copy any information to the pObjects array.

For SmsEnumObjectTypes, the entry value of pCtObjects is less than the number of first-class objects known to the system. The function returns this value but does not copy any information to the pObjects array.

SMS_NEW_FOLDER
For SmsGetFolderID, the specified folder has only been created by using the SmsCreateFolder function. No identifier value has been assigned to the folder yet. A folder is assigned an identifier after it is committed to the site database by using SmsCommitFolder.
SMS_NO_CREATE
For SmsCreateFolder, the specified folder type does not support creation. The folder type is read-only.

For SmsDupFolder, the specified parent handle is not valid for this type of folder.

SMS_NO_MORE_DATA
For SmsGetFolderCount, the folder type (fType) F_ANY is specified for a folder (hFolder) that cannot contain subfolders.

For SmsGetNextFolder, no folder was retrieved because the end of the folder list was reached.

For SmsGetNextScalar, no scalar was returned because the end of the scalar list was reached.

For SmsGetScalarByName, the specified folder does not contain any scalars.

For SmsGetNextFilter, no filter was retrieved because the end of the filter list was reached.

SMS_NOT_FOUND
For SmsGetFolderByID, the folder with the specified identifier was not found.

For SmsSetScalar and SmsGetScalarByName, the specified folder does not contain the specified scalar.

For SmsGetFilterByID, the filter with the specified identifier could not be found in the filter container.

For SmsEnumObjects, either the object type pointed to by pszObjectType or the predecessor objects pointed to by pPredecessors were not found.

SMS_NOT_READY
SmsPopulate was used to retrieve folders in asynchronous mode and an attempt was made to access folders in a container before some or all folders were retrieved from the site database.

For SmsGetFolderCount, the function has not retrieved any folders from the site database yet.

For SmsGetNextFolder, the SMS API engine has returned a "not ready" status while retrieving the next folder from the site database.

SMS_OK
The function completed its action successfully.
SMS_PARAMETER_ERROR
For SmsEnumFolderTypes, the specified type count pctFolderTypes is greater than the actual number of folder types.

For SmsSetScalar, a scalar of type SCALAR_TIME has an invalid time value specified.

For SmsGetFilterID, your application attempted to get the filter identifier for a transient filter. SmsGetFilterID applies only to persistent filters in a filter container; transient filters have no identifier.

For SmsAddToken, one or more of the parameters in the TOKEN structure is invalid, or the pointer to the TOKEN structure is NULL. If your application attempted to add a token to an inventory rules folder and the szTokenString member of the TOKEN structure also uses the retrieve keyword, the szTokenString member may contain a file name that specifies an incorrect location for the file. SmsAddToken will not add the token to the inventory rules folder and will return a status of SMS_PARAMETER_ERROR. If your application passes OP_AND for the opAndOr parameter for an attribute filter, group filter, site filter, or architecture filter, a status of SMS_PARAMETER_ERROR is also returned.

For SmsGetFilterType, the pfilterType parameter is NULL.

For SmsManipulateTokens, value set for dwFlags is an unrecognized value.

For SmsEnumObjects, the value of pszObjectType is NULL.

SMS_PARENT_ALREADY_COMMITTED
For SmsCreateFolder, your application attempted to create a subfolder for a parent folder that has already been committed. After a folder is committed, modification is not allowed. This means that the child folder cannot be added to a parent folder that has already been committed.
SMS_PARENT_NEEDS_COMMIT
For SmsCommitFolder, your application must also commit the parent folder of the specified folder in order to commit the specified folder to the site database.
SMS_PARENT_NOT_FOUND
For SmsLinkFolder, the handle to the parent folder or container that was used to create the current folder has already been closed and it is not possible to insert the child into it.

For SmsUnlinkFolder, the handle to the parent folder or container has already been closed and it is not possible to remove the child folder from it.

SMS_RANGE_ERROR
For SmsGetToken, the specified token index is outside of the range of tokens in the filter or inventory rules folder.

For SmsManipulateTokens, the specified token indexes are outside of the range of tokens in the filter or inventory rules folder. Or the operation specified by dwFlags cannot be performed on the specified range of tokens.

SMS_SCALAR_NO_UPDATE
For SmsSetScalar, the scalar is of a type that has read-only access.

In order to update a scalar, the parent folder or container must support the operation as well as the scalar to set and the folder to commit.

SMS_SCALAR_WRONG_TYPE
For SmsSetScalar, the scType field specified in the SCALAR structure does not match the actual type of the specified scalar.
SMS_SQL_ERROR
An error occurred while trying to access SQL Server.
SMS_UNSUPPORTED
For SmsManipulateTokens, the TOK_GROUP_NOT flag is specified for a folder.


Enumerated Types

The SMS API uses the following enumerated types:

ANDOR

BASETYPE

SCALARTYPE


ANDOR

The ANDOR type represents a control token that connects two expression tokens, two subclauses, or a combination of an expression and a subclause. The ANDOR type defines the relationship between two adjacent expression tokens or subclauses.

typedef enum {
    OP_AND = 0x03,
    OP_OR = 0x02
} ANDOR;

The ANDOR type is used by the SmsAddToken function.

Members

OP_AND
Finds all objects that satisfy both expressions or subclauses connected by the OP_AND token. You can use OP_AND to narrow the list of objects you want to find. For example, the following machine filter finds all computers that have an 80386 processor, 4 MB of extended memory, and Microsoft Excel:
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%386%'
AND
MICROSOFT|X86_PC_MEMORY|1.0:Extended Memory (KByte) is greater than '4000'
AND
MICROSOFT|SOFTWARE|1.0:Name is like '%Excel%'

This filter returns a list of computers that satisfied all three expressions.

OP_OR
Finds all objects that satisfy any (or both) of the two expressions or subclauses connected by the OP_OR token. You can use OP_OR to assemble a set of objects. For example, the following machine filter finds all computers that have an 80386 processor, 4 MB of extended memory, or Microsoft Excel—or any combination of the three:
MICROSOFT|PROCESSOR|1.0:Processor Name is like '%386%'
OR
MICROSOFT|X86_PC_MEMORY|1.0:Extended Memory (KByte) is greater than '4000'
OR
MICROSOFT|SOFTWARE|1.0:Software Name is like '%Excel%'

This filter returns a list of all computers that satisfied any one (or any combination) of the three expressions.

See Also

SmsAddToken


BASETYPE

The BASETYPE enumerated type contains values that specify the type of an object.

typedef enum {
    T_CONTAINER,
    T_FOLDER
} BASETYPE;

The BASETYPE enumerated type is used by the SmsDescribeFolder function and FOLDER_INFO structure. In this function and structure, the BASETYPE specifies whether information is being retrieved for a container or a folder.

Members

T_CONTAINER
Specifies the object is a container.
T_FOLDER
Specifies the object is a folder.


SCALARTYPE

The SCALARTYPE enumerated type contains values that specify the type of a scalar.

typedef enum {
    SCALAR_STRING,
    SCALAR_INT,
    SCALAR_TIME,
    SCALAR_BINARY
} SCALARTYPE;

The SCALARTYPE enumerated type is used by the SCALAR and SCALAR_INFO structures.

Members

SCALAR_STRING
Specifies that the scalar contains a string value.
SCALAR_INT
Specifies that the scalar contains an integer (DWORD) value.
SCALAR_TIME
Specifies that the scalar contains a time value (time_t).
SCALAR_BINARY
Specifies that the scalar contains binary data. Currently, the only scalar of type SCALAR_BINARY is the Icon scalar of program item folders.

See Also

SCALAR, SCALAR_INFO


Sample Applications for the SMS API

The Microsoft® Platform SDK provides sample applications that use the SMS API. Each sample is located in its own directory in the \MSSDK\SAMPLES\SYSMGMT\SMS\SMSAPI directory on the Platform SDK CD-ROM.

All samples can be built using the tools, libraries, and header files described in Installing the SMS API Components. Unless otherwise stated, each sample can be built by running NMAKE against the makefile in the appropriate directory.

Before running these sample applications, follow the steps described in Installing Your Application.

Many of these applications run in console mode, displaying output directly to the screen console. In order to better view the output data, you may want to run these applications in a Command Prompt with a large Screen Buffer size. You can set the Screen Buffer size in the Command Prompt Properties dialog box. Another option is to redirect the output to a file that can be viewed after the application has completed.

In addition to the samples listed below, the SAMPLES\SMS\SMSAPI directory contains noncompilable sample code (ISVREG.C and ISVREG.H) that registers applications for launch from the SMS Administrator console. See Sample Code to Register Applications for information on these samples.

The following sample applications are provided in this SDK:

ATTRIBUT.EXE

BROWSER.EXE

DELJOB.EXE

ENUMOBJ.EXE

MGRP.EXE

NEWJOB.EXE

NEWPKG.EXE

PDF.EXE

RESDLL.DLL

SRVINST.EXE

TESTALL.EXE

TREE.EXE


ATTRIBUT.EXE

Overview

This sample is a console mode application that displays folder properties by using the Attribute filter. This filter is applied to a site container in order to enumerate specified properties of a machine of architecture type Personal Computer. This technique is used because it is faster than setting group filters and then retrieving specified machine group scalars.

Much of the code in this sample is written to be generic, so this is a good sample to use when you need to enumerate folders of unknown type.

The later portions of this code demonstrate techniques for handling specific types of folders. In general, when dealing with a folder that may contain many subfolders, it is recommended that you open and examine each subfolder in turn. For instance, when examining a domain folder, you should follow this technique, and you should not close the folder until all machines in the domain have been displayed. On the other hand, if the folder does not contain many subfolders, it is usually more efficient to open each subfolder, store the handles in a temporary list, and then close the folder.

Running the Program

ATTRIBUT.EXE is a console application that requires you to input the SQL Server name, Database name, SQL Logon ID, and Password. It then displays folder properties for the machines, starting in the root site. When it is finished displaying the folders, the program quits.

Functions

This program illustrates usage of the following SMS functions:

SmsAPIVer
SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsPopulate
SmsGetFolderCount
SmsGetNextFolder
SmsGetFolderType
SmsGetFolderID
SmsCloseFolder
SmsGetScalarCount
SmsGetNextScalar
SmsCreateFilter
SmsSetFilter
SmsCloseFilter
SmsAddToken

Program Flow

This program opens a site container, then constructs and applies an Attribute filter, a Site filter, and an Architecture filter. The code then populates the container with the folder for the root site, opens the folder, and displays the folder's properties (the folder type, and the number of scalars and subfolders the folder contains). Because the folder display function is recursive, calling this function with the root site folder will cause all folders in the site hierarchy to be displayed.


BROWSER.EXE

Overview

This is a graphical mode application that implements a browser for SMS objects. The program allows you to configure and apply filters to the containers that you open. You can view the containers, folders, subfolders, and scalars with this program.

Running the Program

To run BROWSER.EXE
  1. Connect to the appropriate datasource by supplying the SQL Server name, Database name, SQL Logon ID, and Password.
  2. Select a container to browse.
  3. Select the filters you want to apply (if any). If you do not apply any filters, then you will see all objects in the container when you view it. Multiple filters may be selected for the container. Note that you will not be able to select any filters until you have specified the container.
  4. If you select any filters, you must configure them by clicking Configure Filter and setting tokens into the specified filter. There are currently eight filters available: Site, Machine, Group, Job, Architecture, Package, SiteLimit, and Attribute. Machine filters require a group class, an attribute name, an operator, and a value; other filters do not need the group class field. The dialog box will automatically enable the correct edit fields based on the filter type you select.
  5. View the selected container dialog box by clicking View Container at the lower part of the dialog box. This dialog box displays the container type, the number of folders contained in the container, and a list of these folders. Note that you will not be able to view the container until you have selected and configured the filters.
  6. Select and view a folder by clicking View Folder.
  7. View the folder scalars or subfolders by clicking the appropriate buttons. Click Back to return to the previous dialog box. Click Done to dismiss this dialog box and return to the main dialog box. Quit the browser by clicking Quit, or restart by clicking Connect.

Functions

This sample application illustrates possible uses of the following SMS functions:

SmsDataSourceConnect
SmsDataSourceDisconnect
SmsEnumContainers
SmsOpenContainer
SmsPopulate
SmsCloseContainer
SmsGetNextFolder
SmsCloseFolder
SmsRewind
SmsGetFolderID
SmsGetFolderType
SmsGetFolderCount
SmsEnumFolderTypes
SmsGetScalarCount
SmsGetNextScalar
SmsEnumFilters
SmsCreateFilter
SmsCloseFilter
SmsGetAllFilters
SmsGetFilterType
SmsGetToken
SmsAddToken
SmsGetTokenCount

Program Flow

This sample application uses the SmsEnumContainers and SmsEnumFilters functions to discover the containers and filters that have been registered with the datasource. The resulting strings are used to populate the list boxes for the containers and filters.The program allows the user to log on to the database and to select a container to browse. The program opens the container with SmsOpenContainer and then uses the SmsEnumFilter functions to create and configure any filters the user selects. The program then displays the contents of the container to the user. The user can also view any folder that is contained within the container hierarchy. A folder is logically composed of three entities:

  1. Details about the folder itself (see the Folder Details section of the View Folder dialog box).
  2. Subfolders (click View Subfolder in the Subfolders section of the View Folder dialog box).
  3. Scalars (click View Scalars in the Folder Details section of the View Folder dialog box).


DELJOB.EXE

Overview

DELJOB.EXE is a console mode application that can be used for deleting jobs from the SMS database. This code demonstrates datasource connection, folder deletion, scalar manipulation, and helper functions.

Running the Program

DELJOB.EXE runs as a console application. The program prompts you to enter the information needed to connect to SQL Server, then it prompts for the identifier of the job you want to delete. The application will display an error message if the job cannot be deleted. The program then quits.

Functions

SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsPopulate
SmsGetNextFolder
SmsGetFolderID
SmsUnlinkFolder
SmsCommitFolder
SmsCloseFolder

Program Flow

The application first establishes a connection to the datasource. Then, it opens a container of the type C_JOB and populates it. The user is asked for the identifier of the job to delete and then the job container is searched for a job matching the specified identifier. Finally, if the specified job folder is found, the job folder is deleted and the datasource is closed.


ENUMOBJ.EXE

Overview

ENUMOBJ.EXE is a console application that enumerates the high-level objects within an SMS site server database. This sample demonstrates the use of the enumeration functions SmsEnumObjects and SmsEnumObjectTypes.

Running the Program

ENUMOBJ.EXE runs as a console application. To run the program. type enumobj.exe. The program prompts you to enter the information needed to connect to the SQL server, displays the list of enumerated objects by category, and exits.

Functions

SmsAPIVer
SmsDataSourceConnect
SmsDataSourceDisconnect
SmsEnumObjects
SmsEnumObjectTypes

Program Flow

After logging on to a datasource, the program calls SmsEnumObjectTypes to retrieve all of the first-class object types. For each of these object types, the program calls SmsEnumObjects to obtain the details of the type.


MGRP.EXE

Overview

MGRP.EXE is a console application that creates a machine group in the SMS site server database and populates it with the machines from the local site server. This sample demonstrates the code required to create and populate a machine group.

Running the Program

MGRP.EXE runs as a console application. To run the program, type mgrp.exe. The program prompts you to enter the information needed to connect to the SQL server and then prompts you to enter a unique name for the machine group to be created. The application creates the machine group and then allows further creates or exits.

Functions

SmsAPIVer
SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsCreateFolder
SmsPopulate
SmsCloseFolder
SmsGetFolderCount
SmsGetNextFolder
SmsGetFolderID
SmsDupFolder
SmsLinkFolder
SmsCommitFolder
SmsGetFolderID
SmsGetScalarCount
SmsCloseFolder
SmsCreateFilter
SmsAddToken
SmsSetFilter
SmsCloseFilter
SmsSetScalar

Program Flow

After logging on to a datasource and obtaining the machine group name from the user, the program creates the machine group folder and copies machine folders into it using the SmsDupFolder function.


NEWJOB.EXE

Overview

This is a console mode application that illustrates how to view, create, and delete jobs. There are four types of jobs in SMS: Run Command On Workstation jobs, Share Package On Server jobs, Remove Package From Server jobs, and System jobs. Of these, all except System jobs can be created and deleted from the SMS API. All job types can be viewed.

This sample shows how the SmsDescribeFolder function is used to retrieve a template description of the folder and the scalars that it contains.

Running the Program

NEWJOB.EXE runs as a console application. The program prompts you to enter the information needed to connect to SQL Server, then it creates and populates a job container. At this point the program enters a loop and prompts you to view a job, delete a job, create a job, or quit the program. Enter:

C to create a new job

N to view the next job folder

D to delete the current job folder

X to exit the program

Functions

SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsPopulate
SmsGetFolderType
SmsGetFolderCount
SmsGetNextFolder
SmsGetFolderID
SmsCreateFolder
SmsDescribeFolder
SmsLinkFolder
SmsUnlinkFolder
SmsCommitFolder
SmsGetScalarCount
SmsGetNextScalar
SmsSetScalar
SmsRewind

Program Flow

After logging on to a datasource, a job container is created and populated. (No filters are used in this program, so you will be able to view all jobs in the system.) The program then enters a loop asking whether the user wants to view the next job folder, delete the currently viewed folder, or create a new folder. Both deletion and creation are two-stage processes. Only when the SmsCommitFolder function is called will the folder be either deleted from or inserted into the datasource.

For folder creation, the user is asked which of the three types of folders that support creation the user wants to create. The creation process then continues by soliciting scalar information from the user. For each scalar that can be set, the user is given the name of the scalar and its type. When all scalars have been set, the folder is displayed and the user is asked to confirm the creation. Successful folder creation depends on the validity of the scalar settings.


NEWPKG.EXE

Overview

NEWPKG.EXE is a console mode application that can be used for viewing, creating, or removing packages from the SMS database. This code demonstrates datasource connection, folder creation, scalar manipulation, folder display, and helper functions.

Running the Program

NEWPKG.EXE runs as a console application. The program prompts you to enter the information needed to connect to SQL Server, then it creates and populates a package container. At this point the program enters a loop and prompts you to view packages, delete packages, create packages, or terminate the program. Enter:

C to create a new package folder

N to view the next package folder

P to view the previous package folder

V to view the current package folder

D to delete the current package folder

X to exit the program

Functions

SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsPopulate
SmsCreateFolder
SmsGetNextFolder
SmsDescribeFolder
SmsGetFolderID
SmsGetFolderType
SmsGetFolderCount
SmsLinkFolder
SmsUnlinkFolder
SmsCommitFolder
SmsCloseFolder
SmsRewind
SmsGetScalarCount
SmsSetScalar
SmsGetNextScalar

Program Flow

After logging on to a datasource, a package container is created and populated. The program then enters a loop asking whether the user wants to view the next package folder, delete the currently viewed folder, or create a new folder.


PDF.EXE

Overview

PDF.EXE is a console application that processes a PDF file and creates a package in the SMS site server database. The main purpose of this program is to provide a working sample to developers who may want to process PDFs and load them into SMS from their own applications. This code demonstrates datasource connection, folder creation, scalar and token manipulation, folder display, SMS API version identification, and helper functions.

Running the Program

PDF.EXE runs as a console application. To run the program, you can type either PDF or PDF filename.PDF. The program prompts you to enter the information needed to connect to the SQL server and then prompts you to enter the name of the PDF file if you did not specify one on the command line. Specify the file name with the .PDF extension. At this point, the program may prompt you for a directory as follows:

  • An import directory, if the package will be set up for workstations and the PDF file does not specify an import directory.
  • A setup directory, if the package will be set up for sharing and the PDF file does not specify a setup directory.

In either case, if you do not enter a directory at the prompt, the package will not be completely set up in SMS.

Functions

SmsAPIVer
SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsCreateFolder
SmsLinkFolder
SmsCommitFolder
SmsSetScalar
SmsGetNextScalar
SmsGetScalarCount
SmsCloseFolder
SmsCreateFolder
SmsManipulateTokens
SmsAddToken
SmsGetTokenCount
SmsGetToken
SmsGetFolderID
SmsGetFolderType
SmsGetFolderCount
SmsGetNextFolder
SmsCloseFolder
SmsRewind
SmsGetNextFolder

Program Flow

After logging on to a datasource and obtaining any missing information from the user, the program creates the package and displays package details in the console.


RESDLL.DLL

The code in this directory demonstrates how to override and extend graphics in the SMS Administrator. In this example DLL, the default SMS icons for Packages, Macintosh workstations, PC Servers, User Groups, Macintosh Operating System, Mouse, and any non-Macintosh or non-PC system are replaced by the "eye" icon.

The techniques demonstrated in this sample application are documented in Overriding and Extending Graphics in the SMS Administrator.


SRVINST.EXE

Overview

SRVINST.EXE is a console mode application that can be used for creating server install jobs or Run Command on Workstation jobs and monitoring the status of these jobs. This code demonstrates datasource connection, folder creation, scalar manipulation, and helper functions.

Running the Program

SRVINST.EXE runs as a console application. The program prompts you to enter the information needed to connect to SQL Server and then displays a list of sites to target. It then prompts you to enter the target job platforms, and then lets you select the type of job to create.

The program will request the following input for a Share Package On Server job:

Package name
User-defined name of the package.
Package comment
User-defined text.
Package location (UNC path)
The path to the directory where the package files are located.
Package share name
The name that the package will be shared as on the server.
Program item description
User-defined text.
Program item command line
The command to execute on the server.
Program item registry name
User-defined registry key for the package.

The program will request the following input for a Run Command On Workstation job:

Package name
User-defined name of the package.
Package comment
User-defined text.
Package location (share name)
The path to the directory where the client package is located.
WCL Name
User-defined name for the workstation command line.
WCL Command
The command line to execute.

Note If you choose to create a Share Package On Server job or a Run Command On Workstation job, then you must first share the directory where the package files are located.

Functions

SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsCreateFolder
SmsLinkFolder
SmsCommitFolder
SmsCloseFolder
SmsGetNextFolder
SmsSetScalar
SmsGetScalarByName

Program Flow

After logging on to the datasource, a list of sites is displayed and the user is asked to select the site that the job will be run on. This site list is obtained by opening the site container and enumerating the sites found there. The code then queries the user for the platform type and converts the selected platform index to the corresponding platform flag. The user is then asked to choose between a Share Package On Server job or Run Command On Workstation job. The user is asked to enter the necessary scalar values for the job, and the job is created. The code then enters a loop where the status of the job is monitored and displayed periodically until the job completes.


TESTALL.EXE

Overview

This program illustrates the use of the SMS functions to examine a site hierarchy, package container, or job container. For each type of container, the user is prompted for which of the standard sets of filters to apply. The container is then populated, and enumerated to the console.

Running the Program

TESTALL.EXE runs as a console application. The program prompts you to enter the information needed to connect to SQL Server, then prompts you to specify Sites, Jobs, or Packages.

When viewing a Site hierarchy, the program will display the site/domain/machine/machine group tree for the associated datasource according to the filter conditions that you specify during program execution.

When viewing a job container, the user can select a Run Command On Workstation job (w), Share Package On Server job (s), Remove Package From Server job (r), or System job (y). Make one selection per line, and type x to specify no more job types. Selections are connected by the OR operator, so it is possible to select multiple job types. It is also possible to select no filters (x), in which case the system displays all job types.

When viewing a package container, the user can select a workstation package (w), a server package (s), or an inventory package (i). Make one selection per line, and type x to specify no more package types. Selections are connected by the OR operator, so it is possible to select multiple package types. It is also possible to select no filters (x), in which case the system displays all package types.

For both jobs and packages, the program will enumerate all folders and subfolders in the specified container. For each folder it will then display all scalars. After displaying the appropriate data, the program will allow you to restart (examine a new container) or quit.

Functions

SmsAPIVer
SmsDataSourceConnect
SmsDataSourceDisconnect
SmsOpenContainer
SmsCloseContainer
SmsPopulate
SmsGetFolderCount
SmsGetNextFolder
SmsGetFolderID
SmsGetFolderType
SmsGetScalarCount
SmsGetNextScalar
SmsCreateFilter
SmsSetFilter
SmsCloseFilter
SmsAddToken
SmsGetToken
SmsGetTokenCount

Program Flow

This program illustrates the use of the SMS functions to examine a site hierarchy, package container, or job container. The only difference in code between them is the setting of filters.

The code connects to the datasource and prompts the user to select the type of container to view. The user then is asked to select and apply valid filters for the container. All folders in the container are then retrieved, and the folder handles are stored in an array. The container is closed after the folder handles have been stored. The folders are then displayed recursively.

Note that the container is closed before the folders are displayed. This allows the memory used by the folders themselves to be recovered as soon as the folders are closed. Folders all have reference counts and will only be released when this count falls to zero. This technique is also used inside the DisplayFolder function in the sample.


TREE.EXE

Overview

TREE.EXE is a console mode application that builds and displays a tree of the container hierarchy. For each container, the container's type and tag are displayed, followed by a list of filters (possibly empty) which may be acted upon directly at that level of the hierarchy. Following the filter list is a folder list. The folder list gives the folder's type and tag, its filter list, and then a list of scalars for the folders. The scalar display shows the scalar name, type, and access mode. For filters, a list of the filter's attributes are displayed.

This program does not require a datasource connection. It gathers information about the SMS API objects, or object templates, not about specific instances of the objects. There is an important distinction between an object template and a specific instance of the object. A folder instance represents a particular object in the datasource, for example a specific job. A folder template represents the API's notion of the object. Thus, the characteristics of a System job, for example, are predetermined, but the values will be different for each instance of such a job. The same concepts apply to all containers and all folders.

This sample illustrates the self-describing nature of the API objects. It is of interest that a program such as this is, by definition, continually up-to-date. That is, if a future version of the API set were to have additional folders, then this same program could report information about those folder objects without being recompiled or relinked.

Running the Program

Simply type TREE.EXE to run this program. A description of the program will be displayed. The user should then press the ENTER key to continue the program. This program has no user-specified options. The program quits once the data has been displayed.

Functions

SmsAPIVer
SmsEnumContainers
SmsEnumFilters
SmsEnumFolders

Program Flow

This is a relatively simple program. It first gets the number of containers, then it gets the containers themselves, then does the same thing for filters and folders. It then loops through each container and displays all data for the container.

The following information is displayed for each container:

  • The container's tag and type
  • The number of filters activated by this container
  • A description of each of these filters
  • The number of folder types that can be contained in the container
  • A description of each of these folders

The following information is displayed for each filter:

  • The filter's tag and type
  • The names of the fields used by the filter's tokens

The following information is displayed for each folder:

  • The folder's tag and type
  • Filter details (as in container)
  • The number of scalars along with their names, type, and access mode
  • A recursive display of any subfolders that can be contained within this folder


The SMS Demonstration Database

The Platform SDK and the Microsoft Developer Network (MSDN) CD-ROMs include SMS demonstration site data in a separate SQL database. It is designed to be installed as a separate SMS database so that it does not override any previous SMS operations you have done. It also allows you to easily look at both pre-configured data and your real network by logging out and logging back into SMS with a different database name. The sections that follow describe how to install the SMS demonstration database.


Installing the SMS Demonstration Database

The demonstration database was created using SQL Server 6.5, but can be loaded on a SQL Server 6.0 installation running Service Pack 3 or later. (See the instructions for SQL Server 6.0 following this section.)

To set up the demonstration database
  1. Copy the files SMSDMP.DAT and SMS.SQL from the Platform SDK or MSDN CD-ROM, or from http://www.microsoft.com/smsmgmt/demodata.htm, to the directory C:\MSSQL\BACKUP. If SQL is not installed on drive C, you must change this accordingly and also alter the script as explained in the next section, Modifying the Installation.
  2. Start SQL Enterprise Manager from the task list and choose SQL Query Tool from the Tools menu.

  3. Log in to SQL Server. Use the sa account if you are prompted to do so (this will not usually be necessary).
  4. With the Query window open, choose Open from the File menu . Select the script file, \MSSQL\BACKUP\SMS.SQL.

  5. To run the script, choose Execute from the Query menu.

The script takes about five minutes to complete and updates you on its progress. When the script results state "100 percent loaded" in the Query window, the process is complete. (You may need to scroll down the window to see this message.) You can then close the SQL Enterprise Manager.


Modifying the Installation

If you have installed SQL Server on a different drive than the C drive, or you are using SQL Server 6.0 with Service Pack 3, you must modify the SMS.SQL script file. Use the SQL Query Tool to make your edits.

To edit the SQL drive letter
  1. Open the SMS.SQL script file.
  2. Find the two DISK INIT statements.
  3. Change PHYSNAME to match your drive letter and SQL directory structure. Do not change the .DAT file name.

    For example, change:

    PHYSNAME =  'C:\MSSQL\DATA\SMSDATA.DAT'

    to:

    PHYSNAME =  '<your SQL location>\DATA\SMSDATA.DAT'
  4. If necessary, find the LOAD DATABASE statement (the last line in the script) and change the path of the SMSDMP.DAT file.
To Use SQL Server 6.0 with Service Pack 3

If you are using SQL Server 6.0 with Service Pack 3 installed, you can load the demonstration database but you will need to make some changes to the SMS.SQL script and follow a different set of directions:

  1. Copy the files SMSDMP.DAT and SMS.SQL from the Platform SDK or MSDN CD-ROM, or from http://www.microsoft.com/smsmgmt/demodata.htm, to the directory C:\SQL60.
  2. Start ISQL/w (the SQL Query tool).
  3. Log in to SQL Server. Use the sa account if you are prompted to do so (this will not usually be necessary).
  4. Open the C:\SQL60\SMS.SQL script file.
  5. Find the two DISK INIT statements.
  6. Change the PHYSNAME path to match your SQL Server directory structure. By default this is 'C:\SQL60\DATA\…'
  7. Find the LOAD DATABASE statement (the last line in the script).
  8. Change the path to match your directory structure. By default this should be 'C:\SQL60\SMSDMP.DAT'.
  9. To run the script, choose Execute from the Query menu.
  10. The script takes about five minutes to complete and updates you on its progress. When the script results state "100 percent loaded" in the Query Results window, the process is complete. (You may need to scroll down the window to see this message.) You can then close ISQL/w.


Using the SMS API with Visual Basic

The SMS SDK provides a sample Visual Basic interface to the SMS API, and two sample applications that use this interface. These components are located in the \MSSDK\SAMPLES\SYSMGMT\SMS\VBSMSAPI directory of the Platform SDK CD-ROM.

The VBSMSAPI directory contains three subdirectories: COMMON, DLLS, and SAMPLES.

The COMMON directory contains five Visual Basic header files (two of them in the VB4SMS32 subdirectory of COMMON), which must be included by any sample applications that use the SMS API. These files provide all of the declarations needed so that a Visual Basic application can use the SMS API.

In order to write a Visual Basic application that uses the SMS API, the files in the COMMON directory must be copied to a location where your Visual Basic application can access them. The five .BAS files must also be added to your Visual Basic project. The Visual Basic .MAK file may need to be edited manually so that the files added appear in the correct order. The order is important because some of the files depend on definitions made in the preceding files. The correct order is: SMSINFO.BAS, QRYCODES.BAS, OBJECTTY.BAS, SMSAPI.BAS, VB4SMS32.BAS.

The DLLS directory contains another subdirectory called VB4SMS32, which contains the VB4SMS32.OLB (and source code to build the OLB). This OLB provides a set of cover routines that allow a 32-bit Visual Basic application to call the 32-bit SMSAPI.DLL. It must be added to your Visual Basic project using the References item in the Tools menu.

The VB4SMS32.OLB source code is also included in the DLLS directory. You can look at this source to see how certain functions and data structures in the SMS API were implemented under Visual Basic.

The SAMPLES directory contains the BROWSER and the REPORT sample programs. Both samples also use code in the SAMPLES\COMMON subdirectory (for instance, there is code there to present the database login dialog box). The two sample applications are described in more detail below.

Note If you are running a previous version of the SMS SDK (prior to version 1.2), and want to use the SMS API with Visual Basic 3.0, please see Using the SMS API with Visual Basic 3.0.

The Browser Sample

The browser sample provides a way to explore the SMS object hierarchy. The user can add any of the SMS container objects as root nodes in the sample's left-pane outline control. Expanding a container will enumerate its folders and display them as child nodes in the outline control. Expanding a folder does the same thing, except that scalars are enumerated as well.

The sample's right pane shows the type of the object selected in the left pane, along with information relevant for that object. With a container selected, the allowable subfolders and filters are listed. With a folder selected, the allowable subfolders and scalars are listed. With a scalar selected, the value of that scalar is shown.

The Report Sample

The report sample provides a simple, flexible framework for reporting information in the SMS database. The code illustrates how to use the SMS functions to obtain data for reporting purposes, and how to use the SMS filter functions to select desired data. The code implements two types of reports, and can be used as a generic report module to generate additional report types. There is even a skeleton report module called Generic that can be used to develop new reports.

The two implemented reports are a site hierarchy report and a machine group report. The site hierarchy report simply acquires the entire hierarchy of primary sites, secondary sites, and domains. The machine group report acquires the machine properties for all the machines in the desired machine group.

The user can create a new report of either type by choosing New in the File menu. The report data acquired from the SMS database is captured in an access database (*.MDB file) which can subsequently be saved and reopened later with the File menu's Open command. An open report can then be previewed and printed.

The sample uses Crystal Reports for Visual Basic (which is part of the Professional Edition) to do layout and printing of the reports. This provides Print, Preview, and Export to Text File capabilities as well as sophisticated report layout capabilities.

In addition, all information collected from Systems Management Server by the report application is stored in a Microsoft Access version 1.0 database file. This makes it possible to regenerate past reports by simply opening and reprinting saved reports. The saved report data can be further manipulated with a variety of ODBC-compliant tools, such as Microsoft Access.

Visual Basic Samples: Functions

The following SMS API routines are used in the sample programs. Those noted with an asterisk have calling conventions that differ from the corresponding SMS API routine, and are used only in the browser sample. The differences are due to the way that data structures are handled in C versus Visual Basic. See the sample code in the DLLS\VB4SMS32 directory to learn more about how and why these functions are different.

SmsApiVer
SmsDataSourceConnect
SmsDataSourceDisconnect
SmsEnumContainers *
SmsDescribeFolder *
SmsOpenContainer
SmsPopulate
SmsCloseContainer
SmsGetNextFolder
SmsRewind
SmsGetFolderID
SmsGetFolderType
SmsCloseFolder
SmsGetNextScalar
SmsGetScalarByName

Creating Your Own Sample Application

If you want to create your own sample Visual Basic application which uses the SMS API, you must follow these steps:

As previously noted, your application must have access to the five .BAS files from the COMMON directory, and these files must be added (in the proper order) to your Visual Basic project.

In addition, your application must have access to the SMSAPI.DLL included in the SMS SDK CD-ROM.

You must use the Microsoft Visual Basic version 4.0 32-bit Professional Edition. The VB4SMS32.OLB must be copied into a directory in your search path (a reasonable location would be in the same directory as SMSAPI.DLL). Finally, you must add this OLB to your Visual Basic project using the References item in the Tools menu.


Using the SMS API with Visual Basic 3.0

If you are running a previous version of the SMS SDK (prior to version 1.2), and want to use the SMS API with Visual Basic 3.0, please note the following requirements:

  • Visual Basic 3.0 must be installed before running the sample programs because they use the Visual Basic 3.0 run-time DLLs.
  • The Visual Basic 3.0 environment variables must be registered before running the sample programs. On Windows NT 3.5.1 and 4.0 systems, the following must be done to register the environment variables:
    1. Install Visual Basic 3.0.
    2. Put the smsroot\SITE.SRV\platform.BIN directory in the path.
    3. Put VB3SMS16.DLL in the smsroot\SITE.SRV\platform.BIN directory.
    4. Either stop and restart Windows on Windows or log off and log on again. (If this step is not performed, VB3SMS16.DLL will not be found and the sample programs will not run.)


Installation Programs

When a creating a new software package to run in a Systems Management Server environment, you must include a setup or installation program that supports the requirements of the SMS environment. You must also include a Package Definition File (PDF) that contains predefined Workstation, Sharing, and Inventory property settings for your package, and a package directory structure containing the files required to support the installation options in the PDF.

This section starts with an overview of the software installation process, including checklists of steps for installing and deinstalling software in an SMS environment. It then defines the SMS requirements for unattended installation programs, describes the package command status MIF file, and outlines the PDF format. Finally, it discusses the various SMS job types and options, providing sample PDFs for each type of job. Requirements for gaining the Microsoft BackOffice Logo are also described in this section.

Topics included in this section are as follows:

  • Installation Overview
  • Requirements for Gaining the Microsoft BackOffice Logo
  • SMS Requirements for Unattended Installation and Deinstallation
  • DLL Version Checking for ISV Application Installation
  • The Package Command Status MIF File
  • The Package Directory
  • Package Definition File Format
  • Using a prodspec.INI File for Package Identification
  • Installing Packages by Using SMS Jobs


Installation Overview

The installation of software in the SMS environment starts with collecting inventory information from computers throughout the enterprise. This hardware and software inventory information is stored in the SMS database and is used to plan and control the installation process.

SMS distributes software throughout an enterprise in the form of packages. These packages define the components to be installed, the supported platforms, and various configuration options for the software.

SMS installs software by using jobs that target specific sets of computers and define the mechanics of the distribution through the SMS hierarchy. A job defines a set of computers called distribution servers, which act as staging points in the hierarchy for packages. After a package is present on the distribution servers, the job is sent as a control file to the target clients, where it is executed by a component of the SMS client code called the Package Command Manager (PCM).

The processing of a job begins when the PCM mounts the package share point, changes the active directory to that point, and executes the command line specified in the job. The command line specified in the installation job is the setup or installation program for the application contained in the package. This command line can be anything appropriate to the actions required to install the software, and to the platform where the installation is to take place. The installation program must perform the actions required to install the application, and must also take the SMS environment into account by supporting the requirements of the SMS installation process.

For more information, see Installation Checklist and Deinstallation Checklist.


Installation Checklist

To install software in an SMS environment
  1. Create an installation or setup program according to the guidelines outlined in this section.
  2. Create a PDF using the format outlined in this section.
  3. Create a package directory.
  4. Import the software package into the SMS environment.
  5. Use an SMS job to install the package.
  6. Write a package command status MIF file in the Windows directory with a date and time stamp greater than the time that PCM launched the setup application. The package command status MIF indicates installation success or failure, and may provide additional information such as why the installation failed.

The same rules apply when maintaining packages.


Deinstallation Checklist

To deinstall software in an SMS environment
  1. Create a deinstallation program. This can be a command-line switch on your main setup program.
  2. Write a package command status MIF file in the Windows directory to indicate the success or failure of the deinstallation.


Requirements for Gaining the Microsoft BackOffice Logo

Microsoft has developed the Designed for Microsoft BackOffice logo program to provide developers and users with consistent criteria and standards to use in developing and implementing client/server solutions that live in the Microsoft BackOffice environment. The goal of the logo program is to help users identify applications designed specifically to take advantage of BackOffice components and functionality, and to allow developers to garner the marketing benefits of using the logo on product packaging, advertisements, collateral, and other materials. Meeting the criteria required to obtain a logo ensures that your product uses and benefits from important BackOffice technologies.

To meet the Systems Management Server requirements for this program, all applications must:

  1. Support installation and deinstallation in an unattended mode.

    For information on this requirement, see SMS Requirements for Unattended Installation and Deinstallation.

  2. Provide a package command status MIF file with the required Status and Description entries.

    For information on this requirement, see The Package Command Status MIF File.

  3. Provide a Package Definition File (PDF) with all required entries.

    For information on this requirement, see The Package Directory and Package Definition File Format.

    For an example of a PDF file for a simple application, see Run Command on Workstation Jobs.


SMS Requirements for Unattended Installation and Deinstallation

A software setup or installation program used in the SMS environment must support unattended installation and deinstallation in the following ways:

Operate in unattended mode
It is mandatory that the program not require input from the user during the installation, removal, or maintenance of the application. Any information or options required by the setup program should be supplied by command-line switches to the program, or should be provided in a configuration file that is read by the program at run time or by some other means such as the Windows Registry.

Your application must not show any dialog boxes or windows during installation/deinstallation or maintenance. This is required for completely unattended installation/deinstallation using the Package Command Manager.

Do not force restart
Because multiple packages can be installed by SMS at one time, no individual package installation should force a restart as part of its installation program. Instead, the PCM has the capability of intercepting restart requests and queuing them up until all packages have been installed, offering the user the opportunity to save any work in progress before the restart.
Pass restart instructions to the PCM
To copy system files that may be in use, setup programs typically construct a batch file containing operations that must be performed during a restart, such as running an MS-DOS program by using ExitWindowsExec, and then restarting Windows.

In order to set up multiple programs before a restart, the PCM prevents the restart, and then performs an ExitWindowsExec when the user elects to do so.

To coordinate multiple unattended setups, concatenate the batch file of each setup program to the file _MSSETUP.BAT. If _MSSETUP.BAT does not exist, then rename the batch file of the first setup program to _MSSETUP.BAT and concatenate the batch files of additional setup programs to that file. Next, create an _MSRSTRT.EXE program to be executed by the PCM when it calls ExitWindowsExec. This MS-DOS program (_MSRSTRT.EXE) must execute the batch file _MSSETUP.BAT and then delete the batch file and itself.

After the installations are complete, if the PCM detects both _MSSETUP.BAT and _MSRSTRT.EXE in the Windows directory, it displays a dialog box prompting the user to exit Windows and restart. This dialog box does not interfere with subsequent installations.


DLL Version Checking for ISV Application Installation

Applications compiled for a particular version of the SMS SDK DLLs (SMSAPI.DLL and OBJECTTY.DLL) will work with all subsequent versions of those DLLs, but may not run with earlier versions if new SDK functionality is being used. Additionally, the SDK DLLs are matched to a particular minor version of the SMS base DLLs (BASE.DLL) and will only run with that version of SMS.

To make sure that applications run correctly, ISV application setup programs should perform checks during installation to determine which version of SMS and which version of the SMS SDK exist on the system where the application will be installed. The setup program can then use this information to determine which version of the SDK DLLs must be used with the application.

This section describes the DLL resource strings that must be extracted to obtain version information, provides a code sample for extracting the resource strings, and details the actions to take to determine which DLLs to use with the application.


DLL Resource Strings with Version Information

The following DLLs must be checked for version information:

  • BASE.DLL, to obtain SMS version information.
  • SMSAPI.DLL, to obtain SDK version information.

To obtain version information, application setup programs must extract two resource strings within each DLL: ProductVersion and FileVersion. These strings contain the following information:

ProductVersion
The string has the following format in both DLLs:

SMS <Major SMS Version>.<Minor SMS Version>(Build <Build No.>)

For example: SMS 1.2(Build 123)

FileVersion
When extracted from BASE.DLL, this string has the following format:

SMS <Major SMS Version>.<Minor SMS Version>.<SDK Build Version>(Build <Build No.>)

For example: SMS 1.2.6(Build 124)

When extracted from versions of SMSAPI.DLL up to and including those shipped with SMS 1.2, this string has the following format:

SMS <Major SMS Version>.<Minor SMS Version>(Build <Build No.>)

For example: SMS 1.2(Build 123)

When extracted from versions of SMSAPI.DLL shipped with the 1.2 SDK (and subsequent releases), this string has the following format:

SMS SDK <Major SMS Version>.<Minor SMS Version>.<SDK Build Version>(<Optional Description Text>)

For example: SMS SDK 1.2.6(Internal Build)

The next section contains sample code to extract these resource strings from the SDK DLLs.


Code to Extract SDK DLL Version Information

The following C code extracts the resource strings FileVersion and ProductVersion from SMSAPI.DLL to obtain SDK version information. This code should also be run against BASE.DLL to extract SMS version information.

DWORD   dwVerInfoSize;        // Size of version information block
LPSTR   lpVersion;            // String pointer to 'version' text
DWORD   dwVerHnd=0;            // An 'ignored' parameter, always '0'
UINT*    puVersionLen = new UINT;
BOOL    bRetCode;

char szFileName[20];
strcpy(szFileName, "smsapi.dll");

dwVerInfoSize = GetFileVersionInfoSize(szFileName, &dwVerHnd);
if (dwVerInfoSize) {
            LPSTR   lpstrVffInfo;
            HANDLE  hMem;
            hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
            lpstrVffInfo  = (char *)GlobalLock(hMem);
            GetFileVersionInfo(argv[1], dwVerHnd, dwVerInfoSize, lpstrVffInfo);

            // Product Version
            bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
                TEXT("\\StringFileInfo\\040904E4\\ProductVersion"),
                (LPVOID *)&lpVersion,
                puVersionLen);

            if(bRetCode)
            {

                printf("ProductVersion %s\n",lpVersion);

            }
            else
            {
                printf("ProductVersion query failed\n");
            }

            // File version
            bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
                TEXT("\\StringFileInfo\\040904E4\\FileVersion"),
                (LPVOID *)&lpVersion,
                puVersionLen);

            if(bRetCode)
            {

                printf("FileVersion %s\n",lpVersion);

            }
            else
            {
                printf("FileVersion query failed\n");
            }
}


Location of the SDK DLLs

A version of both the SMS 1.1 and 1.2 SDK DLLs ship with this SDK. The SMS 1.2 SDK DLLs are located under the BIN or BIN\platform directory, where platform is the processor type of the computer—i386, Alpha, or MIPS. The SMS 1.1 SDK DLLs are located in a SMS 1.1 directory under BIN or BIN\platform.


Determining Which DLLs to Use

ISV applications that are intended to be installed on both SMS 1.1 and 1.2 should ship with a version of the SMS 1.1 DLLs because these DLLs are not included in an SMS 1.1 installation.

It may also be appropriate to ship the application with a version of the SMS 1.2 DLLs if the application requires a later version of the DLLs than the version that shipped with the SMS 1.2 product. The SMS 1.2 DLLs shipping with this SDK are a later version and include functional enhancements that are not part of the DLLs shipped with the SMS 1.2 product.

To determine which version of the DLLs to use with the application, run the code shown in the previous section on BASE.DLL to determine which version of SMS is running on the system where the application is being installed. Then, take one of the following actions:

For applications that ship with SDK DLLs

When the application is being installed on SMS 1.1:

  • If the application is shipping with SMS 1.1 SDK DLLs, these DLLs should be installed and used.
  • If the application is shipping with SMS 1.2 SDK DLLs and a version of the SMS 1.1 DLLs is not found in the site server BIN directory, the setup program should report an error stating that the ISV application cannot run with this version of SMS.
  • When the application is being installed on SMS 1.2:
  • If the application is shipping with SMS 1.2 SDK DLLs, the setup program should compare the build version of the DLLs being shipped with that of the DLLs in the SMS site server BIN directory. The DLLs with the higher build number should be used. If the DLLs shipped with the application have the higher build number, they should be installed in the SMS site server BIN directory and the application should load them from this directory.

    If the DLLs have the same build number, the application can use the existing DLLs in the site server BIN directory.

  • If the SDK DLLs being shipped with the application are of a different version of SMS (other than 1.2), the application should use the existing DLLs in the site server BIN directory.

For applications that do not ship with SDK DLLs

The setup program must make sure that it can load the SDK DLLs from the SMS site server BIN directory. If the application is being installed on SMS 1.1 and the DLLs are not present, the setup program should report an error stating that the ISV application cannot run with this version of SMS.


The Package Command Status MIF File

To report the status of a PCM-spawned application installation or deinstallation, a package command status MIF file must be created in the Windows directory. The MIF file name must be unique so that multiple installations in a single session can report their status without a conflict in the name of the package command status MIF files.

Additionally, the creation date and time stamp of the MIF file must be set to a time after PCM started to run the job. In this way, PCM knows that the MIF file was placed there by your setup program and will update the SMS database with the values the file provides. The same rules apply to the package command status MIF file for deinstallation and maintenance.

It is important to note that PCM looks for package command status MIF file(s) after the setup command that PCM launched completes. Thus, your installation must write the MIF file(s) before the original process launched by PCM exits. If your installation runs one command, and that command spawns another command that actually writes the MIF file(s) after the first command has terminated, PCM will not recognize that the second command has written a package command status MIF file, and the MIF file will not be reported to SMS.

Package command status MIF files for applications that run on localized versions of SMS must be in the appropriate format: ANSI format for European languages; DBCS format for Far East languages. Additionally, the description string reporting the success or failure of the installation must be localized.

SMS 1.2 provides two DLLs to assist ISVs in writing package command status MIF files:

  • ISMIF32.DLL, for use on 32-bit machines
  • ISMIF16.DLL, for use on 16-bit machines

Programs started by a package command can call a function (InstallStatusMIF) from these DLLs that reports the status of the job corresponding to the package command. This function creates a package command status MIF file in the Windows directory with the correct date and time stamp.

SMS also provides a tool, ISMIF, that writes a generic status MIF file from information given through a command line and/or a dialog box.

For more information, see the following:

InstallStatusMIF Function Parameters

Sample Code to Call InstallStatusMIF

Sample Package Command Status MIF File

Status MIF File Creator (ISMIF)


InstallStatusMIF Function Parameters

The function prototype for InstallStatusMIF is shown below:

DWORD WINAPI_loadds InstallStatusMIF(
  char *szFileName,
  char *szCompany,
  char *szProduct,
  char *szVersion,
  char *szLocale,
  char *szSerialNo,
  char *szMessage,
  BOOL bStatus
);

Parameters

szFileName
A unique name for the MIF file. To ensure that the name is unique, you can specify the name of the application being installed or removed, or you can use the Win32 function GetTempFileName, which creates a temporary file with a unique name. Do not specify a path or file extension.
szCompany
Any string for the company name.
szProduct
Any string for the product name.
szVersion
Version of the product.
szLocale
The localization key that identifies the language version of the product. See the Microsoft Development Network (MSDN) Development Library for tables of the localization key names.
szSerialNo
Any string for the serial number.
szMessage
String reporting the success or failure of the installation. This string must be localized.
bStatus
Install status; specify TRUE if the installation was successful; otherwise FALSE.


Sample Code to Call InstallStatusMIF

You must include code in your setup application that calls InstallStatusMIF. Note that your setup application should create one and only one package command status MIF file.

An example of the required setup code is shown below. This example loads the appropriate library (ISMIF32.DLL or ISMIF16.DLL), retrieves the address of the InstallStatusMIF function, and then calls the function, passing the parameters for the application being installed or removed. The code also reports whether the MIF file was created and, if not, the reason for the failure.

If successful, this code sample results in a package command status MIF file called OFFICE97.MIF in the Windows directory.

{
HINSTANCE hInstLibrary;
DWORD (WINAPI *InstallStatusMIF)(char*, char*, char*, char*,
        char*, char*, char*, BOOL);

#ifdef WIN32
   if (hInstLibrary = LoadLibrary("ismif32.dll"))
#elif defined WIN16
   if (hInstLibrary = LoadLibrary("ismif16.dll"))
#endif
 {
   InstallStatusMIF = (DWORD (WINAPI *)(char*,char*,char*,
         char*,char*,char*,char*,BOOL))GetProcAddress(hInstLibrary,
         "InstallStatusMIF");
if (InstallStatusMIF)
{
        if (InstallStatusMIF("office97", "Microsoft", "Office 97",
           "999.999", "ENU", "1234","Completed successfully",
           TRUE) !=0)
{
    MessageBox("File is in your windows directory\Operation
                      successful");
}
else
{
    MessageBox("Write to MIF file failed");
}
}
else
{
MessageBox("Failed to get procedure address from DLL");
}
FreeLibrary(hInstLibrary);
}
else
{
MessageBox("Load of DLL failed");
}
}

See Sample Package Command Status MIF File for an example of the resulting MIF file.


Sample Package Command Status MIF File

The following example shows the package command status MIF file (called OFFICE97.MIF) created by the previous code sample.

START COMPONENT
 NAME="WORKSTATION"
 START GROUP  NAME="ComponentID"
  ID=1
  CLASS="DMTF|Component|1.0"
  START ATTRIBUTE
   NAME="Manufacturer"
   ID=1
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(64)
   VALUE="Microsoft"
  END ATTRIBUTE
  START ATTRIBUTE
   NAME="Product"
   ID=2
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(64)
   VALUE="Office 97"
  END ATTRIBUTE
  START ATTRIBUTE
   NAME="Locale"
   ID=4
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(64)
   VALUE="ENU"
  END ATTRIBUTE
  START ATTRIBUTE
   NAME="Serial Number"
   ID=5
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(64)
   VALUE="1234"
  END ATTRIBUTE
  START ATTRIBUTE
   NAME="Version"
   ID=3
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(64)
   VALUE="999.999"
  END ATTRIBUTE
  START ATTRIBUTE
   NAME="Installation"
   ID=6
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(64)
   VALUE="DateTime"
  END ATTRIBUTE
 END GROUP
 START GROUP
  NAME="InstallStatus"
  ID=2
  CLASS="MICROSOFT|JOBSTATUS|1.0"
  START ATTRIBUTE
   NAME="Status"
   ID=1
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(32)
   VALUE="Success"
  END ATTRIBUTE
  START ATTRIBUTE
   NAME="Description"
   ID=2
   ACCESS=READ-ONLY
   STORAGE=SPECIFIC
   TYPE=STRING(128)
   VALUE="Completed Successfully"
  END ATTRIBUTE
 END GROUP
END COMPONENT


Status MIF File Creator (ISMIF)

SMS provides a tool, ISMIF, that writes a generic status MIF file from information given through a command line and/or a dialog box (ISMIF16 only). Two versions of the tool are provided: ISMIF16.EXE and ISMIF32.EXE.

ISMIF16 is a 16-bit application that opens a dialog box where you can type any information not specified on the command line; items specified on the command line appear in the corresponding fields of the dialog box.

ISMIF32 is a 32-bit application that has no dialog box; any information must be specified on its command line.

For more information, see the following:

ISMIF16 Syntax

ISMIF32 Syntax

ISMIF32 Example


ismif16 Syntax

ismif16  [-f filename]  [-c manufacturer]  [-p product]  [-v version]  [-l locale]  [-n serial_number]  [-d description]  [-s success]  [-q]  [-?]
-f filename
Specifies the name of the MIF file that will be created. A .MIF extension is automatically appended. The default name is SETUP.MIF.
-c, -p, -v, -l, -n, -d
Each of these options can specify a text string. Each of these options corresponds to a field in the resulting dialog box. Strings containing spaces must be surrounded by quotation marks. The description string (-d) must be localized.
-s success
0 or 1. 1 means success.
-q
Quiet mode. No output is displayed on the screen.
-?
Provides a usage statement.


ismif32 Syntax

ismif32  [-f filename]  [-c manufacturer]  [-p product]  [-v version]  [-l locale]  [-n serial_number]  [-d description]  [-s success]  [-q]  [-?]
-f filename
Specifies the name of the MIF file that will be created. A .MIF extension is automatically appended. The default name is SETUP.MIF.
-c, -p, -v, -l, -n, -d
Each of these options can specify a text string. Strings containing spaces must be surrounded by quotation marks. The description string (-d) must be localized.
-s success
0 or 1. 1 means success.
-q
Quiet mode. No output is displayed on the screen.
-?
Provides a usage statement.


ismif32 Example

The following command shows the use of ISMIF32:

ismif32  -c  Microsoft  -p  SMS  -v  1.2  -d  "The most effective
multi-site management system that provides integrated desktop
management for customers with medium to large Windows environments."

This command creates a file in your Windows directory called SETUP.MIF that contains:

START COMPONENT
  NAME = "WORKSTATION"
  START GROUP    NAME = "ComponentID"
    ID = 1
    CLASS = "DMTF|ComponentID|1.0"
    START ATTRIBUTE
      NAME = "Manufacturer"
      ID = 1
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(64)
      VALUE = "Microsoft"
    END ATTRIBUTE
    START ATTRIBUTE
      NAME = "Product"
      ID = 2
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(64)
      VALUE = "SMS"
    END ATTRIBUTE
    START ATTRIBUTE
      NAME = "Version"
      ID = 3
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(64)
      VALUE = "1.2"
    END ATTRIBUTE
    START ATTRIBUTE
      NAME = "Locale"
      ID = 4
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(16)
      VALUE = ""
    END ATTRIBUTE
    START ATTRIBUTE
      NAME = "Serial Number"
      ID = 5
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(64)
      VALUE = ""
    END ATTRIBUTE
    START ATTRIBUTE
      NAME = "Installation"
      ID = 6
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(64)
      VALUE = "DateTime"
    END ATTRIBUTE
  END GROUP
  START GROUP
    NAME = "InstallStatus"
    ID = 2
    CLASS = "MICROSOFT|JOBSTATUS|1.0"
    START ATTRIBUTE
      NAME = "Status"
      ID = 1
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(32)
      VALUE = "Failed"
    END ATTRIBUTE
    START ATTRIBUTE
      NAME = "Description"
      ID = 2
      ACCESS = READ-ONLY
      STORAGE = SPECIFIC
      TYPE = STRING(148)
      VALUE = "The most effective multi-site management system that
provides integrated desktop management for customers with medium to
large Windows environments."
    END ATTRIBUTE
  END GROUP
END COMPONENT


The Package Directory

The package directory is a directory structure that contains the files required to support the installation or removal options in the Package Definition File. When a job is created that uses a package, the contents of the package directory, including any subdirectory structure, are compressed and sent to the site servers of the target clients. When the compressed package is received at the site server, it is copied to the distribution servers specified in the job and decompressed. The package contents are then exported from the distribution server with the appropriate permissions set.

All of the files required to support the operation of the job must be included in the package directory, including any DLLs or configuration files required to support the operation of the setup program.

It is highly recommended that you add an option on your setup program to create this directory on a network share with all of the files required to support the installation (or deinstallation), including the SMS PDF file. This indicates that you are SMS-capable and will make it easier for administrators to use SMS with your product.


Package Definition File Format

A Package Definition File (PDF) is an ASCII text file that contains predefined Workstation, Sharing, and Inventory property settings for a package. When you create a new package, you can use the Import command from the Package Properties dialog box to define the properties for the package, using a PDF.

A PDF follows the standard initialization file format. It is an ASCII text file containing keys (the key names are enclosed within square brackets). Key names can be separated by spaces. Each key contains one or more entries, where each entry follows the format: name = value1, value2, …. Values are separated by a comma and at least one space. The keys and entries are used by the system to set the properties of a package.

PDF files for applications that run on localized versions of SMS must be in the appropriate format: ANSI format for European languages; DBCS format for Far East languages. Additionally, some file entries must be localized. See the descriptions below for details.

The following topics describe the specific keys and entries for PDF files. All PDF files must, at a minimum, include the required entries listed below.

[PDF] (required)

[Package Definition] (required)

[SetupVariation Setup]

[Setup Package for Sharing]

[Program Item Properties Index] (required for shared applications)

[Setup Package for Inventory] (required)

[FileIndex] (required)


[PDF] (required)

The [PDF] section identifies the file as a Package Definition File. This section contains a single entry:

Version (required)
The version of the PDF format used by the file. Specify the current major version of SMS.

Example:

Version = 1.2


[Package Definition] (required)

The [Package Definition] section defines the overall properties of the package.

Product (required)
The name of the product. This text must be localized.

Example:

Product = Microsoft Excel
Version (required)
The version of the product. This text must be localized.

Example:

Version = 4.0a
Comment (required)
The comment used for the package’s Comment setting. When the PDF is imported into SMS, this string is used as the Comment in the Package Properties. This text must be localized.

Example:

Comment = version 4.0a for Windows
SetupVariations (required)
A list of the setup variations supported by the package. Each setup variation name corresponds to a PDF key that defines a package command. The recommended name for these keys is [SetupVariation Setup].

Example:

SetupVariations = Typical, Complete, Laptop, Automated
WorkstationAccess (recommended)
The access permissions to the packages created with this PDF. You can assign permissions to two user groups: Users and Guests. There are two permissions that you can assign:
Read
Permits users in the group to read and copy files, run programs, change directories within the shared directory, and read extended attributes of files.

To run a program file (that is, one with a .COM, .EXE, or .BAT extension), the user must have Read permission.

Write
Permits users in the group to write the contents and extended attributes of files.

You assign permissions to these groups by using the following entries: UserRead sets Read permission for the Users group, UserWrite sets Write permission for the Users group, GuestRead sets Read permission for the Guests group, and GuestWrite sets Write permission for the Guests group.

The default is for both Users and Guests to have both Read and Write permissions.

Example:

WorkstationAccess = UserRead, UserWrite, GuestRead


[SetupVariation Setup]

For the setup variations specified in the SetupVariation entry in the [Package Definition] key, the PDF must have a key that defines each variation. For SMS, the setup variations specify the package commands that will be defined for the package’s Workstations property.

CommandName (required)
The name used for this package command. When the PDF is imported into SMS, this string is used as the Command Name for this package command. This text must be localized.

Example:

CommandName = Automated Minimum Installation
CommandLine (required)
The command line used for this package command. When the PDF is imported into SMS, this string is used as the Command Line for this package command.

Example:

CommandLine = setup.exe
UserInputRequired (required)
The value for this entry specifies whether this package command requires interaction with the user to complete the command. You can specify TRUE or FALSE.

Example:

UserInputRequired = FALSE
SynchronousSystemExitRequired (required)
On Windows clients, by default, once SMS starts executing a job, it intervenes if it receives a request to exit the Windows environment. SMS does this by returning zero if it receives a WM_QUERY_END_SESSION. SMS then presents a dialog box asking the user to confirm when it is okay to restart the computer. For programs simply attempting to restart the system, this does not cause a problem. However, it does cause a problem for jobs attempting to run MS-DOS programs using ExitWindowsExec. Setting SynchronousSystemExitRequired to TRUE disables the default SMS behavior so that the job can run an MS-DOS program.

On MS-DOS clients, setting SynchronousSystemExitRequired to TRUE indicates to SMS that the job will cause the client to restart. This tells SMS to use overlay mode when executing the job, freeing up the memory used by SMS so it can be made available to the program being executed. By default, SMS executes programs synchronously and remains in memory when a job command line is executed.

Note that setting this value to TRUE is not necessary just to exit the environment at the end of the package setup program.

The possible values are TRUE and FALSE, and the default is FALSE.

Example:

SynchronousSystemExitRequired = FALSE
SupportedPlatforms (required)
The value for this entry specifies the operating systems where the package can be installed and run. Each operating system name must be separated by a comma and a space.

Example:

SupportedPlatforms = Windows, Windows NT (Alpha), Macintosh

Note that a version number is no longer needed and should not be used with Windows and Windows NT. Old PDFs that specified Windows 3.1 or Windows NT 3.1 will still work with SMS, but PDFs that specify any other versions of these platforms will not work. Particular versions of an operating system can still be uniquely targeted for package installation by using the SMS database query feature.


[Setup Package for Sharing]

The [Setup Package for Sharing] section defines the Sharing properties of the package. Sharing properties are used for installing the package on servers and sharing it from those servers (Share Package On Server jobs).

ShareName (required)
The share name that you want to assign to the shared package when it is installed on a server.

Example:

ShareName = exc40ash
ShareAccess (required)
The access permissions to the package’s share when the shared package is installed on a server. You can assign permissions to two user groups: Users and Guests. There are two permissions that you can assign:
Read
Permits users in the group to read and copy files, run programs, change directories within the shared directory, and read extended attributes of files.

To run a program file (one with a .COM, .EXE, or .BAT extension), the user must have Read permission.

Write
Permits users in the group to write the contents and extended attributes of files.

You assign permissions to these groups by using the following entries: UserRead sets Read permission for the Users group, UserWrite sets Write permission for the Users group, GuestRead sets Read permission for the Guests group, and GuestWrite sets Write permission for the Guests group.

Example:

ShareAccess = UserRead, UserWrite, GuestRead, GuestWrite


[Program Item Properties Index] (required for shared applications)

Each [Program Item Properties Index] key specifies the program item properties for network applications contained in the package. Each program item will be defined in the package’s Sharing property. The Program Item Properties key heading should have the following form: [Program Item Properties Index], where Index is a unique integer that identifies the program item within the PDF. The Index should start at 1 and increase by 1 for each additional program item.

Description (required)
The text used at workstations for the network application’s program item description. When the PDF is imported into SMS, this entry is used as the Description for the program item. This text can be localized.

Example:

Description = Microsoft Excel
CommandLine (required)
The command used to start the network application.

Example:

CommandLine = EXCEL.EXE
ConfigurationScript (required)
The configuration script file used to configure the network application at workstations. Note that this value can be NULL. If an explicit path is not specified, the package source directory is the default path to the configuration script.

Example:

ConfigurationScript = exc40a0n.PCD
RegistryName (required)
The name of the key where the network application’s configuration information is stored in the Windows registry.

Example:

RegistryName = EXCEL4
DefaultINIFile (required)
The file that the network application uses as a default initialization file.

Example:

DefaultINIFile= EXCEL4.ini
RunMinimized (required)
This entry specifies whether the network application should be minimized to an icon each time the user starts it by using the program item. You can specify TRUE or FALSE.

Example:

RunMinimized = TRUE
RunLocalCopyIfPresent (required)
Specifies whether the SMS APPSTART program should search local directories on the workstation’s path for the file specified by CommandLine. If APPSTART finds this file, it starts the local version; otherwise, it starts the network version. You can specify TRUE or FALSE.

Example:

RunLocalCopyIfPresent = TRUE
DriveMode (required)
This entry specifies how the SMS APPSTART program should connect to the server and shared directory where the network application is located. You can specify one of three values:
UNC
APPSTART executes the network application by using a UNC name. No drive letter is connected to the application’s shared directory.
ANYDRIVELETTER
APPSTART must connect to the application’s shared directory by using a drive letter—but APPSTART can use any available drive letter on the workstation.
SPECIFICDRIVELETTER DRIVE:
APPSTART must connect to the application’s shared directory by using a specific drive letter. DRIVE specifies the drive letter that APPSTART must use. The drive letter must be followed by a colon (:).

Example:

DriveMode = SPECIFICDRIVELETTER  W:
SupportedPlatforms (required)
This entry specifies the operating systems on which the program item is to be made available. Separate the operating system names with commas. When the PDF is imported into SMS, this entry is used as the Supported Platforms for the program item.

Example:

SupportedPlatforms = Windows, Windows NT (Alpha), Macintosh

Note that a version number is no longer needed and should not be used with Windows and Windows NT. Old PDFs that specified Windows 3.1 or Windows NT 3.1 will still work with SMS, but PDFs that specify any other versions of these platforms will not work. Particular versions of an operating system can still be uniquely targeted for package installation by using the SMS database query feature.

DisplayIconInProgGroup
This entry specifies whether an application icon is placed in a program group. This entry should be FALSE for utility applications, such as MSAPPS, that are to be distributed along with other shared applications.

Example:

DisplayIconInProgGroup=FALSE
SetupIcon
This entry specifies the file containing the icon that you want to use for the network application.

Example:

SetupIcon = exc40a01.ico


[Setup Package for Inventory]

[Setup Package for Inventory] (required)

The [Setup Package for Inventory] section defines the Inventory properties of the package. The Inventory properties are used by the SMS system to maintain inventory on the package.

The SMS system identifies a package by searching for a set of files that you specify in the package’s Inventory properties. For each file, you specify the attributes used to detect the file (such as file date, file size, CRC, and so on). If the SMS Inventory Agent program detects files that satisfy the conditions set by the package’s Inventory properties, the Inventory Agent reports that the package has been detected on the workstation.

Within the Inventory properties, you can also set an option that enables SMS to collect specified files from workstations and store them at the site server.

InventoryThisPackage (required)
This entry specifies whether the package should be included in the SMS inventory. You can specify TRUE or FALSE.

Example:

InventoryThisPackage = TRUE
Detection Rule (required)
This entry specifies the inventory rule used to identify the package. A package’s inventory rule is the set of files used to identify the package. Using the AND and OR operators, you can specify the set of files required to detect the package.

For the files specified in the rule (except Boolean operators and grouping operators), the PDF must have a key that defines each file. Each file corresponds to a key that defines the attributes of the file. The file key heading must have the following form: [File index] where index is a unique integer that identifies the file within the PDF and the inventory rule. The index should start at 1 and increase by 1 for each additional file.

You combine the file specifications by using the following rules:

  • Files are combined using AND and OR operators. AND has precedence over OR.
  • Files can be grouped and ungrouped by using parentheses. Files within a group are treated as a single entity. For example, the rule File1 AND (File2 OR File3) specifies that SMS detects the package when File1 is found and either File2 or File3 is found—that is, File1 = TRUE and (File2 OR File3) = TRUE. Groups have precedence over AND and OR.

Example:

Detection Rule Part 1 = File1
Detection Rule Part 2 = AND
Detection Rule Part 3 = File2
Detection Rule Part 4 = OR
Detection Rule Part 5 = (
Detection Rule Part 6 = File3
Detection Rule Part 7 = AND
Detection Rule Part 8 = File4
Detection Rule Part 9 = )


[FileIndex] (required)

For the files specified in the PackageDetectionRule entry in the [Setup Package for Inventory] key, the PDF must have a key that defines each file. Each file corresponds to a key that defines the attributes of the file. The file key heading must have the following form: [File index] where index is a unique integer that identifies the file within the PDF and the inventory rule. The index should start at 1 and increase by 1 for each additional file.

The Filename entry is required. All other attributes are optional.

Filename (required)
The name of the file.

Example:

Filename = EXCEL.EXE
Collect
This entry specifies whether the SMS system should collect a copy of this file and store it on the site server. You can specify TRUE or FALSE.

Example:

Collect = FALSE
BYTE
This entry specifies a value stored at a specific location in the file. This attribute requires two entries (separated by a comma and a space): Location is the data offset in bytes, and Value is the value stored at the offset. By default, the entries are decimal. To specify a hexadecimal number, start the hexadecimal number with 0x.

Example:

BYTE = 20000, 216
Checksum
This entry detects the sum of all values stored at a specific set of bytes and compares the sum to a specified value. This attribute requires three entries (separated by a comma and a space): Start Location is the data offset where the summed values begin (in bytes), Length is the total number of bytes that are summed, and Checksum Value is the value checked against the summed values. By default, the entries are decimal. To specify a hexadecimal number, start the hexadecimal number with 0x.

Example:

Checksum = 10000, 300, 32444
CRC
This entry detects the sum of all values stored at a specific set of bytes and compares the sum to a specified value. Unlike Checksum, CRC takes into account the sequence of the summed bytes. This makes it a more reliable identification of a file. In this attribute’s settings, Start Location is the data offset where the summed values begin (in bytes), Length is the total number of bytes that are summed, and Checksum Value is the value checked against the summed values.

SMS uses the CCITT-CRC standard to evaluate the CRC value. You must specify a CRC value computed with the CCITT-CRC algorithm.

By default, the entries are decimal. To specify a hexadecimal number, start the hexadecimal number with 0x.

Example:

CRC = 5000, 300, 38707
Date
The date of the file in decimal format: MM, DD, YY. The entries must be separated by a comma and a space.

Example:

Date = 9, 2, 93
Size
The size of the file (in bytes).

Example:

Size = 2766592
Time
The time of the file (using the 24-hour clock) in hours and minutes. The entries must be separated by a comma and a space.

Example:

Time = 14, 18
LONG
An unsigned LONG value. This attribute requires two entries (separated by a comma and a space): Location is the data offset in bytes, and Value is the value stored at the offset.

Example:

LONG = 30000, 1346373702
WORD
A WORD value. This attribute requires two entries (separated by a comma and a space): Location is the data offset in bytes, and Value is the value stored at the offset.

Example:

WORD = 40001, 15488
Token # (1–4)
A string value. This attribute requires two entries (separated by a comma and a space): Location is the data offset in bytes, and Value is the string value stored at the offset. The string value must be enclosed by double quotation marks. You can define up to four separate StringValue entries.
Example:
Token 1 = 710, "WIN"
Token 2 = 714, "EXCEL"


Using a prodspec.ini File

Using a prodspec.INI File for Package Identification

It is very important that inventory rules for a package or product define that product uniquely among all other products that may be installed on a machine. SMS uses the file names and characteristics (such as file size, file CRC, etc.) defined in the Inventory section of the PDF file to identify packages.

Developers normally build the Inventory section of the PDF file early in the development process, when target inventory file names have been identified. Because the chosen file characteristics can become invalid as the project progresses, a step must be included in the development schedule to ensure that the PDF Inventory section is updated whenever the file characteristics change.

You can avoid this problem by using a prodspec.INI file in conjunction with the Inventory section of the PDF file. A prodspec.INI file uses the standard .INI format and contains sections and keys that uniquely identify a specific version of a package. This file can be created early in the development process, and remains unchanged until the next and subsequent releases of the package. The Inventory section of the PDF file is then updated once to target the prodspec.INI file.

SMS identifies the package by searching for the file or files specified in the PDF Inventory section and, if found, comparing the files’ characteristics with those specified in the PDF file.

This section includes the following topics:

Contents of the prodspec.INI File

Naming the prodspec.INI File

Adding Inventory Rules to the PDF File

Guidelines for Developing SMS Inventory Support


Contents of the prodspec.INI File

The prodspec.INI file uses the standard .INI file format and contains sections and keys that, taken together, uniquely define a specific version of a product.

The contents of the prodspec.INI file are entirely arbitrary. However, the following sections and keys are recommended:

  • [SMS Inventory Identification]

    This section contains the version number that identifies the file for SMS inventory if the file is used in later versions of SMS. This section also contains a warning to users not to edit the file.

  • [Product Specification]

    The following keys are recommended: product name, version, localization, and patch or service pack level. These keys enable SMS to uniquely inventory versions of a package at different patch levels as well as the product itself. The localization key identifies the language version of the product. See the Microsoft Development Network (MSDN) Development Library for tables of the localization key names.

It is important to note that a unique prodspec.INI must be created and included with the package each time the package ships. Upgrades of applications must replace the existing prodspec.INI to ensure that SMS inventories the application accurately. If prodspec.INI files for previous versions of the package remain after an upgrade, SMS will report both versions of the software.

For more information, see Example prodspec.INI File and Naming the prodspec.INI File.


Example prodspec.INI File

The following is an example of a prodspec.INI file:

[SMS Inventory Identification]
;USER NOTE NEVER DELETE OR CHANGE THIS FILE IN ANY WAY
Version=1.0

[Product Specification]
Product=Windows NT 4.00 Workstation
Version 4.0
Localization=enu
ServicePackNumber=Vanilla


Naming the prodspec.INI File

The name of the prodspec.INI file should be as unique as possible. A suggested way to do this is to use the first letters of the product’s name. For example:

Product | File name
Microsoft Windows NT | NTSPEC.INI
Microsoft SQL Server | SQLSPEC.INI
Microsoft Exchange | EXCHSPEC.INI
Microsoft SNA Server | SNASPEC.INI

Note that you do not need to use “SPEC” as the last four letters of the name. Any name can be chosen.

Additionally, you should choose a file name that conforms to MS-DOS 8.3 file naming conventions to ensure that the package can be installed successfully on 8.3 file systems.


Adding Inventory Rules to the PDF File

After the prodspec.INI file has been created, you should add inventory rules to the PDF file that specify the name of the prodspec.INI file and its CRC value (or some other unique characteristic). You can generate file CRCs using the create package function in the SMS Administrator console or with the SMS Resource Kit utilities. If you use the CRC to define the inventory rule, then very little of the prodspec.INI file needs to change when a new version of the product ships.

You can increase the accuracy of package recognition by specifying additional files in the PDF inventory section which are likely to exist only in the target package.

SMS identifies the package by searching for the file or files specified in the PDF inventory section and, if found, comparing the files’ characteristics with those specified in the PDF file.

For more information, see Example PDF Inventory Section.


Example PDF Inventory Section

The following is an example of a PDF inventory section:

[Setup Package for Inventory]
InventoryThisPackage=TRUE
Detection Rule Part 1=File 1
Detection Rule Part 2=AND
Detection Rule Part 3=File 2

[File 1]
FILE=ntoskrnl.exe
COLLECT=FALSE

[File 2]
FILE=ntspec.ini
COLLECT=FALSE
;Checksum details for NT 4.0 Workstation ntspec.ini
CRC=0, 267, 38501

In this example, SMS inventories the product if the NTSPEC.INI file with a file length of 267 bytes and CRC 38501 is present and the file NTOSKRNL.EXE is also present on the inventoried machine. The NTOSKRNL.EXE file was chosen as a file that is expected to exist only on Microsoft Windows NT, but no CRC is specified because this file is likely to change until the product is finalized. Using two files in this way provides a high probability of accurate package recognition.


Guidelines for Developing SMS Inventory Support

Each product revision must include revised prodspec.INI and PDF files to ensure that SMS accurately inventories the revised product.

The following seven-step procedure is recommended for developing SMS inventory support:

  1. Early in the development cycle, create the prodspec.INI file, choosing a unique file name appropriate to the product. Include enough detail in the file to ensure that it will be unique in subsequent shipments of the product.

    If there are different versions of the same product, you can have a prodspec.INI file for each. For example, a product may have client and server pieces that can be installed on the same machine as individual components.

  2. Add the newly-created prodspec.INI file to the product build process and modify your setup application to ensure that the file is shipped and installed with the product.
  3. Develop the inventory rules for the PDF file, including any other files that help to uniquely identify the product. Add the completed PDF to the shipping product image.

    Note that the PDF file simply ships on the product media; it does not have to be installed with the product. An SMS administrator uses the PDF file when preparing the product for installation.

  4. Add a step to your normal development cycle to ensure that Steps 1, 2, and 3 above are followed each time you revise a product or create a new product. This step is important to ensure that new personnel are aware of the requirements.
  5. Update the product testing specifications to ensure that testing checks for the presence of the prodspec.INI and PDF files, and that the contents of these files are correct and consistent. Because the PDF and prodspec.INI files have dependencies on each other, they must be reviewed and tested together for accuracy.
  6. Add a step to your normal testing cycle to ensure that Step 5 is followed each time you revise a product or create a new product. This step is important to ensure that new personnel are aware of the requirements.
  7. Where possible, use SMS to test the product for correct software inventory as developed in the product. Testing should ensure that different versions of the product are inventoried as being unique. SMS reports the package using the Product and Version in the [Package Definition] section of the PDF, so these should be different for each version of the product.


Installing Packages Using SMS Jobs

Installing Packages by Using SMS Jobs

SMS uses jobs to distribute packages to target systems. There are three primary types of jobs for this purpose: Run Command on Workstation jobs, Share Package on Server jobs, and Remove Package From Server jobs.

There are various job options that you can specify, depending on the type of job that you are creating. The main options that affect the distribution of software are the specification of targets, the distribution servers where the package will be made available, and the options for the run phase of the job.

The most useful mechanism for specifying job targets is an SMS database query. You can create a query that allows you to target only those clients or servers that meet the criteria for the particular package that you are going to install. Once you have defined and run the query, the resulting set of clients or servers can be specified as the target of the job.


Run Command on Workstation Jobs

The Run Command on Workstation job is the most common type of job used in SMS. This job is actually run on the target clients in the context of the package share that is associated with the job. It is used to install, remove, and maintain software on target clients.

The following is a sample of a PDF that might be included in a Run Command on Workstation job:

[PDF]
Version=1.2

[Simple Server Install Setup]
CommandLine=instsrv.bat Install
CommandName=Automated installation of the Simple Service
UserInputRequired=FALSE
SynchronousSystemExitRequired=FALSE
SupportedPlatforms=Windows NT (Alpha), Windows NT (MIPS), Windows NT (x86)

[Simple Server Uninstall Setup]
CommandLine=instsrv.bat Remove
CommandName=Automated deinstallation of the Simple Service
UserInputRequired=FALSE
SynchronousSystemExitRequired=FALSE
SupportedPlatforms=Windows NT (Alpha), Windows NT (MIPS), Windows NT (x86)

[Package Definition]
Product=Simple Server
Version=1.0
Comment=Simple Server from the WIN32 samples of VC++ 2.0
SetupVariations=Simple Server Install, Simple Server Uninstall

[Setup Package for Inventory]
InventoryThisPackage=TRUE
Detection Rule Part 1=file 1

[file 1]
FILE=SIMPLE.EXE
COLLECT=FALSE
Checksum=
CRC=
DATE=
SIZE=
TIME=
BYTE=
WORD=
LONG=
TOKEN 1=
TOKEN 2=
TOKEN 3=
TOKEN 4=


Share Package on Server Jobs

The Share Package on Server job is used to install an SMS network application on a set of servers. Unlike the Run Command on Workstation job, the Share Package on Server job does not actually run a command on the distribution servers. It simply copies the files and directory structure in the package directory to the specified servers and makes them available as a share. The access permissions for each package are set in the PDF for that package.

The following is an example of a PDF that might be included in a Share Package on Server job:

[PDF]
Version=1.2

[Package Definition]
Product=My Application
Version=1.0
Comment=Sample package for use with Share Package on Server jobs.

[Setup Package for Sharing]
ShareName=MYAPPSHR
ShareAccess=UserRead, GuestRead

[Program Item Properties 1]
Description=My Application
CommandLine=MYAPP.EXE
ConfigurationScript=
RegistryName=MyApp
DefaultINIFile=MYAPP.INI
RunMinimized=TRUE
RunLocalCopyIfPresent=TRUE
DriveMode=UNC
SupportedPlatforms=Windows
DisplayIconInProgGroup=TRUE
SetupIcon=MYAPP.ICO


Remove Package Jobs

Remove Package From Server Jobs

Remove Package From Server jobs do not remove packages from clients; that is done by using deinstall options with the Run Command on Workstation job. The Remove Package From Server job is used to remove packages from SMS site servers, distribution servers, and servers that have had a package installed using a Share Package on Server job.

There is no specific PDF for this type of job. Any package in SMS can be the basis of a Remove Package From Server job.


SMSVIEW Samples

With the SMSVIEW program, you can create database views on a site database. Using the Microsoft Desktop ODBC Database Driver, you can use these views in other applications (such as Microsoft Word for Windows) to view the computer inventory and generate reports.

SMSVIEW is provided with the Microsoft Systems Management Server product.

The SMS SDK provides samples for viewing, extracting, and using the computer inventory and other information in the site database. Samples are provided for the following applications:

  • Microsoft Word for Windows version 6.0
  • Microsoft Excel version 5.0
  • Microsoft Access version 2.0

The samples are provided on the Microsoft® Platform SDK CD-ROM in the \MSSDK\SAMPLES\SYSMGMT\SMS\SMSVIEW directory.


General Setup for Using the SMSVIEW Samples

Before you can use the samples to access a site database, you must run the SMSVIEW program against that site database. SMSVIEW.EXE is installed in the smsroot\SITE.SRV\platform.BIN directory of every primary site server (where smsroot is the root directory where SMS is installed on the site server, and platform.BIN is the directory for the processor type of the site server—for example, X86.BIN for x86-based processors, ALPHA.BIN for Alpha, and MIPS.BIN for MIPS).

To use the samples, you must have the following items installed on the computer where you will be using the samples:

  • Microsoft Open Database Connectivity (ODBC)
  • ODBC driver for SQL Server. Note that ODBC and the SQL Server driver are provided with Microsoft Office.
  • For Microsoft Word samples, Microsoft Word for Windows version 6.0 or later.
  • For Microsoft Excel samples, Microsoft Excel version 5.0 or later.
  • For Microsoft Access samples, Microsoft Access version 2.0 or later.

After you have installed these items, copy the sample files to your computer and create an ODBC entry for the site database.

To create an ODBC entry for the site database
  1. From the Control Panel, start the ODBC application (for more information about using ODBC, see the ODBC documentation).

    The Data Sources dialog box appears.

  2. Click Add.

    The Add Data Source dialog box appears.

  3. In the Installed ODBC Drivers box, select SQL Server.
  4. Click OK.
  5. In the Data Source Name box, type sms data.

    Optionally, you can add a description.

  6. In the Server box, type the name of the SQL Server that contains the site database.
  7. Click Options.
  8. In the Database Name box, type the name of SMS site database.
  9. Click OK.
  10. Click Close.


Using the Microsoft Word SMSVIEW Sample

The sample document SMSTRAIN.DOC (using the macros in the SMS.DOT template and the ODBC functions in WBODBC.WLL) reads the site database and finds all inventoried software packages. After you select one of these packages, the macro finds all of the computers that have the package installed and generates a letter for the user of each computer informing the user about training information for that package. You can generate these messages to another Word document, to a printer, or to Microsoft® Mail messages.

To set up Microsoft Word for using the sample with Microsoft Mail
  1. Install Microsoft Mail on the computer where you are using the sample document SMSTRAIN.DOC.
  2. Users of SMS computers must complete the UINFO.XNF form that is automatically distributed to SMS client computers.

    When the users complete this form, they report their name, electronic mail, and other information with their computer inventories. The macro used by SMS.DOT uses the information in the electronic-mail attribute to send the messages as mail messages to the users of the package.

To set up the Word sample
  1. Before you run the Word sample, make sure that your site database contains inventory for one or more software packages.
  2. Copy SMS.DOT and WBODBC.WLL from the SDK\TEMPLATE directory on the SMS CD-ROM to the template directory used by Microsoft Word (usually, the template directory is the TEMPLATE subdirectory of the Word root directory).
  3. Copy SMSTRAIN.DOC from the SDK directory on the SMS CD-ROM to the directory on your hard disk where you want to place the sample.
To use the Word sample
  1. Start Microsoft Word.
  2. Open SMSTRAIN.DOC.

    The Connection Information dialog box appears.

  3. In the ODBC Connection Name box, type sms data.
  4. In the SQL Login ID and Password boxes, type the SQL login identifier and password for the SQL Server containing the site database.

    Note that the SQL login identifier must have dbo permission on the site database.

  5. In the Location Of The Word Template Directory box, type the directory containing SMS.DOT and WBODBC.WLL.

    By default, this directory is the template directory used by your Microsoft Word installation.

  6. Click OK.

    The Training Notification dialog box appears.

  7. In the top entry box, type the name that you want to use in the form letters to refer to your training course or the new package.

    This string will be used as the name for the course or package in the form letters.

  8. From the list box, select the software package that you want to use to search for SMS computers.

    The macro will query the site database to get all computers with the software package installed. The macro will search for computers with the Personal Computer architecture with the attribute Software Name equal to the selected package in the Software group (group class MICROSOFT|SOFTWARE|1.0).

  9. From the Notification Method box, select the method to use to notify the computer users of the package.

    If you choose Merge To Document, a Word document will be created for each computer user with the software package.

    If you choose Merge To Mail, a Microsoft Mail message will be created for each computer user with the software package and the messages will be sent to the users.

    If you choose Merge To Printer, the Print dialog box appears. Select the print options you want, and click OK. A letter will be printed for each computer user with the software package.


Using the Microsoft Excel SMSVIEW Sample

This sample spreadsheet has several worksheets that analyze the SMS data. Most of the worksheets use pivot tables to analyze the data. Pivot tables are a multidimensional way to look at data. You can put any of the fields you want to analyze across the rows at the top, or drag them to the side to become the fields down the left side of the table. You can also drag fields to the left corner to become filters. You can change any of this at any time.

You can use Microsoft Excel to do any number of other analytical functions. You can collect cost information (from a MIF file) for example, then use Microsoft Excel to calculate depreciation cost for the PC inventory already in the SMS database by department.

There are worksheets that show software packages, video, BIOS, network cards, jobs, and so on. There are also some charts that show CPU and operating system distributions.

You can also use the Pivot Table Wizard to create your own worksheets, using the view tables created by SMSVIEW.

To set up Microsoft Excel for the Microsoft Excel samples

Make sure you have completed the ODBC setup as described in General Setup for Using the SMSVIEW Samples.

To use the Microsoft Excel sample
  1. Copy SMSSDK.XLS from the SDK directory on the SMS CD-ROM to the directory on your hard disk where you want to place the sample.
  2. Start Microsoft Excel, and open SMSSDK.XLS.
  3. Use the tabs at the bottom of the window to go to the individual worksheets.
  4. Try the pivot tables:
    1. Use the filters by using the list boxes on the spreadsheet.
    2. To see more detail on an item, double-click the cell.
    3. Try moving the fields to organize the data in different ways.
  5. The pivot tables store a local copy of the data. If you want to refresh the data from the site database:
    1. Select the cells where you want to refresh data.
    2. Use the right mouse button to click the selection.
    3. Select Refresh Data.

      A message box tells you that the SQL Server login failed. This occurs because your password is different from the one used to create the pivot table.

    4. Click OK.

      The SQL Data Sources dialog box appears.

    5. From the Select Data Source dialog box, select sms data.
    6. Click OK.

      The SQL Server Login dialog box appears.

    7. In the Login ID box, type a login identifier with access to the site database.
    8. In the Password box, type the password for the login identifier.
    9. Click OK.


Using the Microsoft Access SMSVIEW Samples

This sample Access database uses ODBC to link to the SMS database. The sample provides one form, five queries, and two reports.

The form shows all computers with duplicate TCP/IP addresses.

There are five queries: Duplicate TCP/IP Addresses, Late Scan, ListDup, Low Disk Space, and Network.

The first report shows all computers that have not scanned their hardware or software in the past 10 days. The second report shows all computers that have fixed disks that are over 90 percent full.

You can use Microsoft Access to generate any number of forms or reports to analyze the SMS data. For example, you can create a help desk tracking system using Microsoft Access that ties in to the site database. This can include maintenance history, trouble calls, configuration changes, and so on.

To set up Microsoft Access for the Microsoft Access sample

Make sure you have completed the ODBC setup as described in General Setup for Using the SMSVIEW Samples.

To use the Microsoft Access sample
  1. Start Microsoft Access.
  2. Copy SMSDB.MDB from the SDK directory on the SMS CD-ROM to the directory on your hard disk where you want to place the sample.
  3. Open the SMSDB.MDB database.

    The sample has a main menu form, from which you choose a report or form. You can view the queries (as well as the form and reports) in the database window for SMSDB.

    When you click a button in the main menu form, the SQL Server Login dialog box appears.

  4. In the Login ID and Password boxes, type the SQL login identifier and password for the SQL Server containing the site database.

    Note that the SQL login identifier must have dbo permission on the site database.

  5. In the Database: SMSDB window, you can choose the tab for the type of item you want to use. The sample SMSDB database provides sample forms, queries, and reports. In the tab list, double-click the item you want to use.


How SMSVIEW Works

The SMS system database stores computer inventory in multiple tables in order to store the data efficiently. However, this efficient design can make it difficult to view the computer inventory directly from other applications.

The inventory for each computer is stored in the MachineDataTable. However, the specific inventory data (such as group names, attribute names, and the values for groups and attributes) is stored in other tables. The MachineDataTable has keyed pointers to these other tables. The SMSVIEW program creates views that resolve these keyed pointers so that you can view the computer inventory easily with other applications. For a table of some common views (and their fields) that can be generated by SMSVIEW, see Views Created by SMSVIEW.

SMSVIEW.EXE is used to read the GroupMap table and to create views that make it easier to use the computer inventory data. A view is created for each group. The view for a group joins the group's common table (COMM), the group's specific table (SPEC), and the MachineDataTable.

The views are created using the following naming convention:

v Grouptablename

where

v
Is a literal v.
Grouptablename
Is the group table name without the _COMM or _SPEC suffix.

For example, the view for the Network group with the table names of Network_COMM and Network_SPEC becomes vNetwork.

The views use the MachineDataTable as the driving table and then do outer joins to the COMM and SPEC tables that contain the particular group information (such as network, video, and so on). Outer joins are necessary because some or all group attributes can be in either the SPEC or COMM table. Note that when outer joins are used, you cannot filter on any attribute from the SPEC or COMM tables by using a WHERE clause. When the created view uses an outer join, if you filter out one of the SPEC or COMM entries, the results set will still have a record for the MachineDataTable entry with blank values for the filtered SPEC or COMM entry. If you want to filter on the created views, use the HAVING clause, which works on the results set after the join is completed.


Views Created by SMSVIEW

The following table lists the standard views currently generated by the SMSVIEW.EXE program. For information about the naming conventions for the views, see How SMSVIEW Works.

vPackageLocations | vUserGroups | vJobDetails
vSMSEvent | vIdentification | vWorkstationStatus
vMouse | vVideo | vProcessor
vOperating_System | vDisk | vPC_Memory
vNetwork | vNetcard | vEnvironment
vServices | vSoftware | vSNMP_Traps
vSNMP_Varbinds |  |


Creating a List of SMS Views from the SMS Database

The actual views created in your database may differ from the previous list, depending on the contents of your site database. To see the views that have actually been created in an SMS site database, run the following query:

select * from sysobjects where type = "V"

The SMSVIEW program creates views based on a dynamic table in the SMS database that lists all of the groups and attributes currently in the database. The inventory reported by the Inventory Agent (which runs at each SMS computer and reports the computer's inventory to the site database), and by custom MIF files, determines which groups and attributes are contained in the database. (For more information about extending the SMS inventory with custom MIF files, see Extending the Inventory.)

This means that SMSVIEW may create additional views (or views with additional fields) based on the groups and attributes that have been reported to your particular site database. Or SMSVIEW may create a set of views that does not include the common views or fields listed in the table because inventory information for those groups or attributes has not been reported to your site database.

It is strongly recommended that you run the SMSVIEW program periodically to generate views that reflect the current groups and attributes in the site database. This is particularly important if a new attribute or group has been reported or if a group has been deleted.


Additional Special Views

SMSVIEW creates a view called vGroupNames that lists the SMS group names that have views. However, because the list generated by this view may be inaccurate, you should ignore the contents of vGroupNames and use the query described in the previous section to get the correct listing of group names that have views.

SMSVIEW creates a separate Identification view for each additional machine architecture created in SMS. Each of these additional Identification views will have a number appended to the end of the view name to distinguish it from the others. For example, if the vIdentification view refers to the Personal Computer architecture view, additional machine architecture Identification views will be vIdentification1, vIdentification2, and so on.


Console Application Integration

SMS provides support for launching ISV applications from a Tools menu in the SMS Administrator console in a context-specific manner. (The term context refers to the internal class name of the active SMS multiple document interface (MDI) window.) Launching an application from the SMS Administrator console requires registering information about the application in the Windows NT Registry.

This section provides an overview of the ISV application registration and launch process, a detailed description of the required Registry information, and instructions on using the application registration tool provided by SMS.

Topics in this section are as follows:

Overview of the Application Registration and Launch Process

Windows NT Registry Keys

Supported Context Names

SMS Registered Applications

Using the Application Registration Tool


Overview of the Application Registration and Launch Process

Launching an application from the SMS console requires adding data about the application under the SMS key in the Windows NT Registry. The registered data defines the characteristics of the new application by specifying the command description, command name, command-line parameters, and so on.

SMS supports ISV application launching for several contexts. Applications registered in the General context are always available from the Tools menu, regardless of the current context. Applications registered in a specific context are only available when that context is active (that is, when the MDI window corresponding to that context is active). You can register an application in more than one context.

Context-specific ISV applications store Boolean rules in the Registry that SMS evaluates to determine whether their menu items should be present, and if so, whether they should be enabled or disabled. For example, menu items for SMSMachine-context ISV applications may be disabled if the machine whose Machine Property window is currently active does not meet the criteria specified by the ISV.

Registered applications are displayed in the Tools menu in the SMS Administrator console. When chosen, the Tools menu displays the names of ISV applications that apply to the General context, followed by a separator, then followed by the names of the ISV applications that apply to the current context. If there are no context-specific applications installed, SMS does not display the separator. The menu items are listed in the order indicated by each application's Order Registry value, which SMS determines during initialization.

When the user selects an ISV application from the Tools menu, SMS forms a command line from the application's information in the Windows NT Registry and passes the command line to the underlying operating system for execution. If SMS cannot construct the command line, a message box describing the problem appears and the launch fails. SMS may fail to build a command line if it cannot resolve the environment variable or the SMS database information specified in the Registry by the ISV.

If the application targeted by the command line fails to execute for any reason, SMS displays the error in a message box that contains information that allows the user to determine the cause of the failure.


Windows NT Registry Keys

This section describes the Windows NT Registry keys and values required to register an ISV application, and the behavior of SMS when using that data.

ISV applications are responsible for writing the required Registry keys and values. ISV application Registry sections parsed by SMS as incorrect are ignored and, therefore, no menu item will appear for that ISV application. SMS writes an error value to the Registry to report these errors during application startup as an aid to ISV debugging.

SMS provides a command-line utility, SMSADDIN.EXE, that creates or removes the Registry settings for an ISV application based on command-line arguments and a data file. This utility can be used by the ISV application's setup application. See Using the Application Registration Tool.

The Windows NT Registry keys required for ISV application launching are as follows:

SMS Applications Key

Vendor Keys

Application Keys

Context Keys


SMS Applications Key

SMS provides and checks the SOFTWARE\Microsoft\SMS\Applications key under HKEY_CURRENT_USER in the Registry for ISV application launching. SMS also provides and checks the same key under HKEY_LOCAL_MACHINE, which contains a single value, Version, that allows SMS to handle Registry changes.

Applications registered under HKEY_LOCAL_MACHINE are available to all SMS users; applications registered under HKEY_CURRENT_USER are available only to the user who registered the application.

Note Administrator access is required to modify keys under HKEY_LOCAL_MACHINE.


Vendor Keys

ISVs will create vendor keys under the Applications key. The name of a vendor key is the full name of the vendor. The vendor name may be displayed in future versions of SMS and should therefore be chosen carefully to publicly represent the vendor. Currently, there are no values defined for this key.


Application Keys

There is one application key for each ISV application under the vendor key. Each application key corresponds to a Tools menu item. The key names are supplied by the vendor and are ordered alphabetically in the Registry. The key names are not displayed in SMS, but are used to uniquely identify each application.

The application key can contain the following values:

ApplicationName (mandatory)

Description

Command (mandatory)

WorkingDirectory

RunWindow

Order


ApplicationName (mandatory)

Type

REG_SZ

Description

The full name of the application. SMS displays this value in the Tools menu verbatim, including capitalization.


Description

Type

REG_SZ

Description

A short string that describes the application. This string appears in the status bar when the Tools menu item is selected. The value will not be interpreted by SMS in any way.


Command (mandatory)

Type

REG_EXPAND_SZ

Description

Specifies the name of the executable file launched when the application is selected from the Tools menu. If you do not specify a path, SMS performs a standard %Path% environment variable search using CreateProcess.

Environment strings of the form %<variable>% will be expanded before the executable path is used to launch the application.


WorkingDirectory

Type

REG_EXPAND_SZ

Description

Specifies the directory from which the application will start.

Environment strings of the form %<variable>% will be expanded before SMS changes to that directory immediately before launching the application. SMS changes back to its current working directory after launching the application.

If this value is missing or is an empty string, the default is the same directory as the application itself.


RunWindow

Type

REG_SZ

Description

Specifies the state of the launched application. This value can be Normal, Minimized, or Maximized.

Note that the application must support minimization or maximization if you choose these modes for launching. If the application does not support the selected mode, the following may result:

  • If the application does not have a fixed-size window frame, the result of a forced minimization after the application launch is an icon that cannot be remaximized.
  • If the application has a fixed-size window frame, the result of a forced minimization after the application launch is a normal-sized window frame.


Order

Type

REG_DWORD

Description

Specifies the order in which the application appears in the Tools menu. Ties are resolved alphabetically. SMS resolves the order every time it processes the Registry. Resolved order is always written back.


Context Keys

Each application key must contain at least one context key. General context applications are always available on the Tools menu regardless of the current context. Limited context applications are restricted to a particular context. If the General context key is specified for an application, all other context keys that may be listed for the application are ignored. If no context keys are found for an application, then the application's menu item will not appear under any context.

Each context key contains three additional values that pertain to the application:

PresentRule

EnableRule

Arguments


PresentRule

Type

REG_MULTI_SZ

Description

An expression that evaluates to TRUE or FALSE. When the expression evaluates to FALSE, the application does not appear on the Tools menu. SMS writes an error value to the application key as an aid to ISV debugging. If no expression is specified here, PresentRule defaults to TRUE.

This value is examined only under a specified context key when the current context matches that context key.

PresentRule is REG_MULTI_SZ for readability when using regedt32 to view Registry settings. SMS treats nulls as white space when parsing this value.

Expression Syntax

The syntax of the expression is fixed to the following grammar:

Rule: Term
Rule: Term AND|OR Rule
Term: NOT Term
Term: TRUE|FALSE
Term: Test
Term: (Rule)
Test: $(Function) [NoCase] ==|!=|<|>|<=|>= '<text>'
PresentRule: Rule

SMS replaces the Function substring with data retrieved from the active MDI window when the application is launched. The argument is processed by the MDI window and is therefore context-sensitive.

Functions Supported in SMS 1.2

Attr(<Class>:<Attribute>)

Searches the SMS database for the given key. Valid only in the SMSMachine context. If this argument cannot be resolved, SMS writes an error value into the Registry application key as an aid to ISV debugging.

Example:

$(Attr(MICROSOFT|OPERATING_SYSTEM|1.0:Operating System Name)) ==
'Microsoft Windows NT'

Column(<name>)

Returns the string from the named column for the item with the caret (selection point) in the table of the active window.

Example:

$(Column(SystemRole)) == 'Server'
OR
$(Column(SystemRole)) == 'Workstation'

Note that the AND operator in these expressions has a higher precedence than OR.


EnableRule

Type

REG_MULTI_SZ

Description

An expression that evaluates to TRUE or FALSE. When the expression evaluates to FALSE, the application is present but disabled on the Tools menu. SMS writes an error value to the application key as an aid to ISV debugging. If no expression is specified here, EnableRule defaults to TRUE. The syntax and use of the expression are the same as for PresentRule.

This value is examined only under a specified context key when the current context matches that context key.

EnableRule is REG_MULTI_SZ for readability when using regedt32 to view Registry settings. SMS treats nulls as white space when parsing this value.


Arguments

Type

REG_MULTI_SZ

Description

Contains a list of strings corresponding to the parameters passed on the command line given by the Command value. This value is optional.

The strings are placed on the command line, separated by a single space, in the implicit order of the REG_MULTI_SZ list. Separate arguments must appear on different lines in the REG_MULTI_SZ string. Quotation marks are placed around each argument to enforce this requirement.

Each string in this list is regarded as being of type REG_EXPAND_SZ to allow for expansion of environment variables of the form %<variable>%. SMS must expand any environment strings given in the parameter list.

Strings in the list with literal form are passed verbatim to the command line. $(Function) substrings are replaced with data retrieved from the active MDI window when the application is launched. $(Attr) substrings are replaced with data from the SMS database for the selected machine.

The following code examples show Arguments values. The context in these examples is an SMSMachine window focused on a machine named NAUTICA.

This example returns "/c NAUTICA":

/c $(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

This example returns "\\NAUTICA":

\\$(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

After environment variable expansion and SMS attribute processing, strings that have embedded spaces will be bracketed in double quotes ("") before being placed on the command line. If SMS cannot obtain an attribute, this is considered a launch error and SMS displays a message box describing the problem. Note that the error value is not used here because the failure can be noticed by the user and must be reported interactively.


Supported Context Names

As stated previously, the context that applies to each of the ISV applications is the internal class name of the active SMS MDI window. The currently supported contexts are listed below:

Context | Description
General | Any child window or none at all
SMSMachine | Machine Properties window
SMSSites | Sites window
SMSSiteGroups | Site Groups window
SMSMachineGroups | Machine Groups window
SMSQueryResults | Query Results window
SMSPackages | Packages window
SMSJobs | Jobs window
SMSQueries | Queries window
SMSAlerts | Alerts window
SMSTrapWnd | SNMP Traps window
SMSArchWnd | Events window
SMSProgramGroups | Program Groups window


SMS Registered Applications

By default, the Tools menu in SMS 1.2 contains the applications shown in this section. The lists in the following topics include supported launch contexts, present and enable rules, and command-line arguments for each application.

The registered applications are:

General Context Applications

Context-Specific Applications


General Context Applications

SecurityManager

ServiceManager

DBClean

SenderManager


SecurityManager

ApplicationName
"SMS Security Manager"
Order
1
Command
SECURE.EXE
Description
"Manages user access to the SMS database."


ServiceManager

ApplicationName
"SMS Service Manager"
Order
2
Command
SMSVCMGR.EXE
Description
"Manages SMS services and components."


DBClean

ApplicationName
"SMS Database Maintenance Utility"
Order
3
Command
DBCLEAN.EXE
Description
"Performs useful cleanup tasks on the SMS database."


SenderManager

ApplicationName
"SMS Sender Manager"
Order
4
Command
SNDRMGR.EXE
Description
"Controls the bandwidth available to SMS senders."


Context-Specific Applications

Eventviewer

ServerManager

UserManager

PerformanceMonitor

SNMPEventTrapTranslator


EventViewer

ApplicationName
"Event Viewer"
Order
1
Command
EVENTVWR.EXE
Description
"Views the NT event logs for the selected computer."
Supported Contexts:
SMSMachine
EnableRule:

$(Attr(MICROSOFT|OPERATING_SYSTEM|1.0:Operating System Name)) == 'Microsoft Windows NT'

Arguments:

$(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

SMSSites
Arguments:

$(Column(Name))

SMSQueryResults
Arguments:

$(Column(Name))

SMSMachineGroups
EnableRule:

$(Column(SystemRole)) == 'Server'

OR

$(Column(SystemRole)) == 'Workstation'

Arguments:

$(Column(Name))


ServerManager

ApplicationName
"Server Manager"
Order
2
Command
SRVMGR.EXE
Description
"Manages domains, workgroups, and computers."
Supported Contexts:
SMSMachine
EnableRule:

$(Attr(MICROSOFT|OPERATING_SYSTEM|1.0:Operating System Name)) == 'Microsoft Windows NT'

Arguments:

$(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

SMSSites
Arguments:

$(Column(Name))

SMSQueryResults
Arguments:

$(Column(Name))

SMSMachineGroups
EnableRule:

$(Column(SystemRole)) == 'Server'

OR

$(Column(SystemRole)) == 'Workstation'

Arguments:

$(Column(Name))


UserManager

UserManagerApplicationName
"User Manager"
Order
3
Command
USRMGR.EXE
Description
"Manages user accounts on the selected computer."
Supported Contexts:
SMSMachine
EnableRule:

$(Attr(MICROSOFT|OPERATING_SYSTEM|1.0:Operating System Name)) == 'Microsoft Windows NT'

Arguments:

$(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

SMSSites
Arguments:

$(Column(Name))

SMSQueryResults
Arguments:

$(Column(Name))

SMSMachineGroups
EnableRule:

$(Column(SystemRole)) == 'Server'

OR

$(Column(SystemRole)) == 'Workstation'

Arguments:

$(Column(Name))


PerformanceMonitor

ApplicationName
"Performance Monitor"
Order
4
Command
PERFMON.EXE
Description
"Monitors the resources of the selected computer."
Supported Contexts:
SMSMachine
EnableRule:

$(Attr(MICROSOFT|OPERATING_SYSTEM|1.0:Operating System Name)) == 'Microsoft Windows NT'

Arguments (2):

/c

$(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

SMSSites
Arguments (2):

/c

$(Column(Name))

SMSQueryResults
Arguments (2):

/c

$(Column(Name))

SMSMachineGroups
EnableRule:

$(Column(SystemRole)) == 'Server'

OR

$(Column(SystemRole)) == 'Workstation'

Arguments (2):

/c

$(Column(Name))


SNMPEventTrapTranslator

ApplicationName
"Event/Trap Translator"
Order
5
Command
EVENTRAP.EXE
Description
"Manages translation of NT events to SNMP traps."
Supported Contexts:
SMSMachine
EnableRule:

$(Attr(MICROSOFT|OPERATING_SYSTEM|1.0:Operating System Name)) == 'Microsoft Windows NT'

Arguments:

$(Attr(MICROSOFT|IDENTIFICATION|1.0:Name))

SMSSites
Arguments:

$(Column(Name))

SMSQueryResults
Arguments:

$(Column(Name))

SMSMachineGroups
EnableRule:

$(Column(SystemRole)) == 'Server'

OR

$(Column(SystemRole)) == 'Workstation'

Arguments:

$(Column(Name))


Using the Application Registration Tool

To assist ISVs with integrating their applications into the Registry and creating the structure described previously, SMS provides the SMSADDIN.EXE tool. SMSADDIN.EXE is a Windows-based executable file that you use in two ways to register applications:

  • Interactively, to create and test Add-in Tool Definition (ATD) files, which are ASCII text files containing the Registry data for the application.
  • As part of the application's setup program, to register the application for launching from the SMS Administrator console.

For more information, see:

SMSADDIN.EXE Command Options

ATD Files

Using SMSADDIN.EXE Interactively

Modifying the Application's Setup Program


SMSADDIN.EXE Command Options

SMSADDIN.EXE supports three command-line options, which appear before the path of the input file:

/v - verbose mode
Runs SMSADDIN.EXE interactively. This option displays the SMS Add-in Tool Registration window that you can use to view and change the required Registry information. ISVs should use this mode during development to create and test ATD files. This mode should not be used in a customer application setup scenario.

If no command-line arguments are specified, verbose mode is the default.

/u - unattended mode
Runs SMSADDIN.EXE silently, even when the input file contains invalid data. When using this option, you must specify the ATD file that contains the Registry information for the application. This option cannot be used with /v. Use this option in your setup program for unattended installation (or deinstallation) and registration.
/r - remove the Registry structure
By default, SMSADDIN.EXE adds data to the Registry. Use this option together with the /u option to remove an application's Registry structure in an unattended way. The vendor key will be deleted if there are no other ISV applications registered underneath it.


ATD Files

The ATD file format follows the standard .INI file rules with keys and values organized into sections.

A sample ATD file is shown below. The [Values] section contains all of the REG_SZ keys and values. The context-specific section contains the REG_MULTI_SZ keys. REG_MULTI_SZ keys are divided into multiple keys named using the line number as the last character of the key, starting with 1. Multiple contexts can appear in any order.

The following sample file has a specific context (SMSMachine) and a 3-line Arguments key:

[Values]
Hive=HKEY_CURRENT_USER
VendorKey=ThirdParty
ApplicationKey=mv
ApplicationName=Machine Viewer
Description=Looks at a given machine
Command=machview.exe
WorkingDir=c:\machview
RunWindow=Normal
Order=0
[SMSMachine]
PresentRule1=
EnableRule1=
Arguments1=/r
Arguments2=/showram
Arguments3=/exityes


Using SMSADDIN.EXE Interactively

ISVs should use SMSADDIN.EXE interactively to create ATD files and test Registry settings. The following topics describe procedures.

Creating ATD Files

Testing Registry Settings

Updating Existing ATD Files

Removing an Application


Creating ATD Files

To create an ATD file
  1. Run the SMSADDIN.EXE tool.

    The SMS Add-In Tool Registration window appears as shown below. This window's toolbar has standard New, Open, and Save buttons, as well as Register (check mark) and Unregister (X mark) buttons. These options are also available from the File menu.

    1. Complete the fields listed below. Click the field name for additional details.

    Note If mandatory values are missing or invalid, the application key is ignored and the application will not appear in the Tools menu. SMS writes an error value into the application key as an aid to ISV debugging.

    Name
    Type the full name of the application.
    Description
    Type a short description of the application.
    Command
    Type the name of the executable file launched when the application is selected from the Tools menu.
    Working Directory
    Type the directory from which the application will start.
    Run
    Select one of: Normal, Minimized, or Maximized. Make sure the application supports the selected mode.
    Preferred position in tool list
    Select the position number from the list. This value determines the order in which the application appears on the Tools menu.
    Register for
    Select one of:

    Current User, which restricts the availability of the application to the user who registered the application.

    Local Machine, which makes the application available to all users. Note that you must have administrator privileges to register an application for Local Machine.

    Vendor Registry Key
    Type the full name of the vendor of the application.
    Application Registry Key
    Type a unique name for the application key.
    Tool availability
    Select one of:

    Always available (General Context)

    Only when checked window types are active (Limited Contexts)

    If you choose this option, you must also select the contexts from the list box. Click in the appropriate check box to select a context. See Supported Context Names for a list of the available contexts.

    Note The following fields apply to the selected context. Reselecting a context will display the information previously entered for these fields.

    Display tool in tool list if (Present Rule)
    Type an expression that evaluates to TRUE or FALSE. When the expression evaluates to FALSE, the application does not appear on the Tools menu.
    Enable tool if (Enable Rule)
    Type an expression that evaluates to TRUE or FALSE. When the expression evaluates to FALSE, the application is present but disabled on the Tools menu.
    Command line arguments
    Type the arguments to be passed on the command line when the application is launched. Type each argument on a separate line in the order in which they are to be passed. Strings are passed verbatim to the command line.
  3. Choose the Register button (check mark) on the toolbar.

    The data entered in step 2 is written into the Windows NT Registry. If the registration fails, a message box appears explaining the failure.

  4. Save the Registry data. Click the Save button on the toolbar and type the name for the file in the dialog box that appears. The file is saved with an .ATD extension.
  5. If you want to register the application for another context, select the new context from the list box under Tool availability. Change the Present Rule, Enable Rule, and Command line arguments entries, if necessary. Then click the Register button on the toolbar to write the data to the Registry. You must also save this data in a new .ATD file.


Testing Registry Settings

To test Registry settings
  1. Restart the SMS Administrator console. Then open the window in which you want to work and display the Tools menu.

    Depending on the PresentRule and EnableRule settings, applications defined in the General Context will appear in the Tools menu above the separator line; applications defined in a specific context will appear below the separator line when the MDI window corresponding to that context is active.

  2. Choose the application you want to launch.

    SMS forms a command line from the application's Registry information and passes the command to the underlying operating system for execution. If SMS cannot form the command line, the launch fails and a message box appears describing the problem.

    If an application fails to execute for any reason, a message box appears with information that allows you to determine the cause of the failure.


Updating Existing ATD Files

To update an existing ATD file
  1. Run SMSADDIN.EXE.
  2. Click the Open button on the toolbar and type the name of the ATD file to be modified in the dialog box that appears.
  3. Change the settings in the SMS Add-In Registration window as desired. Then choose the Register button (check mark) on the toolbar.
  4. Click the Save button on the toolbar to save the new settings in the ATD file.
  5. To make the change effective, you must restart the SMS Administrator console.


Removing an Application

To remove an application
  1. Run SMSADDIN.EXE.
  2. Open the appropriate ATD file.
  3. Click the Unregister button (X mark) on the toolbar. This removes all references to the application in the Tools menu for all contexts.
  4. To make the change effective, you must restart the SMS Administrator console.


Modifying the Application's Setup Program

After you have created the application's ATD file(s), you must modify the setup program to run SMSADDIN.EXE.

To modify the setup program
  1. Near the end of the setup program, add the command line to run SMSADDIN.EXE, specifying the /u option (unattended mode) and the application's ATD file. For example:
    smsaddin /u newapp.atd

    If you are registering an application in more than one context, the setup program must include a separate SMSADDIN.EXE command line for each ATD file.

    For deinstallations, specify the /u and /r options as well as the ATD file. This removes the application in unattended mode.

  2. Make sure your application includes SMSADDIN.EXE plus all required ATD files.

When run during setup, SMSADDIN.EXE checks the syntax of the input file and writes the Registry silently. If the data in the file is invalid, SMSADDIN.EXE displays a message box explaining the failed Registry update.


Sample Code to Register Applications

The SAMPLES\SMS\SMSAPI directory contains sample code that adds or deletes applications the same way as SMSADDIN.EXE. ISVs can build this code into their setup application as an alternative to running SMSADDIN.EXE from the setup program.

The sample code is contained in two files: ISVREG.C and ISVREG.H. The code includes routines that add or delete an application, plus functions that support these routines. The input structures for these routines contain all of the strings and values required to register an application. (These strings and values correspond to the input fields in the SMS Add-in Tool Registration window that appears when SMSADDIN.EXE is run interactively.) The code can also register an application in multiple contexts.

For additional information, see the sample files ISVREG.C and ISVREG.H.


Overriding and Extending Graphics in the SMS Administrator

The SMS Administrator displays a wide variety of graphics to assist the user in identifying objects in a list and in differentiating between various properties. These graphics can be extended or overridden using resource-only dynamic-link libraries.

Specifically, when the SMS Administrator displays an object of a particular architecture (such as a computer with the Personal Computer architecture) within a window, it displays identifying graphics for that object and architecture.

In addition, the detailed properties of an object can be viewed by using a machine properties window. To view the attributes by group, the user selects the group to view in the Properties pane. The attributes for the group are then displayed in the right pane. Each group has a graphic that represents that particular group within that particular architecture.

Using resource-only DLLs and the Windows NT Registry, you can override the graphics of existing architectures, objects, and groups.

In addition, you can provide graphics for new architectures, objects, and groups that have been added to the SMS inventory by using custom MIF files. Note that when new architectures, new types of objects, or new properties are added to the SMS inventory, the SMS Administrator uses the default graphic to display these items if no resource-only DLL is supplied.

For more information about adding new architectures, objects, and groups by using MIF files, see Extending the Inventory.


Graphics for Inventoried Objects in the SMS Administrator

Specifically, when the SMS Administrator displays an object of a particular architecture (such as a computer with the Personal Computer architecture) within a window, it displays identifying graphics for that object and architecture. Inventoried objects can be displayed within the Sites, Machine Groups, and Query Result windows.

In addition, the detailed properties of an object can be viewed by using a machine properties window. In the SMS Administrator, the user can view the properties of an inventoried object by selecting the object in a Sites, Machine Groups, or Query Result window and choosing Properties from the File menu. The properties of the object are displayed in a machine properties window. (Note that the title bar of the machine properties window contains the name of the object's architecture.) The properties are represented as attributes that have a name and a value. Related attributes are grouped together into groups. The user can view the attributes by group by selecting the group to view in the Properties pane—the attributes for the group are then displayed in the right pane. Each group has a graphic that represents that particular group within that particular architecture.

For example, a computer object in an SMS site database is displayed according to its architecture, system type, and role. A computer with a Personal Computer architecture, Macintosh system type, and Workstation role would be displayed in the Sites window using the graphic for that particular architecture, system type, and role. The same graphic would also be displayed if the Macintosh workstation were displayed in a Query Result window.

The properties of a Macintosh computer would be displayed in a Personal Computer Properties window. The Identification group would be represented in the Properties pane by the graphic for that particular group in that particular architecture.

When new architectures, new types of objects, or new properties are added to the SMS inventory, the SMS Administrator uses the default graphic to display these items if no resource-only DLL is supplied.

For example, the sample MIF file for a printer object with the Printer architecture is represented by the default icon when it is displayed in the Sites window if no resource-only DLL is provided.

In addition, the groups for a custom Printer object are represented in a Printer Properties window by the default graphic if no resource-only DLL is provided.


How the SMS Administrator Uses Resource DLLs to Display Graphics

When the SMS Administrator needs to display an object or group, it searches for the graphics to use for the display of that architecture, object, or group in the set of DLLs specified in the Windows NT Registry. When displaying a specific object or group, the SMS Administrator searches for a resource with a name corresponding to the object's architecture, type, and/or group. For the naming conventions used for the resources for graphics, see Architecture Bitmaps and Machine Properties Icons.

The set of DLLs can be specified by using the following registry keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\SMS\ResDLLs

HKEY_CURRENT_USER\Software\Microsoft\SMS\ResDLLs

Within the ResDLLs key, there is an Installed value that lists the subkey that represents each DLL in the list. For example, if the Installed value contained DLLName1 DLLName2, two DLLs are specified and the path to those DLLs is specified by the DLLName1 and DLLName2 subkeys. Beneath the ResDLLs key, there are subkeys for each DLL specified in the Installed value. Each of those subkeys contains a PathName value. The PathName value contains the actual path and file name of the DLL.

When the SMS Administrator searches for display graphics in the resource-only DLLs, it searches the DLLs in the following order:

  1. DLLs listed in HKEY_LOCAL_MACHINE. The SMS Administrator uses the reverse of the order listed in the Installed value to search the DLLs.
  2. DLLs listed in HKEY_CURRENT_USER. The SMS Administrator uses the reverse of the order listed in the Installed value to search the DLLs.
  3. SMS Administrator's own application resources. Note that some architectures, objects, and groups (such as the Personal Computer architecture, Macintosh workstation computers, and the Processor and Disk groups) have graphics predefined in the SMS Administrator's resources. However, these graphics can be overriden by a resource-only DLL.

Because the graphic for an item may have more than one available format, the SMS Administrator may search the list of resources several times. For the naming conventions used for the resources for graphics, see Architecture Bitmaps and Machine Properties Icons.

For example, if the SMS Administrator needed to display a Macintosh workstation, it would first search for a graphic for the specific architecture, system type, and role in all resources. In this case, the resource name would be Personal_Computer_Macintosh_Workstation. If the resource with this name is found, it uses that graphic. If no resource with this name is found, it searches for the graphic for the architecure and role. In this case, the resource name would be Personal_Computer_Workstation. If no resource matching this name is found, it searches for the graphic for the architecture. In this case, the resource name would be Personal_Computer_None. If no resource matching this name is found, the default graphic is displayed.


Creating Resource DLLs for Custom Graphics

Using resource-only DLLs, you can control the graphics displayed by the SMS Administrator for architectures and objects within the Sites, Machine Groups, and Query Results windows. You can also control the graphics for the properties within machine properties windows.

There are two types of graphics:

Architecture Bitmaps

Machine Properties Icons

For a sample of a resource DLL, see Sample Resource DLL.


Architecture Bitmaps

For each object of each architecture, the SMS Administrator displays a 16-by-16-pixel bitmap that represents that specific object within that specific architecture. These architecture bitmaps are displayed in the Sites, Machine Groups, and Query Results windows.

Using a resource-only DLL, you can override the graphics for existing architectures and objects or add graphics for new types of architectures or objects. If a new architecture or new type of object is added to the SMS inventory and no resource-only DLL is provided, the default graphic is displayed.

To override or add an architecture bitmap for an object
  1. Create a 16-by-16-pixel bitmap for the object.
  2. In the resource script for the DLL, add the bitmap by using the following formats:

    architecture_SystemType_SystemRole

    –or–

    architecture_SystemRole

    where architecture is the name of the object's architecture, SystemType is the value for the SystemType attribute in the Identification group, and SystemRole is the value for the SystemRole attribute in the Identification group.

    Important In an architecture, SystemType, or SystemRole name, you must replace any spaces with an underscore character. For example, the Personal Computer architecture should be specified as Personal_Computer.

    The SMS Administrator will search first for a bitmap named according to format 1. If a bitmap resource of this name cannot be found in any of the registered resource-only DLLs, the SMS Administrator searches for a bitmap named according to format 2. If this bitmap resource cannot be found, the default bitmap is displayed.

For example, a Macintosh workstation has an architecture Personal Computer, SystemType Macintosh, and SystemRole Workstation. You could create a bitmap named MAC.BMP and use it as the graphic for a Macintosh workstation by adding the following line to your resource script:

Personal_Computer_Macintosh_Workstation  BITMAP  mac.bmp

You can also specify a mask bitmap for an architecture bitmap. A mask bitmap explicitly specifies the pixels to display with the highlight color (if the object is selected) or the background window color (if the object is not selected). The mask bitmap is white where you want the highlight color or background window color to show through the bitmap, and black where you want the bitmap to show. If you do not provide a mask, the system will generate one.

For the previous example, you could create a mask bitmap called MACMASK.BMP and use it as the mask when the object is selected:

Personal_Computer_Macintosh_Workstationmask  BITMAP  macmask.bmp


Machine Property Icons

Machine property windows are used to display the properties of an inventoried object. The properties are organized into groups, and the groups contain attributes. The user can view the attributes by group by selecting the group to view in the Properties pane—the attributes for the group are then displayed in the right pane. Each group has a graphic that represents that particular group within that particular architecture.

Using a resource-only DLL, you can override the graphics for existing groups or add graphics for new types of groups. If a new group is added to the SMS inventory and no resource-only DLL is provided, the default graphic is displayed.

To override or add a group icon
  1. Create an icon for the group.
  2. In the resource script for the DLL, add the bitmap by using the following formats:
    PDG_SystemType_GroupName
    Use the icon of the group for the specific system type.
    PDG_architecture_GroupName
    Use the icon of the group for the specific architecture.
    PDG_Std_GroupName
    Use the general icon for the group.

    where architecture is the name of the object's architecture, SystemType is the value for the SystemType attribute in the Identification group, and GroupName is the name of the group in the Property Display table.

    Important In an architecture, SystemType, or GroupName name, you must replace any spaces with an underscore character. For example, the Personal Computer architecture should be specified as Personal_Computer.

    The SMS Administrator will search first for a bitmap named according to format 1. If a bitmap resource of this name cannot be found in any of the registered resource-only DLLs, the SMS Administrator searches for a bitmap named according to format 2. If no bitmap using format 2 is found, it searches for a bitmap using format 3. If this bitmap resource cannot be found, the default bitmap is displayed.

    Note that the SMS Administrator attempts to load an icon by starting from a very specific format and ending with the broadest format.

For example, the SMS Administrator application resource contains the following icon resource for the Keyboard property group:

PDG_Std_Keyboard  ICON  keyboard.ico

If you wanted objects of the Personal Computer architecture to have a different keyboard icon, you could provide the following icon resource:

PDG_Personal_Computer_Keyboard  ICON  pckybrd.ico

Furthermore, if you wanted all Personal Computer objects (except for members of the Macintosh SystemType) to have the same icon, you could also provide the following icon resource:

PDG_Macintosh_Keyboard  ICON  mackybrd.ico


Installing Resource DLLs for the SMS Administrator

To enable the SMS Administrator to use the graphics in a resource-only DLL, you must install the DLL and add keys to the Windows NT Registry of the computer where the SMS Administrator is installed.

To install resource-only DLLs for the SMS Administrator
  1. Install the resource-only DLLs in a directory that is in the path of the computer where the SMS Administrator is installed.
  2. Add keys that specify the DLLs to the Windows NT Registry of the computer where the SMS Administrator is installed.
  3. If the SMS Administrator is running, exit and restart it.

These steps are described in detail in the following paragraphs.

Install the resource-only DLLs in a directory

Install the resource-only DLLs in a directory that is in the path of the computer where the SMS Administrator is installed. Optionally, you can place the DLLs in their own directory and specify a fully qualified path when you configure the Windows NT Registry to complete the installation of the DLL.

Caution Do not install your resource-only DLLs in a purgeable SMS directory.

When the SMS setup program is used to upgrade site components, the SMS setup program removes all files from the SMS directories marked with the SM_DIRECTORY_PURGEABLE flag in the SYSTEM.MAP file. Those files are then replaced with files copied from the SMS CD-ROM by SMS Setup. The following directories are purgeable SMS directories:

  • sms_install_drive:\smsroot\SITE.SRV\platform.BIN
  • sms_install_drive:\smsroot\SITE.SRV\CLIENT.SRC
  • sms_install_drive:\smsroot\SITE.SRV\MAINCFG.BOX\CLIENT.SRC\platform.BIN

where sms_install_drive is the drive where SMS is installed, smsroot is the name of the directory where the SMS installation directory resides, and platform.BIN is the processor type of the computer—X86.BIN, ALPHA.BIN, or MIPS.BIN.

Note that you can create subdirectories within purgeable directories. These subdirectories and their contents will not be removed on an upgrade. However, if SMS is removed from the computer the entire SMS root directory is removed.

Add keys to specify the DLLs to the Windows NT Registry

The set of DLLs can be specified by using the following registry keys:

HKEY_CURRENT_USER\Software\Microsoft\SMS\ResDLLs
Specifies the resource-only DLLs to be used only by the current user. The SMS Administrator searches for a resource in the list of DLLs in this key first.
HKEY_LOCAL_MACHINE\Software\Microsoft\SMS\ResDLLs
Specifies the resource-only DLLs to be used by any user on that computer. If the resource is not found in the DLLs in HKEY_CURRENT_USER, the SMS Administrator then searches for a resource in the list of DLLs in this key.

When the SMS Administrator searches for display graphics in the resource-only DLLs, it searches the DLLs in the following order:

  1. DLLs listed in HKEY_CURRENT_USER. The SMS Administrator uses the reverse of the order listed in the Installed value to search the DLLs.
  2. DLLs listed in HKEY_LOCAL_MACHINE. The SMS Administrator uses the reverse of the order listed in the Installed value to search the DLLs.
  3. SMS Administrator's own application resources. Note that some architectures, objects, and groups (such as the Personal Computer architecture, Macintosh workstation computers, and the Processor and Disk groups) have graphics predefined in the SMS Administrator's resources. However, these graphics can be overriden by a resource-only DLL.
To add a DLL to the list of DLLs to be searched
  1. Add a ResDLLs key beneath one of the following keys (if the key does not already exist):

    HKEY_LOCAL_MACHINE\Software\Microsoft\SMS

    HKEY_CURRENT_USER\Software\Microsoft\SMS

    Use HKEY_LOCAL_MACHINE if you want the DLL available to all users of the computer. Use HKEY_CURRENT_USER if you want the DLL available to only the current user.

  2. In the ResDLLs key, add a value called Installed with a type of REG_MULTI_SZ (if the key does not already exist).
  3. In the Installed value, add the name of key for the new DLL you want to add, such as DLLName1.
  4. Add the key for the new DLL beneath the ResDLLs key. For example, if you specified the name of the key to be DLLName1 in the Installed value, you must create a key named DLLName1 beneath the ResDLLs key.
  5. In the key for the new DLL, add a value with the name PathName, a type of REG_SZ, and a value that specifies the path and file name. For the value, you can specify only the file name or a fully qualified path.

Exit and restart the SMS Administrator

If the SMS Administrator is running, exit and restart it.

This is a sample registry configuration:

HKEY_CURRENT_USER
    Software
        Microsoft
            SMS
                ResDLLs
                    Installed   REG_MULTI_SZ    DLLName1
                                                DLLName2
                                                DLLName3
                    DLLName1    PathName    REG_SZ    myres.dll
                    DLLName2    PathName    REG_SZ    myicons.dll
                    DLLName3    PathName    REG_SZ    oemicons.dll

In the preceding example, the SMS Administrator would search for a named graphic in the following order: OEMICONS.DLL, MYICONS.DLL, MYRES.DLL, and finally the SMS application resource.


Sample Resource DLL for Extending SMS Administrator Graphics

The SMS SDK provides a sample resource DLL, and source code for the DLL, in the \MSSDK\SAMPLES\SYSMGMT\SMS\SMSAPI\RESDLL directory of the Microsoft® Platform SDK CD-ROM.


Writing a Protocol Parser DLL for Network Monitor

This section describes how to create a custom protocol parser dynamic-link library (DLL) for Network Monitor. It assumes that you are familiar with the protocol you want to parse and know which protocols precede and follow it. Before you begin writing a parser, you should read all the following topics in order to understand the data structures and methods used in parsing a protocol.

The source code for a sample parser is included in the \MSSDK\SAMPLES\SYSMGMT\SMS\NETMON subdirectory of the Microsoft® Platform SDK CD-ROM.

Overview

Parser Entry Points

Recognize Frame

Steps for Creating a Sample Parser DLL

Entry Point Functions for Protocol Parser DLLs

Functions Called by Parser DLLs

Structures (Network Monitor)

Example Data Type Handling and General Discussion

Sample Parser

The Generic Formatter

MIPS

Sample Applications for Network Monitor


Overview

Network Monitor displays protocol information for network administrators to use when viewing network traffic and troubleshooting problems. By writing custom protocol parsers, you can extend the set of protocols for which information is displayed in Network Monitor.

Protocol parsers read through raw network frames (packets of network data), locating specific protocol headers within the data stream, attaching descriptions (properties) to each field of the headers, and identifying those properties to the Network Monitor kernel. Network Monitor then displays the captured data and the properties attached by the parser, to help the network administrator understand the data. For example, when a parser programmed to identify the SMB protocol identifies an SMB header, it attaches the command field property to the fifth byte relative to the start of the SMB header. When Network Monitor displays this field, it displays not only the name of the command (SMB Command), but also the decoded value; for example, 0x2d is always displayed as SMBOpenX.

Note Parsers make no decisions about whether frames are displayed; they simply recognize certain fields and alert the Network Monitor kernel. Filtering is done at a higher level, which allows filter queries to span parsers and greatly simplifies parser writing.

Note that you must not use any threads, or APIs that will not run on Win32s®, in your parser.

Before attaching properties to the raw data, a parser must first register all possible properties with the Network Monitor kernel. The parser tells the kernel to create a property database, and then fills the property database with all of the possible properties for its protocol. Each property in the property database contains information such as a textual description, a data type and qualifier (used to format the raw data), and a formatting routine for displaying the data.


Parser Entry Points

Every parser has five entry points: Register, Deregister, RecognizeFrame, AttachProperties, and FormatProperties. Register builds the property database by making calls to CreatePropertyDatabase, and then passes the database back to the kernel. RecognizeFrame takes a pointer to raw data and passes back to the kernel whether or not the parser recognizes the data; if the parser does recognize the data, it also passes back the length of the recognized data. AttachProperties identifies every displayable element of the frame recognized. For detailed information about entry points, see Entry Point Functions for Protocol Parser DLLs.

Here is an example of a parser calling sequence:

The parser will be called many times at the RecognizeFrame entry for each of the frames being looked at by the kernel. FormatProperties will be called only if the user interface wants to display the frame. Register and Deregister will be called only at the beginning and the end, respectively.

When you do a LoadLibrary on a Network Monitor parser, the parser calls back into the kernel during initialization and passes a structure containing pointers to entry points for each protocol parser stored in the DLL. The kernel then evaluates whether or not it wants each parser's entry points. This allows Network Monitor to swap out a specific parser (for example, NFS) in the field without disturbing the other parsers. You can write a parser for NFS, load it into the system, and tell the system to use your NFS parser instead of the one provided with Network Monitor.


Recognize Frame

Linking Parsers into the Data Stream

There are two ways that a parser can become part of the data stream. One way is for the previous protocol to know that the parser exists and to "hand off" to it. The other is for the previous protocol to build a "follow set" of the possible protocols that could follow it. When a protocol parser is called in its recognize function, its return code indicates whether or not it recognizes its protocol in the raw data, and may indicate which protocol follows.

FollowSet Parsers

HandoffSet Parsers


FollowSet Parsers

FollowSet parsers are usually NetBIOS based. A NetBIOS protocol usually has no idea what protocol follows it. The following protocol could be SMB, or any other NetBIOS protocol. If you look in the file PARSER.INI in the root of the Network Monitor installation directory (for example: C:\NM), the NetBIOS parser entry will look something like this:

[NETBIOS]
    Comment     = "Network Basic Input/Output System protocol"
    FollowSet   = SMB, MSRPC
    HelpFile    =

If the NetBIOS parser recognizes a frame, it returns the lpByte of the following protocol, but not the protocol name. The FollowSet handler in the Network Monitor kernel takes the return from the NetBIOS parser, and sequentially calls the SMB handler and the MSRPC parser until one of them claims the frame.


HandoffSet Parsers

HandoffSet parsers are more efficient than FollowSet parsers. When a HandoffSet parser returns from its recognize function, it identifies the next protocol for the kernel.

For example, the TCP parser has a Port property that tells it what protocol follows it. Port 20 indicates that the next protocol will be FTP; port 53 indicates that the next protocol will be DNS. Another example: in the SMB parser, if the value in the smb_suwcnt field of a Transact SMB is 0, then the data pointed to by smb_psoff is the data for a Remote API and should be handed to the REMAPI parser.

How a HandoffSet parser determines which protocol follows is implemented in one of two ways: one way handles the TCP/IP kind of HandoffSet, and the other handles the SMB kind of HandoffSet. If you examine the TCPIP.INI file in the parser directory, it looks something like this:

[IP_HandoffSet]
   1    = ICMP
   6    = TCP
   17   = UDP
   89   = OSPF

[TCP_HandoffSet]
   20   = FTP
   21   = FTP
   23   = TELNET
   53   = DNS
   111  = RPC
   137  = NBT, 1000
   138  = NBT, 1002
   139  = NBT, 1001
   1024 = NBT, 1001

[UDP_HandoffSet]
   53   = DNS
   67   = DHCP
   68   = DHCP
   111  = RPC
   137  = NBT, 1000
   138  = NBT, 1002
   139  = NBT, 1001
   520  = RIP
   2049 = RPC

[RPC_HandoffSet]
   2049   = NFS

The TCP/IP parser reads this file at DLL initialization, and makes a table of numbers and handles to parsers. When TCP gets a port, it reads the table to see if the port is for a known protocol. This method allows a new parser (that the TCP parser can hand off to) to be added without shipping a new TCP parser.

For example, if you wanted to write a Finger protocol parser, you would create the parser, modify the PARSER.INI file to load your parser, and then tell TCP to hand off to you by adding the Finger port as shown here:

[TCP_HandoffSet]
   20   = FTP
   21   = FTP
   23   = TELNET
   53   = DNS
   79   = FINGER
   111  = RPC
   137  = NBT, 1000
   138  = NBT, 1002
   139  = NBT, 1001
   1024 = NBT, 1001

The TCP/IP parser reads its initialization data out of an .INI file stored in its directory. It scans the data, converts the text "79" to the number 79, gets the text string "FINGER," and calls a function to find Finger's protocol handle.

hFinger = GetProtocolFromName ("FINGER");

If the kernel has successfully loaded the Finger protocol, a valid non-NULL handle will be returned that can be returned at recognize time to identify the Finger protocol as being the next in line.

Helper Functions

The Network Monitor kernel provides some parser helper functions to make this easier. For example, the LLC parser Register function creates and loads its LLC.INI file in the following piece of code by using the BuildINIPath helper API to get the path to the .INI file. It also uses the CreateHandoffTable helper API to load a handoff table.

VOID WINAPI LLCRegister(HPROTOCOL hLLCProtocol)
{
    register DWORD i;
    char     IniFile[INI_PATH_LENGTH];

    //===========================================================
    //  Create the property database.
    //===========================================================

    CreatePropertyDatabase(hLLCProtocol, nLLCProperties);

    for(i = 0; i < nLLCProperties; ++i)
    {
        AddProperty(hLLCProtocol, &LLCDatabase[i]);
    }

    if (BuildINIPath(IniFile, "LLC.DLL") == NULL)
    {
        #ifdef DEBUG
        dprintf(" LLC BuldINIPath Failed !");
        #endif
    }

    if ((nSapHOSets = CreateHandoffTable(  "SAPS",
            IniFile,
            &lpSapHOTable,
            MAX_SAPS,
            16)) == 0)
    {
    #ifdef DEBUG
    dprintf("BuildHandoffTable failed on SAPS Section");
    #endif
    }
}

Now, in the Recognize function for LLC, for SAPS and ETYPES, it looks up who to hand off to by calling the GetProtocolFromTable helper API:

LPBYTE WINAPI LLCRecognizeFrame(HFRAME          hFrame,                     //... frame handle.
                                LPBYTE          MacFrame,                   //... Frame pointer.
                                LPLLC           LLCFrame,                   //... Relative pointer.
                                DWORD           MacType,                    //... MAC type.
                                DWORD           BytesLeft,                  //... Bytes left.
                                HPROTOCOL       hPreviousProtocol,          //... Previous protocol or NULL if none.
                                DWORD           nPreviousProtocolOffset,    //... Offset of previous protocol.
                                LPDWORD         ProtocolStatusCode,         //... Pointer to return status code in.
                                LPHPROTOCOL     hNextProtocol,              //... Next protocol to call (optional).
                                LPDWORD         InstData)                   //... Next protocol instance data.
{
    //===============================================================
    //  If the mac frame equals the llc frame this isn't LLC.
    //===============================================================

    if ( MacFrame != (LPBYTE) LLCFrame )
    {
        //===========================================================
        //  If this is ethernet then the LLC frame had better follow the
        //  mac header.
        //===========================================================

        if (  MacType == MAC_TYPE_ETHERNET &&
      &MacFrame[ETHERNET_HEADER_LENGTH] != (LPBYTE) LLCFrame )
        {
            *ProtocolStatusCode = PROTOCOL_STATUS_NOT_RECOGNIZED;

            return (LPBYTE) LLCFrame;
        }

        //==========================================================
        //  Now check for an LLC frame in general.
        //
        //  For this we rule out the global sap pair.
        //==========================================================

        if ( *((ULPWORD) LLCFrame) != 0xFFFF )
        {
            register LPBYTE EndOfFrame;

            if ( (EndOfFrame = GetEndOfFrame(LLCFrame)) != NULL )
            {
                *hNextProtocol = GetProtocolFromTable(  lpSapHOTable,
                LLCFrame->dsap,
                InstData);

                *ProtocolStatusCode = PROTOCOL_STATUS_NEXT_PROTOCOL;
            }
            else
            {
                *ProtocolStatusCode = PROTOCOL_STATUS_CLAIMED;
            }

            return EndOfFrame;
        }
    }

    *ProtocolStatusCode = PROTOCOL_STATUS_NOT_RECOGNIZED;

    return (LPBYTE) LLCFrame;
}


Steps for Creating a Sample Parser DLL

This section shows the steps necessary to create a parser. The following example uses the Finger protocol to show the steps.

To create a parser DLL
  1. Set up your build environment. For this example, build environment requirements are:

    Windows NT

    Microsoft® Visual C++®

    Win32® SDK

  2. Copy the REMAPI files provided in the \MSSDK\SAMPLES\SYSMGMT\SMS\NETMON\REMAPI subdirectory of the Platform SDK CD-ROM.
  3. Rename REMAPI.* to FINGER.*.
  4. Edit FINGER.C and change all references of "RemAPI" to "Finger."
  5. Edit FINGER.H and change all references of "RemAPI" to "Finger."

    Note FINGER.H is where you make your data structures within the #pragma pack(1) lines. You need this pragma because you will get DWORD aligned unless you tell the compiler to pack.

  6. Edit the makefile and change all references of "RemAPI" to "Finger."
  7. Edit the FINGER.DEF file and change all references of "RemAPI" to "Finger."
  8. Save all files and do an NMAKE. Your output should look like this:
    F:\BH\PARSERS\finger>nmake

Microsoft (R) Program Maintenance Utility   Version 1.50.4048
Copyright (c) Microsoft Corp 1988-93. All rights reserved.

        cl386 -c -G3 -Gs -W3 -nologo -Zl -Z7 -Od -D_X86_=1 -DDEBUG
        -DMSINTERNAL -DDEBUG -D_DLL -If:\bh\include -nologo
        Finger.c
g:\msvcnt\bin\CL386.EXE: warning: invoking g:\msvcnt\bin\CL.EXE
Finger.c
        lib32 -subsystem:WINDOWS -machine:i386 -def:Finger.def
        Finger.obj -out:Finger.lib
g:\msvcnt\bin\LIB32.EXE: warning: invoking g:\msvcnt\bin\LIB.EXE
Microsoft (R) 32-Bit Library Manager Version 1.00
Copyright (C) Microsoft Corp 1992-93. All rights reserved.

   Creating library Finger.lib and object Finger.exp ...
        link32 -subsystem:WINDOWS -machine:i386 -align:0x1000
        -MAP:Finger.map -debug:full -debugtype:both
        -entry:DLLEntry@12 -dll -out:Finger.dll -map:Finger.map
        Finger.exp Finger.obj kernel32.lib user32.lib crtdll.lib
        f:\bh\build\parser.lib f:\bh\build\BHSUPP.lib
        f:\bh\build\NMAPI.lib
Microsoft (R) 32-Bit Executable Linker Version 2.50.4048 (NT)
Copyright (C) Microsoft Corp 1992-94. All rights reserved.

        mapsympe -nologo -n -o Finger.sym Finger.dll > nul
        copy Finger.sym f:\bh\build\parsers
        1 file(s) copied.
        copy Finger.dll f:\bh\build\parsers
        1 file(s) copied.
        copy Finger.lib f:\bh\build\parsers
        1 file(s) copied.
        copy Finger.ini f:\bh\build\parsers
The system cannot find the file specified.
NMAKE : fatal error U1077: 'D:\WINNT\system32\cmd.exe' : return code'0x1'
Stop.
  9. The last error is expected because there is no FINGER.INI file. To avoid this error, remove the COPY statement from the makefile.
  10. Fix any errors in the build. It should compile without errors at this point.
  11. Add your parser to the Network Monitor. See Installing Your Protocol Parser DLL to the Network Monitor.


Installing Your Protocol Parser DLL To the Network Monitor

This section uses the Finger protocol to show installation steps.

To install a protocol parser DLL to the network monitor
  1. Edit the PARSER.INI file and add your protocol:
    ;============================================================
;   Network Monitor parser/protocol initialization file.
;============================================================

[PARSERS]
    FRAME.DLL   = 0: FRAME
    MAC.DLL     = 0: ETHERNET, TOKENRING, FDDI, TMAC
    LLC.DLL     = 0: LLC, RPL, SNAP, BPDU
    NETBIOS.DLL = 0: NETBIOS
    SMB.DLL     = 0: SMB
    XNS.DLL     = 0: XNS
    IPX.DLL     = 0: IPX, SAP, RIPX, NMPI, NBIPX, SPX
    TCPIP.DLL   = 0: IP, ARP_RARP, ICMP, UDP, NBT, TCP, DNS, TELNET, ...
    NCP.DLL     = 0: NCP
    ATALK.DLL   = 0: LAP, AARP, DDP, RTMP, NBP, ATP, PAP, ASP, ZIP, ...
    BONE.DLL    = 0: BONE
    MSRPC.DLL   = 0: MSRPC
    BROWSER.DLL = 0: BROWSER
    PPP.DLL     = 0: PPP, LCP
    FINGER.DLL  = 0: FINGER

[FRAME]
    Comment     = "Base frame properties"
    FollowSet   = PPP, ETHERNET, TOKENRING, FDDI
    HelpFile    =

[BROWSER]
    Comment     = "MS Browser"
    FollowSet   =
    HelpFile    =

[FINGER]
    Comment     = "TCP Finger, port 79"
    FollowSet   =
    HelpFile    =

...
  2. Edit \PARSERS\TCPIP.INI under the Network Monitor Installed directory and add Finger to the handoff setup of TCP. See Handoffset Parsers.
  3. Run Network Monitor and load a .CAP file that contains a Finger frame. Verify that the handoff worked correctly.
  4. Start writing the protocol parser. Remove the code that applies only to RemAPI. Note that the CommandSET defined for RemAPI will not work for Finger. However, the protocol that you are writing a parser for probably has a similar command field, so you may be able to convert this one.

    Note Previous parsers hand off to the Finger parser. However, you may be writing a parser that appears in the follow set of another parser instead. If so, you need to add your protocol to the follow set in the PARSER.INI file of any preceding protocols, and modify the RecognizeFrame in your parser to determine whether the data belongs to your protocol.


Entry Point Functions for Protocol Parser DLLs

The topics in this section describe the entry point functions for parser DLLs.

AttachProperties

Deregister

FormatProperties

RecognizeFrame

Register


AttachProperties

The AttachProperties entry point is called to request that the parser attach any properties that it finds in the frame to the frame.

DWORD AttachProperties(
  HFRAME hFrame,
  LPBYTE lpFrame,
  LPBYTE lpProtocol,
  DWORD MacType,
  DWORD BytesLeft,
  HPROTOCOL hPreviousProtocol,
  DWORD nPreviousProtocolOffset,
  DWORD lpInstData
);

Parameters

hFrame
Specifies the handle to the frame being recognized.
lpFrame
Specifies the pointer to the first byte of the whole frame.
lpProtocol
Specifies the pointer to the current unclaimed portion of the frame.

Note This data is probably somewhere in the middle of the frame, because a previous parser claimed data before your parser was called.

MacType
Specifies a value as follows:
MacType | Meaning
MAC_TYPE_ETHERNET | 802.3
MAC_TYPE_TOKENRING | 802.5
MAC_TYPE_FDDI | ANSI X3T9.5

BytesLeft
Specifies the number of bytes left to process in the frame.
hPreviousProtocol
Specifies the handle of the previous protocol.
nPreviousProtocolOffset
Specifies the offset of the previous protocol.
lpInstData
Instance data from the previous protocol.

Return Values

The return value is a pointer to the next place in the frame. If the parser recognizes the frame, then it should return a pointer to the first byte beyond its recognized data. If the parser does not recognize the frame, it should return the lpProtocol as passed in. If the parser wants to claim all of the remaining data, the parser should return NULL.

Remarks

The AttachProperties entry point is called to request that the parser attach properties to the frame. To add entries, the parser will call the helper function AttachPropertyInstance.


Deregister

The Deregister entry point is called to allow the parser to clean up.

DWORD Deregister(
  HPROTOCOL hProtocol
);

Parameters

hProtocol
Specifies the handle for this given protocol parser.

Return Values

Should return TRUE if successful and FALSE if unsuccessful.

Remarks

Deregister is called to allow the parser to clean up. It should call DestroyPropertyDatabase on its property database.


FormatProperties

The FormatProperties entry point is called to ask the parser to take all of the property instances and build the szPropertyText field in each PropertyInst structure.

DWORD FormatProperties(
  HFRAME hFrame,
  LPBYTE lpFrame,
  LPBYTE lpProtocol,
  DWORD nPropertyInsts,
  LPPROPERTYINST lpPropInst
);

Parameters

hFrame
Specifies the handle to the frame.
lpFrame
Specifies the pointer to the first byte for the frame.
lpProtocol
Specifies the pointer to the protocol start data.
nPropertyInsts
Specifies the number of properties attached on this frame by this parser.
lpPropInst
Specifies the pointer to the property instance or instances to be formatted. This is an array, and will be a pointer to one or more properties in an array.

Return Values

Should return TRUE if successful and FALSE if unsuccessful.

Remarks

FormatProperties is called to ask the parser to take all of the property instances and build the szPropertyText field in each PropertyInst structure. Each PropertyInst structure's szPropertyText field will point to a buffer of the maximum string size (as defined in AddProperty); the parser should fill the buffer pointed to in szPropertyText with the formatted string describing the property.

Note The string values returned in the property instance must be double-null-terminated. If a parser must describe a property with multiple lines, it can do so by returning multiple strings separated by \0, where the last string is terminated by a double \0.


RecognizeFrame

The RecognizeFrame entry point is called to quickly determine if the raw data (starting at lpProtocol passed in) belongs to the protocol the parser understands.

LPBYTE RecognizeFrame(
  HFRAME hFrame,
  LPBYTE lpFrame,
  LPBYTE lpProtocol,
  DWORD MacType,
  DWORD BytesLeft,
  HPROTOCOL hPreviousProtocol,
  DWORD nPreviousProtocolOffset,
  LPDWORD ProtocolStatusCode,
  LPHPROTOCOL hNextProtocol,
  LPDWORD lpInstData
);

Parameters

hFrame
Specifies the handle to the frame being recognized.
lpFrame
Specifies the pointer to the first byte of the whole frame.
lpProtocol
Specifies the pointer to the current unclaimed portion of the frame.

Note This data is probably somewhere in the middle of the frame, because a previous parser has claimed data before this parser.

MacType
Specifies a value as follows:
MacType | Meaning
MAC_TYPE_ETHERNET | 802.3
MAC_TYPE_TOKENRING | 802.5
MAC_TYPE_FDDI | ANSI X3T9.5

BytesLeft
Specifies the number of bytes in the frame left to process.
hPreviousProtocol
Specifies the handle of the previous protocol.
nPreviousProtocolOffset
Specifies the offset of the previous protocol.
ProtocolStatusCode
When a protocol parser gets called in its recognize function, it can return one of four return codes:
Value | Meaning
PROTOCOL_STATUS_RECOGNIZED | The parser recognized the frame and moved the pointer to the end of its protocol header. Network Monitor uses the protocol's follow set to continue parsing.
PROTOCOL_STATUS_NOT_RECOGNIZED | The parser did not recognize the frame and did not move the pointer (that is, the start data pointer which was passed in). Network Monitor uses the previous protocol's follow set to continue parsing.
PROTOCOL_STATUS_CLAIMED | The parser recognized the frame, claimed it all for itself, and parser recognition terminates.
PROTOCOL_STATUS_NEXT_PROTOCOL | The parser recognized the frame and moved the pointer to the end of its protocol header. The current protocol requests that Network Monitor continue parsing at a known next protocol by returning the next protocol's handle to Network Monitor. In this case, the FollowSet of the current protocol, if any, is not used.

hNextProtocol
The spot to return the handle of the next protocol.
lpInstData
Instance data from the previous protocol, and where instance data is passed to the next protocol parser.

Return Values

The return value is a pointer to the next place in the frame. If the parser recognizes the frame, then it should return a pointer to the first byte beyond its recognized data. If the parser does not recognize the frame, then it should return the lpProtocol as passed in. If the parser wishes to claim all of the rest of the data, the parser should return NULL.

Remarks

The task of RecognizeFrame is to as quickly as possible determine if the raw data (starting at lpProtocol passed in) is pointing to data that the parser recognizes as data belonging to the protocol it understands. It should not attach any properties or do any more processing beyond noting the end point of the data belonging to its protocol, or determining that no such data is present. A parser should not search for data beyond lpProtocol.

Note RecognizeFrame may still be called even if Register has not been called. Thus, RecognizeFrame should not rely on any properties or structures that are created or initialized in the Register entry point.


Register

The Register entry point returns the level of parsing that this parser understands.

WORD Register(
  HPROTOCOL hProtocol
);

Parameters

hProtocol
Specifies the handle that the kernel will use to describe this parser in the future. This handle should be kept and used by the parser in future APIs, such as CreatePropertyDatabase.

Return Values

Should return a parser level value of 1.

Remarks

Register returns the level of parsing that this parser understands. Only one level of parsing is recognized. When the parser Register function is called, the parser should call CreatePropertyDatabase and AddProperty to build a database describing all of the properties that it will use in describing the protocol it understands.


Functions Called by Parser DLLs

The topics in this section describe functions called by parser DLLs.

AddProperty

AttachPropertyInstance

AttachPropertyInstanceEx

CreatePropertyDatabase

DestroyPropertyDatabase

FindNextFrame

FindPreviousFrame

FormatPropertyInstance

GetFrameDestinationAddress

GetFrameSourceAddress

GetProtocolStartOffset

ParserTemporaryLockFrame


AddProperty

The AddProperty function adds a PropertyInfo structure to the PropertyDatabase.

HPROPERTY AddProperty(
  HPROTOCOL hProtocol,
  LPPROPERTYINFO PropertyInfo
);

Parameters

hProtocol
The handle of the protocol to add the property to.
PropertyInfo
A pointer to the structure describing the property.

Return Values

Returns a pointer to the property added. If not NULL, then the protocol offset is valid. If NULL, then BHGetLastError is valid.

Error Code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INVALID_HPROPERTY | The hProperty was invalid.
BHERR_INVALID_HFRAME | The hFrame was invalid.

Remarks

This function,which adds a PropertyInfo structure to the PropertyDatabase, is how the parser describes the database format and properties to the kernel. The properties are added one property at a time. See Sample Parser for an example.


AttachPropertyInstance

The AttachPropertyInstance function attaches a property instance to a frame, thus creating a PROPERTYINST structure for that frame in the PROPERTYINSTTABLE for the frame.

DWORD AttachPropertyInstance(
  HFRAME hFrame,
  HPROPERTY hProperty,
  DWORD Length,
  LPVOID lpData,
  DWORD HelpID,
  DWORD IndentLevel,
  DWORD IFlags
);

Parameters

hFrame
Specifies the handle to the frame to which to add the property instance.
hProperty
Specifies the handle for the property to add.
Length
Specifies the length of the data.
lpData
Specifies a pointer to the data in the frame where the Properties value is located.
HelpID
Specifies a number (from 0 to 2047) signifying a Help identifier used to set context-sensitive Help on the property. The number is relative to the Help file identified with the property database identified in the CreatePropertyDatabase call.
IndentLevel
Specifies a number (from 0 to 15) signifying an indentation level for hierachical displays. Properties of type PROP_TYPE_SUMMARY should always be level 0. All other properties are at the parser writer's prerogative, but starting at 1 will provide the most consistent display. The current user interface uses levels 0–9. Level 15 is a special level that allows the parser to attach a hidden property that will not normally be displayed.
IFlags
Specifies a bitfield that has the following definitions:
1 | IFLAG_ERROR
2 | IFLAG_SWAPPED (WORD or DWORD byte is non-Intel format at attach time)
4 | IFLAG_UNICODE (STRING is UNICODE at attach time)

Note that earlier parsers set the fError DWORD to 0 or 1, which will map to IFLAG_ERROR.

Return Values

The return value is the error code.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INVALID_HPROPERTY | The hProperty was invalid.
BHERR_INVALID_HFRAME | The hFrame was invalid.

Remarks

This function is used to attach a property instance to a frame, thus creating a PROPERTYINST structure for that frame in the PROPERTYINSTTABLE for the frame. This function will add the information to the frame as a PROPERTYINST structure.


AttachPropertyInstanceEx

The AttachPropertyInstanceEx function attaches a property to a frame, thus creating a PROPERTYINST and a PROPERTYINSTEX structure for that frame in the PROPERTYINSTTABLE for the frame.

DWORD AttachPropertyInstanceEx(
  HFRAME hFrame,
  HPROPERTY hProperty,
  DWORD Length,
  LPVOID lpData,
  DWORD LengthEx,
  LPVOID lpDataEx,
  DWORD HelpID,
  DWORD IndentLevel,
  DWORD IFlags
);

Parameters

hFrame
Specifies the handle to the frame to which to add the property.
hProperty
Specifies the handle for the property to add.
Length
Specifies the length of the data in the frame in bytes. Length can be zero.
lpData
Specifies a pointer to the data in the frame where the Properties original value is located. lpData can be NULL.
LengthEx
Specifies the length of the extended data in bytes.
lpDataEx
Specifies a pointer to the extended data, usually a stack variable.
HelpID
Specifies a number (from 0 to 2047) signifying a Help identifier used to set context-sensitive Help on the property. The number is relative to the Help file identified with the property database identified in the CreatePropertyDatabase call.
IndentLevel
Specifies a number (from 0 to 15) signifying an indentation level for hierachical displays. Properties of type PROP_TYPE_SUMMARY should always be level 0. All other properties are the parser writer's prerogative, but starting at 1 will provide the most consistent display. The current user interface uses levels 0–9. Level 15 is a special level that allows the parser to attach a hidden property that will not normally be displayed.
IFlags
Specifies a bitfield that has the following definitions:
1 | IFLAG_ERROR
2 | IFLAG_SWAPPED (WORD or DWORD byte is non-Intel format at attach time)
4 | IFLAG_UNICODE (STRING is UNICODE at attach time)

Note that earlier parsers set the fError DWORD to 0 or 1, which will map to IFLAG_ERROR.

Return Values

The return value is the error code.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INVALID_HPROPERTY | The hProperty was invalid.
BHERR_INVALID_HFRAME | The hFrame was invalid.

Remarks

This function is used to attach a property to a frame, thus creating a PROPERTYINST and a PROPERTYINSTEX structure for that frame in the PROPERTYINSTTABLE for the frame. This function will add the information to the Frame as a PROPERTYINST structure.

The AttachPropertyInstanceEx function is used when data needs to be generated external to the frame data in order to more clearly describe the protocol. For example, the Ethernet parser generated a property that describes the length of the frame. Another example would be where the SMB parser converts the time to a SYSTEMTIME format and attaches the converted time with AttachPropertyInstanceEx so that the Generic Formatter will format it.

Note A copy of the lpDataEx structure is made (of LengthEx length) so that it can be in a temporary variable when calling this function. If the lpDataEx pointer is NULL, or the LengthEx parameter is zero, then the "ex" parameters will be ignored and AttachPropertyInstance will be called.


CreatePropertyDatabase

The CreatePropertyDatabase function creates a property database for describing properties that the parser will be using to describe its data.

DWORD CreatePropertyDatabase(
  HPROTOCOL hProtocol,
  DWORD nProperties
);

Parameters

hProtocol
Specifies the handle to the protocol that owns this database.
nProperties
Specifies the number of properties that the database can store.

Return Values

The return value is the error code.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INTERNAL_ERROR | An internal error occurred.
BHERR_INVALID_HPARSER | The HPARSER was invalid.

Remarks

This function is used by a parser to create a property database for describing properties that it will be using to describe its data. The property database is used to interpret Properties added by the parser to describe a Frame.

This function allocates the necessary structures needed to maintain a property database.

Note This function should be called by a parser DLL only from the Register entry point.


DestroyPropertyDatabase

The DestroyPropertyDatabase function destroys a property database created by calls to CreatePropertyDatabase and AddProperty.

DWORD DestroyPropertyDatabase(
  HPROTOCOL hProtocol
);

Parameters

hProtocol
Specifies the handle to the property database to destroy.

Return Values

The return value is the error code.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INTERNAL_ERROR | An internal error occurred.
BHERR_INVALID_HPARSER | The HPARSER was invalid.

Remarks

This function is used to destroy a property database created by calls to CreatePropertyDatabase and AddProperty, which frees up all resources associated with this database.


FindNextFrame

The FindNextFrame function finds the next frame in the current capture context that matches the filter.

HFRAME FindNextFrame(
  HFRAME hCurrentFrame,
  LPSTR ProtocolName,
  LPADDRESS DestinationAddress,
  LPADDRESS SourceAddress,
  LPWORD ProtocolOffset,
  DWORD OriginalFrameNumber,
  DWORD HighestFrame
);

Parameters

hCurrentFrame
Specifies a handle to the frame.
ProtocolName
Specifies the protocol name, such as "TCP."
DestinationAddress
Specifies the destination address.
SourceAddress
Specifies the source address.
ProtocolOffset
Specifies a pointer to a WORD that will receive the protocol offset.
OriginalFrameNumber
Starting point for this search. By default this API will search forward 1000 frames from here. The search forward distance can be changed by adding a MAXLOOKBACK=<new lookforward distance> line to the NMAPI.INI file in the Network Monitor Installed directory.
HighestFrame
Highest frame number in the capture to search to.

Return Values

The return value is the handle to the frame. If the return value is not NULL, then the protocol offset is valid; if it is NULL, then BHGetLastError is valid.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INTERNAL_ERROR | An internal error occurred.
BHERR_INVALID_HFRAME | The hframe was invalid.

Remarks

This function finds the next frame in the current capture context that matches the filter. The filter is defined primarily by the ProtocolName, and this is the only required filter input. The DestinationAddress and SourceAddress can be given as a speed enhancement. The ProtocolOffset is returned to the calling parser, which adds this word to the pointer returned by locking the frame (with the ParserTemporaryLockFrame API call) to get the LPBYTE of the protocol that is being searched for. On return, the HFRAME that passed the filter is given to the parser. If the parser finds that this frame is not the one it is looking for, it can hand this HFRAME back to FindNextFrame to get the next one back. The source and destination addresses are not required and can be passed in as NULL.


FindPreviousFrame

The FindPreviousFrame function finds the previous frame in the current capture context that matches the filter.

HFRAME FindPreviousFrame(
  HFRAME hCurrentFrame,
  LPSTR ProtocolName,
  LPADDRESS DestinationAddress,
  LPADDRESS SourceAddress,
  LPWORD ProtocolOffset,
  DWORD OriginalFrameNumber,
  DWORD LowestFrame
);

Parameters

hCurrentFrame
Specifies a handle to the frame.
ProtocolName
Specifies the protocol name, such as "TCP."
DestinationAddress
Specifies the destination address of the frame to find.
SourceAddress
Specifies the source address of the frame to find.
ProtocolOffset
Specifies a pointer to a WORD that will receive the protocol offset.
OriginalFrameNumber
Starting point for this search. By default, this API will search back 1000 frames from here. The search-back distance can be changed by adding a MAXLOOKBACK=<new lookback distance> line to the NMAPI.INI file in the Network Monitor Installed directory.
LowestFrame
Lowest frame number in the capture to search to.

Return Values

The return value is the handle to the frame. If the return value is not NULL, then the protocol offset is valid; if it is NULL, then BHGetLastError is valid.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_INTERNAL_ERROR | An internal error occurred.
BHERR_INVALID_HFRAME | The hFrame was invalid.

Remarks

This function finds a frame in the current capture context that matches the filter. The filter is defined primarily by the ProtocolName, and this is the only required filter input. The DestinationAddress and SourceAddress can be given as a speed enhancement. The ProtocolOffset is returned to the calling parser, which adds this DWORD to the pointer returned by locking the frame (with the ParserTemporaryLockFrame API call) to get the LPBYTE of the protocol that is being searched for. On return, the HFRAME that passed the filter is given to the parser. If the parser finds that this frame is not the one it is looking for, it can hand this HFRAME back to FindPreviousFrame to get the next frame back. The source and destination addresses are not required, and can be passed in as NULL. When used, they can be of type ADDRESS_TYPE_IP, and so on, not just MAC types.


FormatPropertyInstance

The FormatPropertyInstance function formats the property instance in a generic manner.

DWORD FormatPropertyInstance(
  LPPROPERTYINST lpPropertyInst,
  ...
);

Parameters

lpPropertyInst
Specifies a pointer to a property instance.

Return Values

None.

Remarks

This function formats the property instance in a generic manner. It modifies the text of the property instance to reflect the data and the strings associated with the data type and qualifiers.


GetFrameDestinationAddress

The GetFrameDestinationAddress function obtains the destination address of a frame.

DWORD GetFrameDestinationAddress(
  HFRAME hFrame,
  LPADDRESS lpAddress,
  DWORD AddressType,
  DWORD Flags
);

Parameters

hFrame
Specifies the handle to the frame to get a pointer to.
lpAddress
The return buffer that will store the frame destination address.
AddressType
The type of address you are looking for: ADDRESS_TYPE_ETHERNET, ADDRESS_TYPE_IP, and so on.
Flags
The flags specify ADDRESSTYPE_FLAGS_NORMALIZE, which cancels out the routing and group bits and ADDRESSTYPE_FLAGS_BIT_REVERSE, which is used on token ring to flip the address back to normal after a 3 to 5 bridge has flipped it.

Return Values

If the return value is SUCCESS, the lpAddress is valid.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_PROTOCOL_NOT_FOUND | The specified protocol in the AddressType is invalid for the frame.
BHERR_INVALID_HFRAME | The hFrame is invalid.

Remarks

An address type of ADDRESS_TYPE_FIND_HIGHEST is allowed. If this type is used, the API will attempt to find the IPX, XNS, IP, or VINES IP address before returning the ETHERNET, TOKENRING, or FDDI address. This is useful for protocols and environments where two netcards can be multiplexed under a single server address.


GetFrameSourceAddress

The GetFrameSourceAddress function obtains the source address of a frame.

DWORD GetFrameSourceAddress(
  HFRAME hFrame,
  LPADDRESS lpAddress,
  DWORD AddressType,
  DWORD Flags
);

Parameters

hFrame
Specifies the handle to the frame to get a pointer to.
lpAddress
The return buffer that will store the frame source address.
AddressType
The type of address you are looking for: ADDRESS_TYPE_ETHERNET, ADDRESS_TYPE_IP, and so on.
Flags
The flags specify ADDRESSTYPE_FLAGS_NORMALIZE, which cancels out the routing and group bits and ADDRESSTYPE_FLAGS_BIT_REVERSE, which is used on token ring to flip the address back to normal after a 3 to 5 bridge has flipped it.

Return Values

If the return value is SUCCESS, the lpAddress is valid.

Error code | Meaning
BHERR_SUCCESS | No problems were encountered.
BHERR_PROTOCOL_NOT_FOUND | The specified protocol in the AddressType is invalid for the frame.
BHERR_INVALID_HFRAME | The hFrame is invalid.

Remarks

An address type of ADDRESS_TYPE_FIND_HIGHEST is allowed. If this type is used, the API will attempt to find the IPX, XNS, IP, or VINES IP address before returning the ETHERNET, TOKENRING, or FDDI address. This is useful for protocols and environments where two netcards can be multiplexed under a single server address.


GetProtocolStartOffset

The GetProtocolStartOffset function returns the offset to a specified protocol in the frame.

DWORD GetProtocolStartOffset(
  HFRAME hFrame,
  LPSTR ProtocolName
);

Parameters

hFrame
Specifies a handle to the frame.
ProtocolName
Specifies the protocol name, such as "TCP."

Return Values

The DWORD offset to the beginning of the protocol being searched for, or zero.

Remarks

Given the handle to a frame, this function returns the offset to a specified protocol in the frame. For example, the DNS (Domain Name Service) parser needs the port address of the TCP protocol to determine if the frame is a DNS frame. The DNS parser would call this API with "TCP" as the ProtocolName. If the frame has been recognized by the TCP protocol, then the WORD offset from the beginning of the frame to the beginning of the TCP frame is returned. If there is no TCP protocol, then a zero is returned.

This function finds the start of a protocol in a frame.


ParserTemporaryLockFrame

The ParserTemporaryLockFrame function locks a frame when it enters a parser, and unlocks the frame when it exits.

LPBYTE ParserTemporaryLockFrame(
  HFRAME hFrame
);

Parameters

hFrame
Specifies the handle to the frame to get a pointer to.

Return Values

A pointer to the first byte of data in the frame.

Remarks

Parsers should not call LockFrame. If a parser takes a lock and then gets faulted or returns without unlocking, it leaves the system in a state where it cannot change protocols or cut/copy frames. Parsers should use ParserTemporaryLockFrame, which grants a lock only during the context of the API entry into the parser. The lock is released on exit from the parser for that frame. This means that the pointer will be valid only after the parser returns from the AttachProperties or RecognizeFrame call.


Structures (Network Monitor)

The topics in this section describe Network Monitor structures.

LABELED_BIT

LABELED_BYTE

LABELED_DWORD

LABELED_WORD

PROPERTYINFO

PROPERTYINST

PROPERTYINSTEX

PROTOCOLINFO

RANGE

SET


LABELED_BIT

The LABELED_BIT structure is used to handle bitfields or flags. The data type will almost always be found in conjunction with a SET data type.

typedef struct _LABELED_BIT {
    BYTE BitNumber;
    LPSTR LabelOff;
    LPSTR LabelOn;
} LABELED_BIT;

typedef LABELED_BIT *LPLABELED_BIT;

Members

BitNumber
Bit number (starts at 0, up to 256 bits).
LabelOff
Label for bit = 0.
LabelOn
Label for bit = 1.


LABELED_BYTE

The LABELED_BYTE structure is used to represent a value/label pair. You can create a table of these value/label pairs and point a SET to it to make a set of LABELED_BYTEs.

typedef struct labeled_byte {
    BYTE Value;
    LPSTR Label;
} LABELED_BYTE[];

typedef LABELED_BYTE  *LPLABELED_BYTE;

Members

Value
The actual field value, found in the raw data.
Label
The textual description of the field.


LABELED_DWORD

The LABELED_DWORD structure is used to represent a value/label pair. You can create a table of these value/label pairs and point a SET to it to make a set of LABELED_DWORDs.

typedef struct labeled_dword {
    DWORD Value;
    LPSTR Label;
} LABELED_DWORD[];

typedef LABELED_DWORD *LPLABELED_DWORD;

Members

Value
The actual field value, found in the raw data.
Label
The textual description of the field.


LABELED_WORD

The LABELED_WORD structure is used to represent a value/label pair. You can create a table of these value/label pairs and point a SET to it to make a set of LABELED_WORDs.

typedef struct labeled_word {
    WORD Value;
    LPSTR Label;
} LABELED_WORD[];

typedef LABELED_WORD  *LPLABELED_WORD;

Members

Value
The actual field value, found in the raw data.
Label
The textual description of the field.


PROPERTYINFO

The PROPERTYINFO data structure is used to describe the properties that the protocol parser needs to describe the frames.

typedef struct _PROPERTYINFO
{
    HPROPERTY hProperty;
    DWORD Version;
    LPSTR Label;
    LPSTR Comment;
    BYTE DataType;
    BYTE DataQualifier;

    union
    {
        LPVOID lpExtendedInfo;
        LPRANGE lpRange;
        LPSET lpSet;
        DWORD Bitmask;
        DWORD Value;
    };

    WORD FormatStringSize;
    LPVOID InstanceData;
} PROPERTYINFO;

typedef PROPERTYINFO *LPPROPERTYINFO;

For example, the PROPERTYINFO table for the SMB parser starts like this:

PROPERTYINFO property_table[] =
{

// PROP_SMB_SUMMARY
    {   0,0,
        "Summary",
        "Server Message Block (SMB)",
        PROP_TYPE_SUMMARY,
        PROP_QUAL_NONE,
        NULL,
        128,
        fm_smb_summary },
...

At Register time, the SMB parser then tell the system about the properties like this:
    for (i = 0; i < PROP_LAST_PROPERTY; i++)
    {
        AddProperty(hSMBProtocol, &property_table[i]);
    }

Members

hProperty
Handle to the property. Assign at AddProperty time.
Version
Set to zero. Unused at this time.
Label
The name of the property.
Comment
The description of property that shows up on the status bar.
DataType
The data type of a property, such as Prop, Type or Byte.
DataQualifier
The data qualifier of the property, such as Prop, Type, or Array.
lpExtendedInfo
Reserved.
lpRange
A pointer to a range structure.
lpSet
A pointer to a set.
Bitmask
A bitmask to apply.
Value
Constant value.
FormatStringSize
Maximum size to reserve for textual description.
InstanceData
Property-specific instance data.


PROPERTYINST

The PROPERTYINST structure is used to represent an instance of a Property in a frame. If the PropertyInst–>Length is set to 0, then the lpPropertyInstEx structure points to a PROPERTYINSTEX structure defining free-form property instance data.

typedef struct _PROPERTYINST
{
    LPPROPERTYINFO lpPropertyInfo;
    LPSTR szPropertyText;

    union
    {
        LPVOID lpData;
        LPBYTE lpByte;
        ULPWORD lpWord;
        ULPDWORD lpDword;

        ULPLARGEINT lpLargeInt;
        ULPSYSTEMTIME lpSysTime;
        LPPROPERTYINSTEX lpPropertyInstEx;
    };

    WORD DataLength;
    WORD fError  : 1  ;      // flag for error condition ...............1
    WORD Level   : 4  ;      // level information        ...........1111.
    WORD HelpID  : 11 ;      // context ID for helpfile  11111111111.....
                             //    ---------------
                             // total of 16 bits == 1 WORD == DWORD ALIGNED structure
} PROPERTYINST;

Members

lpPropertyInfo
Pointer to property information.
szPropertyText
Pointer to string description.
lpData
Pointer to data.
lpByte
Bytes.
lpWord
WORDs.
lpDword
DWORDs.
lpLargeInt
Large Integer.
lpSysTime
Pointer to SYSTEMTIME structures.
lpPropertyInstEx
Pointer to PropertyInstEx (if DataLength = -1).
DataLength
Length of data or flag for PropertyInstEx structure.
fError : 1
Flag for error condition ....................1.
Level : 4
Level information ......................1111.
HelpID : 11
Context ID for Help file 11111111111.....


PROPERTYINSTEX

The PROPERTYINSTEX structure is used to describe a free-form extended property instance when the actual data is in a proprietary format. For instance, if you want your parser to interpret a DWORD as a DWORD, but the protocol stores it in reverse format, then your parser should call AttachPropertyInstanceEx using PropertyInstEx information, and translate the DWORD from the proprietary format into the common format. See AttachPropertyInstance.

typedef struct _PROPERTYINSTEX {
    WORD Length;
    WORD LengthEx;
    ULPVOID lpData;
    union
    {
      BYTE Byte[];
      WORD Word[];
      DWORD Dword[];
      LARGE_INTEGER LargeInt [];
      SYSTEMTIME SysTime[];
      TYPED_STRING TypedString;
    };
} PROPERTYINSTEX;

Members

Length
Length of raw data in frame.
LengthEx
Number of bytes following.
lpData
Pointer to raw data in frame.
Byte
Table of bytes follows.
Word
Table of words follows.
Dword
Table of Dwords follows.
LargeInt
Table of LARGEINT structures to follow.
SysTime
Table of SYSTEMTIME structures follows.
TypedString
A TYPED_STRING that may have extended data.


PROTOCOLINFO

The PROTOCOLINFO structure describes a protocol.

typedef struct _PROTOCOL INFO

{
    DWORD ProtocolID;
    LPPROPERTYDATABASE PropertyDatabase;
    BYTE ProtocolName[16];
    BYTE HelpFile[16];
    BYTE Comment[128];
} PROTOCOLINFO;

typedef PROTOCOLINFO *LPPROTOCOLINFO;

Members

ProtocolID
The system-assigned protocol identifier for this run session.
PropertyDatabase
The property database for this protocol.
ProtocolName
The abbreviated name.
HelpFile
The file name of the Help file.
Comment
A comment describing the protocol.


RANGE

The RANGE structure is used to represent a valid range for a number.

typedef struct range {
    DWORD MinValue;
    DWORD MaxValue;
} RANGE;

typedef RANGE *LPRANGE;

Members

MinValue
The lowest possible value for the field.
MaxValue
The highest possible value for the field.


SET

The SET structure is used to represent a table of values for a property. The first field is a count, and the rest of the entries can interpret the data pointed to as a BYTE, WORD, DWORD, LABELED_BYTE, LABELED_WORD, or LABELED_DWORD.

typedef struct _SET
{
    DWORD nEntries;

    union
    {
        //... set of labeled values
        LPLABELED_BYTE lpLabeledByteTable;
        LPLABELED_WORD lpLabeledWordTable;
        LPLABELED_DWORD lpLabeledDwordTable;
        LPLABELED_LARGEINT lpLabeledLargeIntTable;
        LPLABELED_SYSTEMTIME lpLabeledSystemTimeTable;
        LPLABELED_BIT lpLabeledBit;
    };
} SET;

typedef SET *LPSET;

Members

nEntries
Total number of entries in the set.
lpLabeledByteTable
Pointer to the table of labeled byte-sized members of the set.
lpLabeledWordTable
Pointer to the table of labeled word-sized members of the set.
lpLabeledDwordTable
Pointer to the table of labeled Dword-sized members of the set.
lpLabeledLargeIntTable
Pointer to the table of labeled Large Integer members of the set.
lpLabeledSystemTimeTable
Pointer to the table of labeled System Time members of the set.
lpLabeledBit
Pointer to the table of labeled bit-sized members of the set.


Example Data Type Handling and General Discussion

This section provides some example data structure scenarios and shows how they should be represented as properties.

The Level Field

The Labeled Set

The FLAGS Property Qualifier

A Bitset

A Byte-Swapped Element

When to Use AttachPropertyInstanceEx

Time

Arrays

Protocols That Resolve Network Names

The Summary Property


The Level Field

The level fields of the AttachPropertyInstance and AttachPropertyInstanceEx APIs are used by the user interface for making decisions about which properties are subservient to other properties. For example, if you have a flags byte:

Joe Flags = 0x06

which is a level 2 property, then when you break out the definition of the flags:

Joe Flags = 0x06
    ......1.  User has Read Privileges
    .....1..  User has Write Privileges

The breakdown of the flags properties are set to level 3. The user interface automatically indents the level 3 properties from the level 2 properties, and, if the user wishes, the user interface can hide all level 3 properties for that protocol.

Another use of the level field is to show increasing detail of the properties. A level 4 property should be one that has more detail than a level 3 property.

Parsers should strive to follow the following rules:

  • Properties should go from less detail to more detail as you indent further.
  • Properties at the same level should pass the test of "Is this property as important as its peers at this level?" If not, group them under another property, or make a new property that summaries the group and add the properties at a higher level.
  • A parser writer should strive to make as much information available as will fit within a normal detail pane under a VGA system.


The Labeled Set

Assume that you have a BYTE field that could be a distinct set of values; for example, Application_Error can have the values of 0=No Error, 1=System Error, 2=Application Error, 3=User Error, and 5=Critical Error. (Note that there is no 4.) You can use a Labeled Set to describe this field.

First, define the SET for the property:

// APPLICATION_ERROR  labeled set
LABELED_BYTE APPLICATIONError[] =
{
    0x00,  "No Error",
    0x01,  "System Error",
    0x02,  "Application Error",
    0x03,  "User Error",
    0x05,  "Critical Error",
};

SET APPLICATIONErrorSet = {sizeof(APPLICATIONError)/sizeof(LABELED_BYTE),
                   APPLICATIONError};

The SET type is defined in BHTYPES.H.

Next, define the property: (Note that this is a piece of a larger property table.)

PROPERTYINFO property_table[] =
{
...
// PROP_APPLICATIONERROR
    {      0,0,            // handle, label
    "Error",            // property name
    "Specifies the type of APPLICATION Error",    //  status bar message
    PROP_TYPE_BYTE,        // prop type
    PROP_QUAL_LABELED_SET,    // qualifier
    &ApplicationErrorSet,        //  address of set structure
    64,                //  max string size of display text
    FormatPropertyInstance },        //  instance data
...
};

The instance data is being used by this parser to store the address of the formatting routine. At FormatProperties time, this parser simply jumps to the address stored in the instance data.

Next, at attach time, the property instance is added:

// Application Error
    AttachPropertyInstance( hFrame,  // handle to frame
        PropertyTable[PROP_APPLICATIONERROR].hProperty,  // handle of property
        sizeof(MyApplicationStruct->Error),  // size of data instance
        &MyApplicationStruct->Error,  // pointer to instance in frame
        ApplicationFrame,    // Help ID
        3,        // level
        0);        // Error

Many formatting routines are already provided to the parser writer in a library. Look at PARSER.H and OLDPLIB.H in the \MSSDK\INCLUDE subdirectory of the Platform SDK CD-ROM for the names and functions of the formatting routines.


The FLAGS Property Qualifier

Many times, the protocol takes a byte, word, or dword, and makes each bit mean something. For example, a flag byte might be defined like this:

Byte             Flags;
#define          FLAGS_Dynamic_Tracking          0x01
#define          FLAGS_Effective_Only            0x02

where the variable FLAGS is allowed to take on the value:

Flags = FLAGS_Dynamic_Tracking | FLAGS_Effective_Only.

If you need to specify a different string for both the on and off case, then use the FLAGS data type.

First, define the SET for the property:

LABELED_BIT NTCreateSecurityFlagsFLAGS[] =
{   {  0,      // 0 bit = SMB_SECURITY_DYNAMIC_TRACKING,
      "dynamic tracking bit not set",
      "dynamic tracking"
    },

    {   1,      // 1th bit = SMB_SECURITY_EFFECTIVE_ONLY,
     "effective only bit not set",
      "Effective only"
    }
};

SET NTCreateSecurityFlagsFLAGSET =
  {sizeof(NTCreateSecurityFlagsFLAGS)/sizeof(LABELED_BIT),
    NTCreateSecurityFlagsFLAGS};

Next, define the property (note that this is a piece of a larger property table):

// PROP_NTCREATE_SECURITYFLAGS
  { 0,0,
  "Security Flags Dynamic Tracking",
  "Specifies the security flags on the request",
  PROP_TYPE_BYTE,
  PROP_QUAL_FLAGS,
  &NTCreateSecurityFlagsFLAGSET,
  60 * 2,
  FormatPropertyInstance },

Note that this property uses the generic property formatter called FormatPropertyInstance, which takes a property and formats it.

Important In the preceding example, the PROPERTYINFO for the qualifier FLAGS must include text-formatting space for all of the lines of text. The 60 * 2 line shows two lines, 60 columns each. You must include in this estimate the space needed to format the bits. For example, if you have a LABELED_BIT on a BYTE, with a string of "My String", then the formatting is going to look something like "......1. = My String" and the length would be 11 characters plus the length of the string itself ("My String").

Next, at attach time, the property instance is added:

// File Create Security Flags flag set
AttachPropertyInstance(hFrame,
  property_table[PROP_NTCREATE_SECURITYFLAGSFLAGSET].hProperty,
  sizeof(reqptr->SecurityFlags),
  &reqptr->SecurityFlags,    // ptr to data
  SMBcreateX,        // Help ID
  PL_COMMAND+1,        // level
  0);          // error

The generic formatter will take this and build a multSZ string, where each string entry is separated by a \0 and the last entry ends with a double \0.


A BitSet

If you have a BYTE, WORD, or DWORD where each bit means something, then the BITSET is probably the data structure to use. Note that most people will not use the BITSET because you usually need to describe the bit on and the bit off case. Use the FLAGS qualifier if you need this functionality. If, however, you have a situation where each bit has an on and no description for an off, use the BITSET.


A Byte-Swapped Element

Byte swapping is used by the UNIX-style protocols such as TCP/IP, XNS, and IPX. The ordering of a WORD or DWORD is opposite of Intel convention. When creating the property, you should still use the property types of PROP_TYPE_WORD or PROP_TYPE_DWORD, but at attach time, label the instance of the property as swapped. (This is a change from the 1.0 SDK.) See AttachPropertyInstance and AttachPropertyInstanceEx for details on IFLAG_SWAPPED.


When to Use AttachPropertyInstanceEx

AttachPropertyInstanceEx should be used in cases where you cannot represent the data exactly as it appears in the frame. For example, the Ethernet frame length is not actually a field in the Ethernet frame, but it is a useful property to have. The parser writer for Ethernet can build a local word value representing the frame length and add it to the system with an AttachPropertyInstanceEx. Another example of when AttachPropertyInstanceEx becomes important is when the data does not fall into a byte or word. For example, the LLC Next Send and Next Receive correlators are bytes that do not use the first bit of the byte. To correctly represent this field, the LLC parser moves the data out of the frame into a local variable and shifts it to get the correct value. Then it adds the property with AttachPropertyInstanceEx. Another example of using AttachPropertyInstanceEx is when the data can be more easily used by the system in another format. See the Time example.


Time

Time is represented differently in every parser. If you want Network Monitor to be able to do a filter on your time field in a generic fashion, you must convert the field to the Win32 SystemTime value and do an AttachPropertyInstanceEx on it. For example, in the SMB parser case:

//////////////////////////////////////////////////////////////////
//
// attach_time2 - Attach a property whose data is an embedded
//      date/time dword.  Convert the date/time into a SYSTEMTIME
//      struct and call AttachPropertyInstanceEx().
//
// changed to use bitfields to fix bug
//////////////////////////////////////////////////////////////////

typedef struct _TIMECONVHIWORD {
   unsigned int Day  : 5;
   unsigned int Month  : 4;
   unsigned int Year  : 7;
   } TIMECONVHIWORD;

typedef struct _TIMECONVLOWORD {
   unsigned int Second  : 5;
   unsigned int Minute  : 6;
   unsigned int Hour   : 5;
   } TIMECONVLOWORD;

void attach_time2(HFRAME fhandle,
      WORD prop,
      DWORD * time,
      WORD cmd)
{
   SYSTEMTIME systime;
   TIMECONVLOWORD * lpLo = (LPVOID ) time;
            // get second one
   TIMECONVHIWORD * lpHi = (LPVOID ) &((WORD *)time)[1];

    systime.wYear    = lpHi->Year + 1980;
    systime.wMonth   = lpHi->Month;
    systime.wDay     = lpHi->Day;
    systime.wHour    = lpLo->Hour;
    systime.wMinute  = lpLo->Minute;
    systime.wSecond  = lpLo->Second * 2;

    systime.wDayOfWeek = 0;
    systime.wMilliseconds = 0;

    AttachPropertyInstanceEx(fhandle,
              property_table[prop].hProperty,
              sizeof(DWORD),
              time,
              sizeof(SYSTEMTIME),
              &systime,
              cmd,
              PL_COMMAND,
              0);
}


Arrays

An array is added by attaching a length greater than the size of the data type. For example, the SMB attaches byte data with a property that looks like:

// PROP_BYTE_DATA
    {   0,0,
  "Byte parameters",
  "Command specific byte parameters",
  PROP_TYPE_BYTE,
  PROP_QUAL_ARRAY,
  NULL,
  32,
  fm_property_name },

And the attach looks like:

AttachPropertyInstance(  fhandle,
        property_table[PROP_BYTE_DATA].hProperty,
        (WORD)(*bytecnt * sizeof(BYTE)),
        bytecnt + 1,
        cmd,
        PL_COMMAND,
        0);


Protocols That Resolve Network Names

Protocols that can identify the name of the computer sending or receiving the frame can resolve network names, but only in such a way that the friendly name is detached from the protocol. Detaching the friendly name from the protocol means that the parser adding the name is not required to know the protocols below it.

For example, when the Server Message Block (SMB) parser sees a session setup with a computer name in it, it should not have to know that TCP/IP was the protocol used to transport the SMB. If the SMB parser was coded to recognize the protocol, it would have to be recoded when a new low-level protocol (such as XNS or OSI) was used to transport SMBs.

The SMB parser should identify the friendly name as either a SourceFriendlyName or a DestinationFriendlyName and point only to the name, not the network identification. This allows the user interface (or some other component located above the parsing level) to associate the friendly name with the network identification address. Changing the user interface so that it understands OSI eliminates the problem of having to change the SMB parser.

Two property data types (PROP_TYPE_SRCFRIENDLYNAME and PROP_TYPE_DSTFRIENDLYNAME) have been added to the property types. A property of these data types is assumed to be an array of bytes that is null terminated (a string).

The following example shows how to use PROP_DST_FRIENDLYNAME:

// We have a path name that includes a server name. Extract the server
// name and attach it as a DestinationFriendlyName.
{

    char  * pStr;
    char    szName[50];

    if ( IsUnicode )
        strncpy ( szName, szPath+2, 17 );  // copy the converted unicode
        // string
    else
        strncpy ( szName, chptr+2, 17 );  // get at least one \ char

    // remove the last bytes.
    pStr = strchr ( szName, '\\' );
    *pStr = '\0';

    // Note that you should always deal with the friendly name as a
    // AttachPropertyInstanceEx() instead of a AttachPropertyInstance()
    // call. Even if the protocol has the friendly name terminated with
    // a null, the frame might be clipped.

    AttachPropertyInstanceEx(fhandle,
                 property_table[PROP_DST_FRIENDLYNAME].hProperty,
                 0,
                 NULL,
                 16,
                 szName,
                 SMBtconX,
                 15, 0);

}


The Summary Property

The Summary property is special in that it can be found by the user interface for special display. The property type attached is PROP_TYPE_SUMMARY. You can attach only one per protocol. The summary property should claim the same data size as the protocol so that when the user clicks on it in the detail window, it correctly highlights the hex data.


Sample Parser

//=================================================================
//  MODULE: ethernet.c
//
//  Description:
//
//  Network Monitor parer DLL for 802.3 (ETHERNET).
//
//  Modification History
//
//=================================================================

#include "mac.h"

//=================================================================
//  FUNCTION: RecognizeEthernetFrame()
//
//  Modification History
//
//=================================================================

LPBYTE BHAPI RecognizeEthernetFrame(
    HFRAME            hFrame,
    LPETHERNET        Frame,
    WORD              MacType,
    WORD              BytesLeft,
    LPRECOGNIZEDATA   lpRecognizeData,  // RecognizeData to fill in
    LPBYTE            lpEntriesAdded    // Increment by number of
                                        // entries added to
                                        // PropertyInstTable
)
{
    //=========================================================
    //  To verify that this frame is ethernet, we do the following:
    //
    //  1)  Make sure the MacType is MAC_TYPE_ETHERNET.
    //
    //  2)  Make sure the value of BytesLeft does not exceed the
    //      maximum ethernet frame size of 1514.
    //=========================================================

    if ( MacType == MAC_TYPE_ETHERNET && BytesLeft <=
                            ETHERNET_FRAME_LENGTH )
    {
        lpRecognizeData->hPropertyDB = hDatabase;
        lpRecognizeData->nProtocolOffset = (WORD)(Frame-Frame);
        (*lpEntriesAdded)++;
        return (LPBYTE) Frame->Info;
    }

    return (LPBYTE) Frame;             //...It's not ethernet!
}

//=============================================================
//  FUNCTION: AttachProperties()
//
//  Modification History
//
//=============================================================

LPBYTE BHAPI AttachEthernetProperties(HFRAME     hFrame,
                                      LPETHERNET Frame,
                                      WORD       MacType,
                                      WORD       BytesLeft)
{
    WORD EthernetTypeField, PropIndex, FrameLength;

    //============================================================
    //  Attach the summary, addresses, and frame length fields.
    //============================================================

    AttachPropertyInstance(hFrame,
                           pit[ETHERNET_SUMMARY].hProperty,
                           sizeof(ETHERNET), Frame,
                           0,0,0);

    AttachPropertyInstance(hFrame,
                           pit[ETHERNET_DST_ADDR].hProperty,
                           sizeof Frame->DstAddr, &Frame->DstAddr,
                           0,1,0);

    AttachPropertyInstance(hFrame,
                           pit[ETHERNET_SRC_ADDR].hProperty,
                           sizeof Frame->SrcAddr, &Frame->SrcAddr,
                           0,1,0);

    FrameLength = (WORD) GetFrameLength(hFrame);

    AttachPropertyInstanceEx(hFrame,
                             pit[ETHERNET_LENGTH].hProperty,
                             0,
                             NULL,
                             sizeof(WORD),
                             &FrameLength,
                             0,1,0);

    //============================================================
    //  Attach the length/type properties.
    //============================================================

    EthernetTypeField = XCHG(Frame->Type);

    PropIndex = ((EthernetTypeField <= ETHERNET_DATA_LENGTH) ?
                 ETHERNET_DATALENGTH : ETHERNET_TYPE);

    AttachPropertyInstanceEx(hFrame,
                             pit[PropIndex].hProperty,
                             sizeof Frame->Type,
                             &Frame->Type,
                             sizeof EthernetTypeField,
                             &EthernetTypeField,
                             0,1,0);

    return (LPBYTE) Frame->Info;
}

//===============================================================
//  FUNCTION: FormatType()
//===============================================================

VOID BHAPI FormatType(LPPROPERTYINST lpPropertyInst, HFRAME hFrame)
{
    register WORD  Etype = lpPropertyInst->lpPropertyInstEx->Word[0];
    register DWORD Length, i;

    //============================================================
    //  Format the "ETYPE = 0x600"
    //============================================================

    Length = wsprintf(lpPropertyInst->szPropertyText, "%s : 0x%.4X",
                      lpPropertyInst->lpPropertyInfo->Label, Etype, Etype);

    //=========================================================
    //  Now search for the etype in the Etype table and display
    //  the label if found.
    //=========================================================

    for(i = 0; i < EtypeSetSize; ++i)
    {
        if ( Etypes[i].Value == Etype )
        {
            Length = wsprintf(&lpPropertyInst->szPropertyText[Length],
                              " (%s)", Etypes[i].Label);

            return;
        }
    }
}

//====================================================
//  FUNCTION: FormatDataLength()
//
//  Modification History
//
//====================================================

VOID BHAPI FormatDataLength(LPPROPERTYINST lpPropertyInst, HFRAME hFrame)
{
    wsprintf(lpPropertyInst->szPropertyText,
             "%s : 0x%.4X (%u)",
             lpPropertyInst->lpPropertyInfo->Label,
             lpPropertyInst->lpPropertyInstEx->Word[0],
             lpPropertyInst->lpPropertyInstEx->Word[0]);

}


The Generic Formatter

The generic formatter should be used whenever possible. Using Network Monitor's formatting routines instead of writing your own will not only reduce the code size, but it will also allow for Network Monitor performance adjustments and fixups to porting problems for other platforms without impacting your parser.

Even if the generic formatter is not exactly what you need, you should still use the formatting routines that it calls if you must build your own string. For example, if you want to take the generic formatting routine's output for a WORD that looks like this:

Privilege ID   (PID) = 0x0029

and add something to the end of it to make it look like:

Privilege ID   (PID) = 0x0029   The Process has privileges

then you should call the format function that the Generic Formatter calls. In this case, you would call FormatPropertyDataAsWord and then append your string.

The following table shows how the generic formatter will format the different property types:

PROP_TYPE_VOID

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ"
PROP_QUAL_RANGE |
PROP_QUAL_BITFIELD |
PROP_QUAL_LABELED_SET |
PROP_QUAL_LABELED_BITFIELD |
PROP_QUAL_CONST |
PROP_QUAL_FLAGS |
PROP_QUAL_ARRAY |

PROP_TYPE_SUMMARY

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ"
PROP_QUAL_RANGE |
PROP_QUAL_BITFIELD |
PROP_QUAL_LABELED_SET |
PROP_QUAL_LABELED_BITFIELD |
PROP_QUAL_CONST |
PROP_QUAL_FLAGS |
PROP_QUAL_ARRAY |

PROP_TYPE_BYTE

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ = 10 (0xa)"
PROP_QUAL_RANGE | "XYZ = 10 (0xa) Range:(1 (0x1) - 20 (0x14))"
PROP_QUAL_BITFIELD
PROP_QUAL_LABELED_SET | Calls FormatLabeledSet function.
PROP_QUAL_LABELED_BITFIELD | Calls FormatLabeledSetAsFlags function.
PROP_QUAL_CONST | No output results.
PROP_QUAL_FLAGS ...0 = Label Off String
..1. = Label On String
.0.. = Label Off String
0... = Label Off String
PROP_QUAL_ARRAY | "XYZ = 00 0a ff ..."

PROP_TYPE_WORD

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ = 10 (0xa)"
PROP_QUAL_RANGE | "XYZ = 10 (0xa) Range:(1 (0x1) - 20 (0x14))
PROP_QUAL_BITFIELD | No output results.
PROP_QUAL_LABELED_SET | Calls FormatLabeledWordSet function.
PROP_QUAL_LABELED_BITFIELD | Calls FormatLabeledWordSetAsFlags function.
PROP_QUAL_CONST | No output results.
PROP_QUAL_FLAGS .......0 = Label Off String
......1. = Label On String
.....0.. = Label Off String
....0... = Label Off String
...1.... = Label On String
..0..... = Label Off String
.0...... = Label Off String
0....... = Label Off String
PROP_QUAL_ARRAY | "XYZ = 0000 000a ffff ..."

PROP_TYPE_DWORD

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ = 10 (0xa)"
PROP_QUAL_RANGE | "XYZ = 10 (0xa) Range:(1 (0x1) - 20 (0x14))
PROP_QUAL_BITFIELD
PROP_QUAL_LABELED_SET | Calls FormatLabeledDwordSet function.
PROP_QUAL_LABELED_BITFIELD | Calls FormatLabeledDwordSetAsFlags function.
PROP_QUAL_CONST | No output results.
PROP_QUAL_FLAGS ...............0 = Label Off String
..............1. = Label On String
.............0.. = Label Off String
............0... = Label Off String
...........1.... = Label On String
..........0..... = Label Off String
.........0...... = Label Off String
........0....... = Label Off String
(and so on)
PROP_QUAL_ARRAY | "XYZ = 00000000 0000000a ffffffff ..."

PROP_TYPE_LARGEINT

Property qualifier | Example output
PROP_QUAL_NONE PROP_QUAL_RANGE PROP_QUAL_BITFIELD PROP_QUAL_LABELED_SET PROP_QUAL_LABELED_BITFIELD PROP_QUAL_CONST PROP_QUAL_FLAGS PROP_QUAL_ARRAY | No output results.

PROP_TYPE_ADDR

Property qualifier | Example output
PROP_QUAL_NONE PROP_QUAL_RANGE PROP_QUAL_BITFIELD PROP_QUAL_LABELED_SET PROP_QUAL_LABELED_BITFIELD PROP_QUAL_CONST PROP_QUAL_FLAGS PROP_QUAL_ARRAY | No output results.

PROP_TYPE_TIME

Property qualifier | Example output
PROP_QUAL_NONE PROP_QUAL_RANGE PROP_QUAL_BITFIELD PROP_QUAL_LABELED_SET PROP_QUAL_LABELED_BITFIELD PROP_QUAL_CONST PROP_QUAL_FLAGS PROP_QUAL_ARRAY | Calls FormatPropertyDataAsTime function.

PROP_TYPE_STRING

Property qualifier | Example output
PROP_QUAL_NONE PROP_QUAL_RANGE PROP_QUAL_BITFIELD PROP_QUAL_LABELED_SET PROP_QUAL_LABELED_BITFIELD PROP_QUAL_CONST PROP_QUAL_FLAGS PROP_QUAL_ARRAY | "XYZ = String, which was attached as an AttachPropertyInstEx."

PROP_TYPE_IP_ADDRESS

Property qualifier | Example output
PROP_QUAL_NONE PROP_QUAL_RANGE PROP_QUAL_BITFIELD PROP_QUAL_LABELED_SET PROP_QUAL_LABELED_BITFIELD PROP_QUAL_CONST PROP_QUAL_FLAGS PROP_QUAL_ARRAY | "XYZ = 129.65.100.2"

PROP_TYPE_BYTESWAPPED_WORD

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ = 10 (0xa)"
PROP_QUAL_RANGE | "XYZ = 10 (0xa) Range:(1 (0x1) - 20 (0x14))
PROP_QUAL_BITFIELD | No output results.
PROP_QUAL_LABELED_SET | Calls FormatLabeledWordSet function.
PROP_QUAL_LABELED_BITFIELD | Calls FormatLabeledWordSetAsFlags function.
PROP_QUAL_CONST | No output results.
PROP_QUAL_FLAGS .......0 = Label Off String
......1. = Label On String
.....0.. = Label Off String
....0... = Label Off String
...1.... = Label On String
..0..... = Label Off String
.0...... = Label Off String
0....... = Label Off String
PROP_QUAL_ARRAY | "XYZ = 0000 000a ffff ..."

PROP_TYPE_BYTESWAPPED_DWORD

Property qualifier | Example output
PROP_QUAL_NONE | "XYZ = 10 (0xa)"
PROP_QUAL_RANGE | "XYZ = 10 (0xa) Range:(1 (0x1) - 20 (0x14))
PROP_QUAL_BITFIELD | No output results.
PROP_QUAL_LABELED_SET | Calls FormatLabeledDwordSet function.
PROP_QUAL_LABELED_BITFIELD | Calls FormatLabeledDwordSetAsFlags function.
PROP_QUAL_CONST | No output results.
PROP_QUAL_FLAGS ...............0 = Label Off String
..............1. = Label On String
.............0.. = Label Off String
............0... = Label Off String
...........1.... = Label On String
..........0..... = Label Off String
.........0...... = Label Off String
........0....... = Label Off String
(and so on)
PROP_QUAL_ARRAY | "XYZ = 00000000 0000000a ffffffff ..."

PROP_TYPE_OBJECT_IDENTIFIER

Property qualifier | Example output
PROP_QUAL_NONE | "OID = 1.3.6.1.2.1.1.3.0"

PROP_TYPE_VINES_IP_ADDRESS

Property qualifier | Example output
PROP_QUAL_NONE | "Address = 172345:52"

PROP_TYPE_VAR_LEN_SMALL_INT

Property qualifier | Example output
PROP_QUAL_NONE | "Version = 2"


MIPS

Windows NT supports the MIPS processor, as well as the DEC Alpha and others. For a parser to be MIPS-compliant, it must be careful about aligning its data structures. For example, if you have a structure that looks like:

{
    BYTE  b1;
    BYTE  b2;
    BYTE  b3;
    WORD  w1;
  ...} MyStruct;

  MyStruct *lpMyStruct;

or if the MyStruct structure is byte-aligned, you will run into trouble. If b1 is on a QUADWORD boundary, then the WORD w1 will be straddling the QUAD boundary and will cause an exception on a MIPS machine. For the internal data structures that the parser will use, you must always make sure that the data is QUAD-aligned.

The data that the parser is dealing with is another matter. You cannot force the data structure that defines a TCP/IP frame to be aligned in a MIPS-friendly format. There are two ways you can handle this. One is to move the data as an array of bytes into your WORD or DWORD structure before referencing it. Another, cleaner way to handle the problem is to let the compiler do it. For example, if you have a structure called MyParserOverlay that looks like this:

typedef struct _MyParserOverlay {
  BYTE  b1;
  BYTE  b2;
  BYTE  b3;
  WORD  w1;
} MyParserOverlay;

and you want to put this overlay on top of a stream of bytes that is part of a frame, the easy way is to define an unaligned pointer.

MyParserOveray UNALIGNED * lpMyParserOverlay = FramePointer;

The UNALIGNED keyword will allow you to reference w1 as follows:

if ( lpMyParserOverlay->w1 == 7)
...

The compiler at this point moves the bytes into a register a byte at a time and then compares the register to 7. The compiler knows whether the target build environment is big-endian or dword-aligned, and you no longer have to worry about it.

Also note that the Network Monitor code is written with the Intel platform as the target platform. You must tell the kernel when the data pointed at by a parser is byte-swapped. When Windows NT runs on a non-Intel format processor, the kernel takes care of not converting the byte-swapped values and converting the non-byte-swapped values. This implies that you should use the kernel default display formatters and specific formatters whenever possible. Changing the parser is not necessary.


Sample Applications for Network Monitor

The Microsoft® Platform SDK CD-ROM provides two sample protocol parser DLLs for Network Monitor. The source for these DLLs is in the \MSSDK\SAMPLES\SYSMGMT\SMS\NETMON directory.

BROWSER

The first sample, BROWSER, is an example of a shipping parser. In a Microsoft Network, when you NET VIEW, or (in Microsoft® Windows® 95) when you look at the Network Neighborhood, the information displayed is acquired through use of the Browser protocol. The Browser protocol follows the SMB protocol; the SMB protocol "hands off" or "packages" the Browser protocol.

The Browser protocol sample is a good place to start building your own protocol parser because it is a complete, high-quality program. The code calls almost every parser API exposed in the SDK, and it uses many of the data types defined for parser writers. It is an especially good source to see how a parser should acquire and format data.

The Browser parser DLL (BROWSER.DLL) is installed by the SMS setup program when you install the Network Monitor product. To use the parser, start Network Monitor and capture at least one buffer. To view the acquired data, set up a display filter for packets that contain the Browser protocol.

REMAPI

The second sample, REMAPI, is for parsing SMB Remote APIs. This sample provides all of the files needed to make a parser, and it demonstrates the five standard entry points that every parser must implement; however, it uses very few of the parser APIs. This sample could be used as a shell to build your own parser.

For more information see Writing a Protocol Parser DLL for Network Monitor.


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

Remedy: Insert the MSDN Library CD into the CD-ROM drive.