// ====================================================================
//
// File: attribut.cpp
//
// Copyright (C) 1994, 1995 Microsoft Corp.
//
// Author:
// Jonathan Shuval Microsoft Corp.
//
// This program illustrates possible uses of the following SMS APIs:
//
// SmsAPIVer
//
// SmsDataSourceConnect
// SmsDataSourceDisconnect
//
// SmsOpenContainer
// SmsSetFilter
// SmsPopulate
// SmsGetFolderCount
// SmsCloseContainer
// SmsGetNextFolder
//
// SmsCreateFilter
// SmsAddToken
// SmsCloseFilter
//
// SmsGetFolderType
// SmsGetFolderID
// SmsCloseFolder
// SmsGetScalarCount
// SmsGetNextScalar
//
//
// See the readme.txt file in this directory for a decription of this
// sample.
//
// ====================================================================
//
// ====================================================================
//
// Includes.
//
// ====================================================================
#include <afx.h>
#include <smsapi.h> // Header for the APIs.
#include <time.h> // For converting time scalars into strings.
// Include the GetStatusName function.
// -------------------------------------
#include "..\common\status.inc"
// ====================================================================
//
// Defines.
//
// ====================================================================
#define CCH_MAXINPUT 256 // Length for some string buffers.
// ====================================================================
//
// Globals.
//
// ====================================================================
HANDLE ghConnect; // Connection handle.
// ====================================================================
//
// Local prototypes.
//
// ====================================================================
// Set filters.
// -------------------------------------------------------------
BOOL setFilters( HANDLE hContainer );
// Displays folders (recursively).
// -------------------------------------------------------------
void DisplayFolder( DWORD ctFolder, HANDLE hFolder );
// Retrieves, decodes, and displays a folder's scalars.
// -------------------------------------------------------------
void DisplayScalars( HANDLE hFolder );
// Prompt the user for input and return the reply.
// -------------------------------------------------------------
void InputString( const char *pszMessage, char *pszResult );
// Connect to the SMS datasource.
// -------------------------------------------------------------
HANDLE ConnectToDatasource();
// Display the help message.
// -------------------------------------------------------------
void DisplayHelp();
// Display the greeting.
// -------------------------------------------------------------
void DisplayGreeting();
// Check if there was a request for help on the command line.
// -------------------------------------------------------------
BOOL DidRequestHelp( int argc, char **argv );
// Display an error message with its SMS status value.
// -------------------------------------------------------------
void DisplaySmsError( const char *pszMessage, SMS_STATUS stat );
// Get the string equivalence for an SMS status code.
// -------------------------------------------------------------
const char *GetStatusName( SMS_STATUS stat );
// ====================================================================
// The work starts here.
// ====================================================================
void main( int argc, char **argv )
{
// Check to see if this is a request to display the help
// screen. If so, display it. Otherwise, display a greeting
// banner.
// =========================================================
if (DidRequestHelp(argc, argv)) {
DisplayHelp();
return;
}
else {
DisplayGreeting();
}
SMS_STATUS stat; // Return from the APIs.
HANDLE hContainer; // Handle to a container.
// Get and display the SMS API version.
// ------------------------------------
char *pszVersion; // Receives pointer to the version string.
SmsAPIVer( &pszVersion ); // Get version
printf("Using %s\n", pszVersion); // and print it.
//===========================================
// Connect to the SMS datasource.
//===========================================
ghConnect = ConnectToDatasource();
if (ghConnect == NULL) {
return;
}
// Open the site container.
// ========================
stat = SmsOpenContainer( C_SITE, ghConnect, &hContainer );
if (stat != SMS_OK) {
DisplaySmsError("SmsOpenContainer failed", stat);
SmsDataSourceDisconnect( ghConnect );
return;
}
// Construct and apply filters.
// ============================
BOOL bRet = setFilters( hContainer );
if (!bRet) {
// Error message already displayed, but give a general one as well.
printf("Problem with setting filters.\n");
SmsDataSourceDisconnect( ghConnect );
return;
}
// Select all folders matching our filters.
// ========================================
stat = SmsPopulate( hContainer, POP_SYNC, NULL );
if (stat != SMS_OK) {
DisplaySmsError("Bad return from SmsPopulate", stat);
SmsCloseContainer( hContainer );
SmsDataSourceDisconnect( ghConnect );
return;
}
printf("======== Enumerating site hierarchy =============\n");
// For each folder in the list enumerate its properties.
// What we do is open all folders in a loop and then
// close the container. The open container causes ALL
// folders to be left open until the container closes.
// -----------------------------------------------------
CObArray topFolders;
HANDLE hFolder;
// Open all top-level folders.
// ===========================
while ((stat = SmsGetNextFolder( hContainer, F_ANY, &hFolder )) == SMS_OK) {
// Store the folder's handle for later processing.
// -----------------------------------------------
topFolders.Add( (CObject *)hFolder );
}
printf("*** Retrieved %d folders ***\n", topFolders.GetSize());
// Check why we exited the loop.
// -----------------------------
if (stat != SMS_NO_MORE_DATA) {
DisplaySmsError("Failed to retrieve folder", stat);
}
// Close the container.
// --------------------
SmsCloseContainer( hContainer );
// Now (recursively) process each top-level folder.
// ================================================
for (int iLoop = 0; iLoop < topFolders.GetSize(); iLoop++) {
// Retrieve the handle.
// --------------------
hFolder = (HANDLE)topFolders[iLoop];
printf("*** Top folder #%d\n", iLoop);
// Display the folder.
// -------------------
DisplayFolder( iLoop, hFolder );
// Note: the folder is closed inside DisplayFolder.
}
printf("********* All done ***************\n");
stat = SmsDataSourceDisconnect( ghConnect );
} /* main */
// ====================================================================
//
// DisplayFolder
//
// Display the folder's details and scalars, then recursively process
// any sub-folders.
//
// Parameters:
// DWORD ctFolder
// The number of sub-folders at this level of the container/folder
// hierarchy.
//
// HANDLE hFolder
// The handle of the folder to display.
//
// Returns: Nothing.
//
// ====================================================================
// Simple macro for checking status.
#define CHKSTAT(str) if (stat != SMS_OK && stat != SMS_MORE_DATA) { \
printf(str); printf(": %d\n", stat); \
return; }
void DisplayFolder( DWORD ctFolder, HANDLE hFolder )
{
SMS_STATUS stat;
HANDLE hSubFolder;
DWORD fType; // type of folder we're dealing with.
char szfType[30]; // type as a string.
DWORD totFolders; // Total number of sub-folders of
// all types.
char szFolderID[100]; // This folder's ID.
DWORD ctScalars; // How many scalars in this folder.
// Get object type and id.
// -----------------------
stat = SmsGetFolderID( hFolder, szFolderID );
CHKSTAT("SmsGetFolderID");
stat = SmsGetFolderType( hFolder, &fType, szfType );
CHKSTAT("SmsGetFolderType");
printf("===================================================\n");
printf("[%d] Folder %s is a %s\n", ctFolder, szFolderID, szfType);
// How many scalars and folders in this folder.
// --------------------------------------------------------
stat = SmsGetScalarCount( hFolder, &ctScalars );
stat = SmsGetFolderCount( hFolder, F_ANY, &totFolders );
printf("\tContains %d scalars and %d folders\n", ctScalars, totFolders);
DisplayScalars( hFolder );
// Allocate space for sub-folder handles.
// --------------------------------------
CObArray subFolders;
subFolders.SetSize( totFolders );
// This loop gets the sub-folder IDs and displays them.
// ====================================================
char szSubFolderID[100];
DWORD ctFolders;
for (ctFolders = 0; ctFolders < totFolders; ctFolders++) {
// Get a handle to a sub-folder.
// -----------------------------
stat = SmsGetNextFolder( hFolder, F_ANY, &hSubFolder );
CHKSTAT("SmsGetNextFolder");
subFolders.SetAt( ctFolders, (CObject *)hSubFolder );
// Get and display the sub-folder's ID.
// ------------------------------------
stat = SmsGetFolderID( hSubFolder, (char *)szSubFolderID );
CHKSTAT("SmsGetFolderID");
printf("Sub-folder #%d: %s\n", ctFolders, szSubFolderID);
}
// =======================================================
// We can now release the handle that was passed in to us.
// If we wait until the function returns then, because we
// recurse, we don't release it till the very end.
// =======================================================
SmsCloseFolder( hFolder );
// This loop gets the sub-folders and displays them.
// =================================================
for (ctFolders = 0; ctFolders < totFolders; ctFolders++) {
hSubFolder = (HANDLE)subFolders[ctFolders];
DisplayFolder( ctFolders, hSubFolder );
}
// Free the folder handle array.
// -----------------------------
subFolders.RemoveAll();
} /* DisplayFolder */
// ====================================================================
//
// DisplayScalars
//
// Display all the scalars for the folder.
//
// Parameters:
// HANDLE hFolder
// This is the folder handle. Display this folder's scalars.
//
// Returns: Nothing.
//
// ====================================================================
#define MY_BUFF_SIZE 100 // Buff size for strings and binaries.
// NOTE: this is deliberately set lower than the maximum (SMS_DATA_BUFF_SIZE).
// By doing this we can exercise the code for checking if the buffer is too
// small for the data (see 'Check for buffer being too small' below).
void DisplayScalars( HANDLE hFolder )
{
SMS_STATUS stat = SMS_OK;
SCALAR scalar;
char szName[50]; // buffer for name
char szValue[MY_BUFF_SIZE]; // buffer for value
BYTE byValue[MY_BUFF_SIZE]; // Buffer for binary scalars.
scalar.pszName = szName;
scalar.pszValue = szValue;
scalar.pValue = byValue;
char *pszTime; // For time scalars.
CTime tTime; // ditto
CString sTime; // ditto
while (1) {
scalar.dwLen = MY_BUFF_SIZE-1; // must tell him the size
stat = SmsGetNextScalar( hFolder, &scalar);
if (stat != SMS_OK && stat != SMS_MORE_DATA) {
break;
}
// Check for buffer being too small.
// ---------------------------------
if (stat == SMS_MORE_DATA) {
printf("Receive buffer too small, should be %d. Data truncated\n",
scalar.dwLen);
// NOTE: at this point we could retrieve the scalar by name
// after allocating a larger buffer.
}
// Check scalar type, display accordingly.
// ---------------------------------------
switch (scalar.scType) {
case SCALAR_STRING:
printf("\t%25s (string): %s\n", scalar.pszName, scalar.pszValue);
break;
case SCALAR_INT:
printf("\t%25s (Integer): %ld\n", scalar.pszName, scalar.dwValue);
break;
case SCALAR_TIME:
// Check if we have a string equivalence. If so use it.
if (scalar.bStringEquivalence) {
pszTime = scalar.pszValue;
} else {
// Use time functions to make a string out of it.
// NOTE: we really need to get rid of trailing newline.
tTime = scalar.tValue;
sTime = tTime.Format( "%m/%d/%y %I:%M %p" );
pszTime = (char *)(const char *)sTime;
}
printf("\t%25s (time): %s", scalar.pszName, pszTime);
break;
case SCALAR_BINARY:
// In this sample we won't display the binary data.
// Just tell the user its size.
printf("\t%25s (Binary - this is its size): %ld\n", scalar.pszName, scalar.dwLen);
break;
}
}
// Why did we exit (other than no more scalars)?
// ---------------------------------------------
if (stat != SMS_NO_MORE_DATA) {
DisplaySmsError("Bad return from Scalar access: %d\n", stat);
}
// Terminate with newline.
// -----------------------
printf("\n");
}
// ********************************************************************
// Helper functions.
// ********************************************************************
// ====================================================================
//
// setFilters
//
// Create a new filter and apply it to the specified container.
//
// Parameters:
// HANDLE hContainer
// This is the handle of the container to which the filter
// will be applied to.
//
// Returns:
// BOOL
// TRUE if no errors occcured, otherwise FALSE.
//
// ====================================================================
#define CHECK(str) if (stat != SMS_OK) { \
DisplaySmsError(str, stat); \
return(FALSE); \
}
BOOL setFilters( HANDLE hContainer )
{
printf("This test will set the following filters:\n");
printf(" Site filter: RootSite\n");
printf("Architecture filter: Personal Computer\n");
printf(" Attribute filter: (MS|ID|1.0) Name\n");
printf(" : (MS|ID|1.0) SMSLocation\n");
printf(" : (MS|ID|1.0) NetCardID\n");
SMS_STATUS stat;
HANDLE hFilter;
TOKEN Token;
// Define a filter: root site.
// ----------------------------------
memset( &Token, 0, sizeof(TOKEN) ); // Clear it.
stat = SmsCreateFilter( SITE_FILTER, ghConnect, &hFilter );
strcpy( Token.szName, "RootSite" );
stat = SmsAddToken( hFilter, OP_OR, &Token, -2 );
CHECK("SmsAddToken (site)");
stat = SmsSetFilter( hContainer, hFilter );
SmsCloseFilter( hFilter );
CHECK("SmsSetFilter (site)");
// =========================================================
// Must set an architecture filter else we get no machines.
// =========================================================
memset( &Token, 0, sizeof(TOKEN) ); // Clear it.
stat = SmsCreateFilter( ARCHITECTURE_FILTER, ghConnect, &hFilter );
strcpy( Token.szName, "Architecture" );
strcpy( Token.szValue, "Personal Computer" );
Token.dwOp = QOP_STR_EQ;
stat = SmsAddToken( hFilter, OP_OR, &Token, -2 );
CHECK("SmsAddToken (architecture)");
stat = SmsSetFilter( hContainer, hFilter );
SmsCloseFilter( hFilter );
CHECK("SmsSetFilter (architecture)");
// =========================================================
// Attribute filter (MICROSOFT|IDENTIFICATION|1.0)
// Three tokens:
// Name
// SMSLocation
// NetCardID
// =========================================================
memset( &Token, 0, sizeof(TOKEN) ); // Clear it.
stat = SmsCreateFilter( ATTRIBUTE_FILTER, ghConnect, &hFilter );
strcpy( Token.szArchitecture, "Personal Computer" );
strcpy( Token.szGroupClass, "MICROSOFT|IDENTIFICATION|1.0" );
strcpy( Token.szAttributeName, "Name" );
stat = SmsAddToken( hFilter, OP_OR, &Token, -2 );
CHECK("SmsAddToken (attribute:name)");
strcpy( Token.szAttributeName, "SMSLocation" );
stat = SmsAddToken( hFilter, OP_OR, &Token, -2 );
CHECK("SmsAddToken (attribute:Location)");
strcpy( Token.szAttributeName, "NetCardID" );
stat = SmsAddToken( hFilter, OP_OR, &Token, -2 );
CHECK("SmsAddToken (attribute:NetCardID)");
stat = SmsSetFilter( hContainer, hFilter );
SmsCloseFilter( hFilter );
CHECK("SmsSetFilter (attribute)");
return( TRUE );
} /* setFilters */
// ====================================================================
//
// InputString
//
// Prompt the user to input a string and return the string in the
// specified buffer.
//
// Parameters:
// const char *pszMessage
// The user prompt to display.
//
// char *pszResult
// Pointer to the buffer where the user's input will be returned.
//
// Returns;
// The user's input is returned via the given buffer.
//
// ====================================================================
void InputString( const char *pszMessage, char *pszResult )
{
printf("%s: ", pszMessage);
gets(pszResult);
}
// ====================================================================
//
// ConnectToDatasource
//
// Get the datasource connection information from the user and use it
// to connect to the datasource.
//
// Parameters: None.
//
// Returns:
// The connection handle or NULL if the connection failed.
//
// ====================================================================
HANDLE ConnectToDatasource()
{
// Get the information we need to connect to the
// data source from the user.
//==============================================
char szServer[CCH_MAXINPUT];
char szUser[CCH_MAXINPUT];
char szPasswd[CCH_MAXINPUT];
char szDatabase[CCH_MAXINPUT];
printf("\n");
printf("**************************\n");
printf("* Connect to data source *\n");
printf("**************************\n");
InputString("SQL server name", szServer);
InputString("SQL database name", szDatabase);
InputString("User name for SQL server", szUser);
InputString("Password for SQL server", szPasswd);
printf("\n");
// Connect to a data source. SQL in this case.
// ===========================================
DATASOURCE dsParams;
dsParams.sqlParams.ds = DB_SQL;
dsParams.sqlParams.pszServer = szServer;
dsParams.sqlParams.pszUserName = szUser;
dsParams.sqlParams.pszPasswd = szPasswd;
dsParams.sqlParams.pszDbName = szDatabase;
dsParams.sqlParams.pFunc = NULL; // No encryption.
dsParams.sqlParams.pszKey = "";
HANDLE hConnect;
SMS_STATUS stat;
stat = SmsDataSourceConnect( &dsParams, &hConnect);
if (stat != SMS_OK) {
hConnect = NULL;
DisplaySmsError("Connect to data source failed", stat);
}
return( hConnect );
}
// ====================================================================
//
// DidRequestHelp
//
// Check the program's arguments to see if the user asked for
// the help screen to be displayed.
//
// Parameters:
// int argc
// The argc value from main(argc, argv)
//
// char **argv
// The argv value from main(argc, argv)
//
// Returns:
// TRUE if command line parameters included a request
// for help to be displayed.
//
// ====================================================================
BOOL DidRequestHelp( int argc, char **argv )
{
if (argc == 2 && (strcmp(argv[1], "-help") == 0)) {
return( TRUE );
}
else {
return( FALSE );
}
}
// ====================================================================
//
// DisplayHelp
//
// This function displays the samples help screen.
//
// Parameters:
// None
//
// Returns:
// Nothing.
//
// ====================================================================
void DisplayHelp()
{
printf("\n\n");
printf("***********************************************************\n");
printf("* attribut.exe: *\n");
printf("* *\n");
printf("* SMS API Example: Test attribute filters. *\n");
printf("* *\n");
printf("* This sample illustrates the use of the Attribute filter *\n");
printf("* that is applied to a site container in order to *\n");
printf("* enumerate specified properties of a machine *\n");
printf("* (architecture Personal Computer). *\n");
printf("* *\n");
printf("* Applying an attribute filter in order to enumerate *\n");
printf("* machines is considerably faster than setting group *\n");
printf("* filters and then retrieving specified machine group *\n");
printf("* scalars (machine properties). *\n");
printf("* *\n");
printf("* Syntax: *\n");
printf("* attribut.exe [-help] *\n");
printf("* *\n");
printf("* Switches: *\n");
printf("* -help Display this help message. *\n");
printf("* *\n");
printf("***********************************************************\n");
printf("\n");
}
// ====================================================================
//
// DisplayGreeting
//
// Display the initial greeting banner.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
// ====================================================================
void DisplayGreeting()
{
// For this sample, the greeting is identical to the help screen.
//===============================================================
DisplayHelp();
}
/* EOF: attribut.cpp */