/*********************************************************************************************

Copyright (c) Microsoft Corporation
 
Module Name: 
    
    LoggingData.cpp

Abstract:
    
    Collects and displays all the data related with the logging option.     
 
Author:
    
    Wipro Technologies.
    
Revision History:

    22-Feb-2001 : Created It.

*********************************************************************************************/ 

#include "pch.h"
#include "GpResult.h"
#include "WMI.h"

// Local function prototypes
BOOL GetDomainType( LPTSTR lpszDomainName, BOOL * pbW2K, BOOL *pbLocalAccount );
BOOL RsopDeleteMethod( IWbemClassObject *pClass, CHString strNameSpace, 
                                        IWbemServices *pNamespace );
VOID DisplayLinkSpeed( IWbemServices *pNameSpace, COAUTHIDENTITY *pAuthIdentity );
VOID SortAppliedData( TARRAY arrAppliedData );

/*********************************************************************************************
Routine Description:

    This function is the main entry point for collecting and displaying the data for logging mode
     
Arguments:
 
    None

Return Value:
 
    TRUE  on SUCCESS
    FALSE on ERROR
*********************************************************************************************/
BOOL  CGpResult::GetLoggingData()
{
    // Local declarations
    BOOL        bResult = FALSE;
    BOOL        bAllUsers = TRUE;

    DWORD       dwBufferSize = MAX_STRING_LENGTH;
    DWORD       dwPosition = -1;

    // Connect to wmi...connecting to 'cimv2' and saving the pointer in a member variable
    bResult = ConnectWmiEx( m_pWbemLocator, &m_pWbemServices, m_strServerName,
                            m_strUserName, m_strPassword, &m_pAuthIdentity, 
                            m_bNeedPassword, ROOT_NAME_SPACE, &m_bLocalSystem );
        
    if( bResult == FALSE )
    {
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );
        return FALSE;
    }

    // check the remote system version and its compatiblity
    if ( m_bLocalSystem == FALSE )
    {
        // check the version compatibility
        DWORD dwVersion = 0;
        dwVersion = GetTargetVersionEx( m_pWbemServices, m_pAuthIdentity );
        
        // Check for the version W2K = 5000 and WindowsXP = 5001
        if ( dwVersion <= VERSION_CHECK )
        {
            // Display the appropriate error message
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, ERROR_OS_INCOMPATIBLE );
            return FALSE;
        }
    }

    // Set the password to the one got in the AUTHIDENTITY structure
    if( m_pAuthIdentity != NULL )
    {
        m_pwszPassword = m_pAuthIdentity->Password;
    }

    // check if it is the local system and the user credentials are specified....
    // if so display a warning message
    if( ( m_bLocalSystem == TRUE ) && ( m_strUserName.GetLength() != 0 ) )
    {
        ShowMessage( stdout, GetResString( IDS_WARNING ) );
        ShowMessage( stdout, GetResString( IDS_WARN_LOCAL ) );
        ShowMessage( stdout, NEW_LINE );

        // set the user name and password to NULL
        m_strUserName = L"";
        m_pwszPassword = NULL;

        // Get the new screen co-ordinates
        if ( m_hOutput != NULL )
        {
            GetConsoleScreenBufferInfo( m_hOutput, &m_csbi );
        }
    }
    
    // Connection part is over...check wether the user,for whom the RSOP data
    // has to be got has been specified.
    if( m_strUser.GetLength() == 0 )
    {
        // user is not specified....get the current logged on user
        LPWSTR pwszUserName = NULL;
        try
        {
            pwszUserName = m_strUser.GetBufferSetLength( dwBufferSize );
        }
        catch( ... )
        {
            // display the error message
            SetLastError( E_OUTOFMEMORY );
            SaveLastError();
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetReason() );
        }

        if ( GetUserNameEx( NameSamCompatible, pwszUserName, &dwBufferSize ) == FALSE )
        {
            // error occured while trying to get the current user info
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            return FALSE;
        }

        // Release the buffer
        m_strUser.ReleaseBuffer();
    }

    // Separating the domain name from the user name for whom the data has to be retrieved
    if( m_strUser.Compare( TEXT_WILD_CARD ) != 0 )
    {
        bAllUsers = FALSE;
        dwPosition = m_strUser.Find( SLASH );
        try
        {
            if( dwPosition != -1 )
            {
                m_strDomainName = m_strUser.Left( dwPosition );
                m_strUser = m_strUser.Mid( ( dwPosition + 1 ), m_strUser.GetLength() );
            }
            else
            {
                // Try for the name@domain format (UPN format)
                dwPosition = m_strUser.Find( SEPARATOR_AT );
                if( dwPosition != -1 )
                {
                    m_strDomainName = m_strUser.Mid( ( dwPosition + 1 ), m_strUser.GetLength() );
                    m_strUser = m_strUser.Left( dwPosition );
                }

                // Remove the unwanted things in the domain name
                dwPosition = m_strDomainName.Find( SEPARATOR_DOT );
                if( dwPosition != -1 )
                {
                    m_strDomainName = m_strDomainName.Left( dwPosition );
                }
            }
        }
        catch( ... )
        {
            // display the error message
            SetLastError( E_OUTOFMEMORY );
            SaveLastError();
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetReason() );
        }
    }

    PrintProgressMsg( m_hOutput, GetResString( IDS_USER_DATA ), m_csbi );

    //
    // Start the retrieval of information....
    // Get the user information
    if( GetUserData( bAllUsers ) == FALSE )
    {
        return FALSE;
    }

    return TRUE;
}

/*********************************************************************************************
Routine Description:

     This function displays the non verbose data
     
Arguments:
 
    [in] USERINFO           :   pointer to the user information structure
    [in] IWBEMSERVICES      :   pointer to the namespace
    
Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::DisplayData( PUSERINFO pUserInfo, IWbemServices *pRsopNameSpace )
{
    // local variables
    HRESULT                     hResult = S_OK;

    BOOL                        bResult = FALSE;
    BOOL                        bCreatedRsop = FALSE;

    ULONG                       ulReturn = 0;
    DWORD                       dwi = 0;
    DWORD                       dwj = 0;
    DWORD                       dwMutex = 0;

    CHString                    strTemp;
    CHString                    strNameSpace;
    BSTR                        bstrTemp = NULL;
    
    IWbemClassObject            *pClass = NULL;
    IWbemClassObject            *pInClass = NULL;
    IWbemClassObject            *pInInst = NULL;
    IWbemClassObject            *pOutInst = NULL;
    IWbemServices               *pNameSpace = NULL;
    IEnumWbemClassObject        *pRsopClass = NULL;

    WCHAR                       szMutexName[512] = MUTEX_NAME;

    try
    {
        if( pUserInfo == NULL || pRsopNameSpace == NULL )
        {
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );

            _com_issue_error( STG_E_UNKNOWN );
        }
    
        PrintProgressMsg( m_hOutput, GetResString( IDS_GET_PROVIDER ), m_csbi );

        // Get the object for the RSOP diagnostic mode provider
        hResult = pRsopNameSpace->GetObject( _bstr_t( CLS_DIAGNOSTIC_PROVIDER ),
                                                0, NULL, &pClass, NULL );
        CHECK_HRESULT_EX( hResult );
        
        PrintProgressMsg( m_hOutput, GetResString( IDS_GET_METHOD ), m_csbi );

        // get the reqd. method....create an rsop session
        hResult = pClass->GetMethod( _bstr_t( FN_CREATE_RSOP ), 0, &pInClass, NULL );
        CHECK_HRESULT_EX( hResult );

        // spawn the instances....get a new instance of the provider
        hResult = pInClass->SpawnInstance( 0, &pInInst );
        CHECK_HRESULT_EX( hResult );
        
        // Put the user SID...
        PrintProgressMsg( m_hOutput, GetResString( IDS_PUT_SID ), m_csbi );

        hResult = PropertyPut( pInInst, CPV_USER_SID, pUserInfo->strUserSid );
        CHECK_HRESULT_EX( hResult );

        hResult = PropertyPut( pInInst, CPV_FLAGS, FLAG_FORCE_CREATENAMESPACE );
        CHECK_HRESULT_EX( hResult );

        PrintProgressMsg( m_hOutput, GetResString( IDS_WAIT ), m_csbi );
        
        // We are ready to call the method to create a session
        // Check on the mutex to see if the call can be executed
        lstrcat( szMutexName, L"_");
        strTemp = pUserInfo->strUserName;
        LONG lPos = strTemp.Find(TEXT_BACKSLASH);
        if( lPos >= 0 && lPos <= strTemp.GetLength() )
        {
            strTemp.SetAt(lPos, L'_' );
        }

        lstrcat( szMutexName, strTemp );
        if( FALSE == CreateRsopMutex( szMutexName ) )
        {
            ShowMessage(stdout, GetResString(IDS_INFO) );
			SetLastError( ERROR_RETRY );
			ShowLastError( stdout );

            // release the interface pointers and exit
            SAFEIRELEASE( pRsopClass );
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pInClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );

            return TRUE;
        }
        dwMutex = WAIT_FAILED;
        if( NULL == m_hMutex )
        {
           PrintProgressMsg( m_hOutput, NULL, m_csbi );

            ShowMessage(stdout, GetResString(IDS_INFO) );
			SetLastError( ERROR_SINGLE_INSTANCE_APP );
			ShowLastError( stdout );

            // release the interface pointers and exit
            SAFEIRELEASE( pRsopClass );
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pInClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );

            return TRUE;
        }
        if( m_hMutex != NULL )
        {
            dwMutex = WaitForSingleObject( m_hMutex, INFINITE );
            if( dwMutex == WAIT_FAILED )
            {
                SaveLastError();
                ShowMessage( stderr, GetResString(IDS_ERROR) );
                ShowMessage( stderr, GetReason() );
            }
        }

        if( dwMutex != WAIT_FAILED )
        {
            // Print the progress message
            strTemp.Format( GetResString( IDS_CREATE_SESSION ), pUserInfo->strUserName );
            PrintProgressMsg( m_hOutput, strTemp, m_csbi );

            // All The required properties are set, so...execute method RSopCreateSession
            hResult = pRsopNameSpace->ExecMethod( _bstr_t( CLS_DIAGNOSTIC_PROVIDER ), 
                                                    _bstr_t( FN_CREATE_RSOP ), 
                                                    0, NULL, pInInst, &pOutInst, NULL);
        }
        if( pOutInst == NULL )
        {
            hResult = E_FAIL;   
        }
        if( FAILED( hResult ) )
        {
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );

            // display the error message
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            // release the interface pointers and exit
            SAFEIRELEASE( pRsopClass );
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pInClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );

            //release the object
            ReleaseMutex( m_hMutex );
        
            return FALSE;
        }
        
        // Get the result value...
        bResult = PropertyGet( pOutInst, FPR_RETURN_VALUE, ulReturn, 0 );
        CHECK_BRESULT( bResult );

        if( ulReturn != 0 )
        {
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );

            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            // release the interface pointers and exit
            SAFEIRELEASE( pRsopClass );
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pInClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );

            ReleaseMutex( m_hMutex );

            return FALSE;
        }

        // set the flag to indicate that the namespace has been created.
        bCreatedRsop = TRUE;

        // Get the resultant RSOP name space
        bResult = PropertyGet( pOutInst, FPR_RSOP_NAME_SPACE, strTemp, V_NOT_AVAILABLE );
        CHECK_BRESULT( bResult );

        // Check if we have got the output
        if( lstrcmp( strTemp, V_NOT_AVAILABLE ) == 0 )
        {
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );

            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            // release the allocated variables
            SAFEIRELEASE( pRsopClass );
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pInClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );
            
            ReleaseMutex( m_hMutex );

            return FALSE;
        }

        // Got the data so start displaying
        // Display the information common to both scopes
        DisplayCommonData( pUserInfo );

        // Get the string starting with 'R'...as that's where the RSOP namespace starts
        // This is done to remove the '\'s in the beginning of the string returned.
        lPos = 0;
        strTemp.MakeLower();
        lPos = strTemp.Find( START_NAMESPACE );
        if ( lPos != -1 )
        {
            strTemp = strTemp.Mid( lPos + 1 );
        }
        else
        {
            _com_issue_error( STG_E_UNKNOWN );
        }

        // check if the computer information has to be displayed
        if( (m_dwScope == SCOPE_COMPUTER) || (m_dwScope == SCOPE_ALL) )
        {
            // connect to the resultant name space (computer)
            strNameSpace = strTemp + TEXT_BACKSLASH + TEXT_SCOPE_COMPUTER;

            ConnectWmi( m_pWbemLocator, &pNameSpace, m_strServerName, 
                        m_strUserName, m_pwszPassword, &m_pAuthIdentity,
                        FALSE, strNameSpace, &hResult );
            CHECK_HRESULT( hResult );

            // get the link speed information
            DisplayLinkSpeed( pNameSpace, m_pAuthIdentity );

            // Display the heading for the scope Computer
            ShowMessage( stdout, GetResString( IDS_GPO_COMPUTER ) );
            ShowMessage( stdout, NEW_LINE );
            for( dwi = lstrlen( GetResString( IDS_GPO_COMPUTER ) ); dwi > 1; dwi-- )
            {
                ShowMessage( stdout, GetResString( IDS_DASH ) );
            }
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );

            // Display the FQDN for the computer
            ShowMessage( stdout, pUserInfo->strComputerFQDN );
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );

            // Display the link speed threshold value for the computer
            DisplayThresholdSpeedAndLastTimeInfo( TRUE );

            // Display the heading for the Computer GPO's
            ShowMessage( stdout, GetResString( IDS_GPO_DISPLAY ) );
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );
            for( dwi = lstrlen( GetResString( IDS_GPO_DISPLAY ) ); dwi > 4; dwi-- )
            {
                ShowMessage( stdout, GetResString( IDS_DASH ) );
            }
            ShowMessage( stdout, GetResString( IDS_NEWLINE ) );

            // Display the GPO data for computer
            GpoDisplay( pNameSpace, TEXT_SCOPE_COMPUTER );

            // Display the security groups for the system
            DisplaySecurityGroups( pNameSpace, TRUE );

            // check wether the verbose option is specified
            if( m_bVerbose == TRUE || m_bSuperVerbose == TRUE )
            {
                // display the verbose computer information
                DisplayVerboseComputerData( pNameSpace );
            }

            // release the interface pointer
            SAFEIRELEASE( pNameSpace );
        }

        // check for user...
        if( (m_dwScope == SCOPE_USER) || (m_dwScope == SCOPE_ALL) )
        {
            // connect to the resultant name space (user)
            strNameSpace = strTemp + TEXT_BACKSLASH + TEXT_SCOPE_USER;

            ConnectWmi( m_pWbemLocator, &pNameSpace, m_strServerName, 
                        m_strUserName, m_pwszPassword, &m_pAuthIdentity,
                        FALSE, strNameSpace, &hResult );
            CHECK_HRESULT( hResult );

            // if only the user scope has been specified then the link speed 
            // information has not yet been displayed...display it
            if( m_dwScope == SCOPE_USER )
            {
                // Get the link speed information
                DisplayLinkSpeed( pNameSpace, m_pAuthIdentity );
            }

            // Display the heading for the scope User
            ShowMessage( stdout, GetResString( IDS_GPO_USER ) );
            ShowMessage( stdout, NEW_LINE );
            for( dwi = lstrlen( GetResString( IDS_GPO_USER ) ); dwi > 1; dwi-- )
            {
                ShowMessage( stdout, GetResString( IDS_DASH ) );
            }
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );

            // Display the FQDN for the computer
            ShowMessage( stdout, pUserInfo->strUserFQDN );
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );

            // Display the link speed threshold value for the user
            DisplayThresholdSpeedAndLastTimeInfo( FALSE );

            // Display the heading for the User GPO's
            ShowMessage( stdout, GetResString( IDS_GPO_DISPLAY ) );
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );
            for( dwi = lstrlen( GetResString( IDS_GPO_DISPLAY ) ); dwi > 4; dwi-- )
            {
                ShowMessage( stdout, GetResString( IDS_DASH ) );
            }
            ShowMessage( stdout, GetResString( IDS_NEWLINE ) );

            // Display the GPO data for user
            GpoDisplay( pNameSpace, TEXT_SCOPE_USER );

            // Display the security groups for the user
            DisplaySecurityGroups( pNameSpace, FALSE );

            // check wether the verbose option is specified
            if( m_bVerbose == TRUE || m_bSuperVerbose == TRUE )
            {
                // display the verbose computer information
                DisplayVerboseUserData( pNameSpace );
            }

            // release the interface pointer
            SAFEIRELEASE( pNameSpace );
        }
        
        // Delete the namespace created
        if( RsopDeleteMethod( pClass, strTemp, pRsopNameSpace ) == FALSE )
        {
            // release the allocated variables
            SAFEIRELEASE( pRsopNameSpace );
            SAFEIRELEASE( pRsopClass );
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pInClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );
            ReleaseMutex( m_hMutex );
            return FALSE;
        }
    }
    catch(  _com_error & error )
    {
        // display the error message
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // Delete the name space if it has been created.
        if( bCreatedRsop == TRUE )
        {
            RsopDeleteMethod( pClass, strNameSpace, pRsopNameSpace );
        }

        // release the interface pointers and exit
        SAFEIRELEASE( pRsopClass );
        SAFEIRELEASE( pClass );
        SAFEIRELEASE( pInClass );
        SAFEIRELEASE( pInInst );
        SAFEIRELEASE( pOutInst );
        
        ReleaseMutex( m_hMutex );
        return FALSE;
    }

    ReleaseMutex( m_hMutex );

    // release the interface pointers and exit
    SAFEIRELEASE( pRsopClass );
    SAFEIRELEASE( pClass );
    SAFEIRELEASE( pInClass );
    SAFEIRELEASE( pInInst );
    SAFEIRELEASE( pOutInst );
    
    return TRUE;
}

/*********************************************************************************************
Routine Description:

    This function gets the user data and fills the structure with the same
     
Arguments:
 
    [in] BOOL   bAllUsers       :   Specifies that the Rsop data has to be retrieved
                                    for all the users.

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::GetUserData( BOOL bAllUsers )
{
    // Local variables
    HRESULT                     hResult = S_OK;

    BOOL                        bResult = FALSE;
    BOOL                        bGotDomainInfo = FALSE;
    BOOL                        bConnFlag = TRUE;
    
    TCHAR                       szTemp[ MAX_STRING_LENGTH ];
    TCHAR                       szServer[ MAX_STRING_LENGTH ];
    TCHAR                       szName[ MAX_STRING_LENGTH ];
    TCHAR                       szDomain[ MAX_STRING_LENGTH ];
    TCHAR                       szFQDN[ MAX_STRING_LENGTH ];
    TCHAR                       szAdsiBuffer[ MAX_STRING_LENGTH ];
    
    CHString                    strTemp = NULL_STRING;
    CHString                    strDisplay = NULL_STRING;
    
    IEnumWbemClassObject        *pEnumClass = NULL;
    IWbemServices               *pRsopNameSpace = NULL;
    IWbemClassObject            *pUserClass =  NULL;
    IWbemClassObject            *pInInst = NULL;
    IWbemClassObject            *pOutInst = NULL;

    ULONG                       ulReturn = 0;
    LONG                        lCount = 0;
    LONG                        lLBound = 0;
    LONG                        lUBound = 0;

    DWORD                       dwName = MAX_STRING_LENGTH;
    DWORD                       dwDomain = MAX_STRING_LENGTH;
    DWORD                       dwBufSize = MAX_STRING_LENGTH;
        
    USERINFO                    *pUserInfo = new USERINFO;

    VARIANT                     vVarVerbose;
    VARTYPE                     vartype;

    SAFEARRAY                   *safeArray = NULL;

    PSID                        pSid = NULL;
    SID_NAME_USE                *pSidNameUse = new SID_NAME_USE;

    try
    {
        // set the strings to NULL
        ZeroMemory( szTemp, MAX_STRING_LENGTH * sizeof( TCHAR ) );
        ZeroMemory( szName, MAX_STRING_LENGTH * sizeof( TCHAR ) );
        ZeroMemory( szServer, MAX_STRING_LENGTH * sizeof( TCHAR ) );
        ZeroMemory( szDomain, MAX_STRING_LENGTH * sizeof( TCHAR ) );
        ZeroMemory( szFQDN, MAX_STRING_LENGTH * sizeof( TCHAR ) );

        PrintProgressMsg( m_hOutput, GetResString( IDS_CONNECT_RSOP ), m_csbi );

        // connect to the RSOP namespace
        ConnectWmi( m_pWbemLocator, &pRsopNameSpace, m_strServerName, 
                    m_strUserName, m_pwszPassword, &m_pAuthIdentity,
                    FALSE, _bstr_t( ROOT_RSOP ), &hResult );
        CHECK_HRESULT( hResult );

        // Get the object for the RSOP diagnostic mode provider
        hResult = pRsopNameSpace->GetObject( _bstr_t( CLS_DIAGNOSTIC_PROVIDER ),
                                                0, NULL, &pUserClass, NULL );
        CHECK_HRESULT( hResult );
        
        PrintProgressMsg( m_hOutput, GetResString( IDS_GET_METHOD ), m_csbi );

        // get the reqd. method....to enumerate the users
        hResult = pUserClass->GetMethod( _bstr_t( FN_ENUM_USERS ), 0, &pInInst, NULL );
        CHECK_HRESULT( hResult );

        PrintProgressMsg( m_hOutput, GetResString( IDS_GET_SID ), m_csbi );

        // Execute method RSopEnumerateUsers
        hResult = pRsopNameSpace->ExecMethod( _bstr_t( CLS_DIAGNOSTIC_PROVIDER ), 
                                                _bstr_t( FN_ENUM_USERS ), 
                                                0, NULL, pInInst, &pOutInst, NULL);
        if( pOutInst == NULL )
        {
            hResult = E_FAIL;   
        }
        if( FAILED( hResult ) )
        {
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );
                    
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            // release the interface pointers and exit
            SAFEIRELEASE( pRsopNameSpace );
            SAFEIRELEASE( pUserClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );
            SAFEIRELEASE( pEnumClass );
            
            SAFE_DELETE( pUserInfo );
            SAFE_DELETE( pSidNameUse );

            return FALSE;
        }

        // Get the result value...
        bResult = PropertyGet( pOutInst, FPR_RETURN_VALUE, ulReturn, 0 );
        CHECK_BRESULT( bResult );

        if( ulReturn != 0 )
        {
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );

            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            // release the interface pointers and exit
            SAFEIRELEASE( pRsopNameSpace );
            SAFEIRELEASE( pUserClass );
            SAFEIRELEASE( pInInst );
            SAFEIRELEASE( pOutInst );
            SAFEIRELEASE( pEnumClass );
            
            SAFE_DELETE( pUserInfo );
            SAFE_DELETE( pSidNameUse );

            return FALSE;
        }

        VariantInit( &vVarVerbose );
        hResult = pOutInst->Get( _bstr_t( CPV_USER_SIDS ), 0, &vVarVerbose, 0, 0 );
        CHECK_HRESULT_VAR( hResult, vVarVerbose );

        if( vVarVerbose.vt != VT_NULL && vVarVerbose.vt != VT_EMPTY )
        {
            // get the type of the elements in the safe array
            vartype = V_VT( &vVarVerbose ) & ~VT_ARRAY;

            //get the array of strings in to the safe array from the variant
            safeArray = (SAFEARRAY *)vVarVerbose.parray;

            //get the number of elements (subkeys)
            if( safeArray != NULL )
            {
                hResult = SafeArrayGetLBound( safeArray, 1, &lLBound );
                CHECK_HRESULT( hResult );   

                hResult = SafeArrayGetUBound( safeArray, 1, &lUBound );
                CHECK_HRESULT( hResult );  
                if( lUBound == 0xffffffff )
                {
                                // erase the last status message
                    PrintProgressMsg( m_hOutput, NULL, m_csbi );

                    ShowMessage( stdout, GetResString( IDS_INFO) );
					SetLastError( ERROR_POLICY_OBJECT_NOT_FOUND );
					ShowLastError( stdout );

                    // release the interface pointers and exit
                    SAFEIRELEASE( pRsopNameSpace );
                    SAFEIRELEASE( pUserClass );
                    SAFEIRELEASE( pInInst );
                    SAFEIRELEASE( pOutInst );
                    SAFEIRELEASE( pEnumClass );
                    SAFE_DELETE( pUserInfo );
                    SAFE_DELETE( pSidNameUse );
                    return TRUE;
                }
            }

            // If we have to get the information from a remote machine then...
            // connect to the remote machine.
            if ( m_bLocalSystem == FALSE )
            {
                lstrcpy( szServer, m_strServerName );
                lstrcpy( szName, m_strUserName );
                
                // erase the last status message
                PrintProgressMsg( m_hOutput, NULL, m_csbi );

                bResult = EstablishConnection( szServer, szName, MAX_STRING_LENGTH, 
                                                m_pwszPassword, MAX_STRING_LENGTH, FALSE );
                if( bResult != TRUE )
                {
                    // erase the last status message
                    PrintProgressMsg( m_hOutput, NULL, m_csbi );
                    
                    ShowMessage( stderr, GetResString( IDS_ERROR ) );
                    ShowMessage( stderr, GetReason() );

                    // release the interface pointers and exit
                    SAFEIRELEASE( pRsopNameSpace );
                    SAFEIRELEASE( pUserClass );
                    SAFEIRELEASE( pInInst );
                    SAFEIRELEASE( pOutInst );
                    SAFEIRELEASE( pEnumClass );
                    
                    SAFE_DELETE( pUserInfo );
                    SAFE_DELETE( pSidNameUse );

                    return FALSE;
                }
                else
                {
                    switch( GetLastError() )
                    {
                        case I_NO_CLOSE_CONNECTION:
                            bConnFlag = FALSE;
                            break;
 
                        case E_LOCAL_CREDENTIALS:
                        case ERROR_SESSION_CREDENTIAL_CONFLICT:
                            bConnFlag = FALSE;
                            break;

                        default:
                            break;
                    }
                }

                // Get the new output co-ordinates
                if ( m_hOutput != NULL )
                {   
                    GetConsoleScreenBufferInfo( m_hOutput, &m_csbi );
                }
            }

            for( lCount = lLBound ; lLBound <= lUBound; lLBound++ )
            {
                bResult = GetPropertyFromSafeArray( safeArray, lLBound, strTemp, vartype );
                CHECK_BRESULT( bResult );
                         
                // Got the SID...save it in the structure
                pUserInfo->strUserSid = strTemp;

                PrintProgressMsg( m_hOutput, GetResString( IDS_GET_NAME ), m_csbi );

                // Get the User Name
                lstrcpy( szTemp, strTemp );
                ConvertStringSidToSid( szTemp, &pSid );
                                
                // Get the user name for the SID we have got
                bResult = LookupAccountSid( szServer, pSid, szName, &dwName, szDomain, 
                                            &dwDomain, pSidNameUse );
                if( bResult == 0 )
                {
                    // Could not get the name from the API try to retrieve it from WMI
                    bResult = GetUserNameFromWMI( szTemp, szName, szDomain );
                    PrintProgressMsg( m_hOutput, NULL, m_csbi );
                    if( bResult == FALSE )
                    {
                        // Increment the count
                        lCount++;

                        // If the user was not found then display a message stating the same
                        if( lCount > lUBound )
                        {
                            strTemp = L"";
                            if( bAllUsers == FALSE )
                            {
                                // check if we need to append the domain name
                                if ( m_strDomainName.GetLength() != 0 )
                                {
                                    strTemp = m_strDomainName + _T( "\\" ) + m_strUser;
                                }
                                else
                                {
                                    strTemp = m_strUser;
                                }
                            }
                            
                            // Form the display string
                            strDisplay.Format( GetResString( IDS_USER_NO_RSOP ), strTemp );

                            ShowMessage( stderr, GetResString( IDS_INFO ) );
                            ShowMessage( stderr, strDisplay );
                        }

                        // could not get a name for this SID, so continue with the next SID.
                        continue;
                    }
                }
                
                // Free the pSid
                if( pSid != NULL )
                {
                    LocalFree( pSid );
                    pSid = NULL;
                }

                // Check wether the Rsop data has to be retrieved for this user name.
                if( bAllUsers == FALSE )
                {
                    if( lstrcmpi( szName, m_strUser ) != 0 
                        || ( lstrcmpi( szDomain, m_strDomainName ) != 0 
                                && m_strDomainName.GetLength() != 0 ) )
                    {
                        // erase the last status message
                        PrintProgressMsg( m_hOutput, NULL, m_csbi );

                        // re-set the buffer sizes
                        dwName = MAX_STRING_LENGTH;
                        dwDomain = MAX_STRING_LENGTH;

                        // Increment the count
                        lCount++;

                        // If the user was not found then display a message stating the same
                        if( lCount > lUBound )
                        {
                            // check if we need to append the domain name
                            if ( m_strDomainName.GetLength() != 0 )
                            {
                                strTemp = m_strDomainName + _T( "\\" ) + m_strUser;
                            }
                            else
                            {
                                strTemp = m_strUser;
                            }

                            // Form the display string
                            strDisplay.Format( GetResString( IDS_USER_NO_RSOP ), strTemp );

                            ShowMessage( stderr, GetResString( IDS_INFO ) );
                            ShowMessage( stderr, strDisplay );
                        }

                        // No need to get the data for this user
                        continue;
                    }
                }

                // Store the user name into the structure.
                pUserInfo->strUserName = szName;

                // Append the domain name to the user name.
                lstrcat( szDomain, TEXT_BACKSLASH );
                lstrcat( szDomain, pUserInfo->strUserName );
                pUserInfo->strUserName = szDomain;
  
                PrintProgressMsg( m_hOutput, GetResString( IDS_GET_PROFILE ), m_csbi );

                // Get the user profile information
                if( GetUserProfile( pUserInfo ) == FALSE )
                {
                    // erase the last status message
                    PrintProgressMsg( m_hOutput, NULL, m_csbi );

                    // Display the error message
                    ShowMessage( stderr, GetResString( IDS_ERROR ) );
                    ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

                    // release the interface pointers and exit
                    SAFEIRELEASE( pRsopNameSpace );
                    SAFEIRELEASE( pUserClass );
                    SAFEIRELEASE( pInInst );
                    SAFEIRELEASE( pOutInst );
                    SAFEIRELEASE( pEnumClass );
                    
                    SAFE_DELETE( pUserInfo );
                    SAFE_DELETE( pSidNameUse );

                    // if we have opened a connection then close the same.
                    if( m_bLocalSystem == FALSE  && bConnFlag == TRUE )
                    {
                        lstrcpy( szServer, m_strServerName );
                        CloseConnection( szServer );
                    }

                    return FALSE;
                }

                if( bGotDomainInfo == FALSE )
                {
                    PrintProgressMsg( m_hOutput, GetResString( IDS_GET_COMMON ), m_csbi );

                    // Get the domain name and other related information
                    if( GetDomainInfo( pUserInfo ) == FALSE )
                    {
                        // erase the last status message
                        PrintProgressMsg( m_hOutput, NULL, m_csbi );

                        // Display the error message
                        ShowMessage( stderr, GetResString( IDS_ERROR ) );
                        ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

                        // release the interface pointers and exit
                        SAFEIRELEASE( pRsopNameSpace );
                        SAFEIRELEASE( pUserClass );
                        SAFEIRELEASE( pInInst );
                        SAFEIRELEASE( pOutInst );
                        SAFEIRELEASE( pEnumClass );
                        
                        SAFE_DELETE( pUserInfo );
                        SAFE_DELETE( pSidNameUse );

                        // if we have opened a connection then close the same.
                        if( m_bLocalSystem == FALSE && bConnFlag == TRUE )
                        {
                            lstrcpy( szServer, m_strServerName );
                            CloseConnection( szServer );
                        }

                        return FALSE;
                    }

                    // Get the OS information
                    if( GetOsInfo( pUserInfo ) == FALSE )
                    {
                        // erase the last status message
                        PrintProgressMsg( m_hOutput, NULL, m_csbi );

                        // Display the error message
                        ShowMessage( stderr, GetResString( IDS_ERROR ) );
                        ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );
                        
                        // release the interface pointers and exit
                        SAFEIRELEASE( pRsopNameSpace );
                        SAFEIRELEASE( pUserClass );
                        SAFEIRELEASE( pInInst );
                        SAFEIRELEASE( pOutInst );
                        SAFEIRELEASE( pEnumClass );
                        
                        SAFE_DELETE( pUserInfo );
                        SAFE_DELETE( pSidNameUse );

                        // if we have opened a connection then close the same.
                        if( m_bLocalSystem == FALSE && bConnFlag == TRUE )
                        {
                            lstrcpy( szServer, m_strServerName );
                            CloseConnection( szServer );
                        }

                        return FALSE;
                    }

                    // Get the FQDN of the computer
                    // PrintProgressMsg( m_hOutput, GetResString( IDS_GET_FQDN ), m_csbi );

                    if( m_bLocalSystem == TRUE )
                    {
                        // we have to get the FQDN for the local system 
                        // use the GetComputerObjectName API
                        ulReturn = MAX_STRING_LENGTH;
                        GetComputerObjectName( NameFullyQualifiedDN, szFQDN, &ulReturn);
                    }
                    else 
                    {
                        // Get the local computers domain name
                        GetComputerNameEx( ComputerNameDnsDomain, szAdsiBuffer, &dwBufSize );

                        lstrcpy( szServer, m_strADSIServer );
                        lstrcat( szServer, TEXT_DOLLAR );

                        // Check if the machine we are querying is in the same domain
                        if( m_strADSIDomain.CompareNoCase( szAdsiBuffer ) == 0 )
                        {
                            // get the FQDN from the Translate name call
                            dwBufSize = MAX_STRING_LENGTH;
                            TranslateName( szServer, NameDisplay, NameFullyQualifiedDN, 
                                            szFQDN, &dwBufSize );
                        }
                        else
                        {
                            // Get the FQDN from ADSI directory services
                            GetFQDNFromADSI( szFQDN, TRUE, szServer );
                        }
                    }
                        
                    // Store the FQDN into the structure.
                    pUserInfo->strComputerFQDN = szFQDN;
    
                    // Set the flag to TRUE so that this code is not executed again and again
                    bGotDomainInfo = TRUE;
                }

                // Get the FQDN of the user
                if( ( m_bLocalSystem == TRUE ) 
                        || ( m_strADSIDomain.CompareNoCase( szAdsiBuffer ) == 0 ) ) 
                {
                    ZeroMemory( szFQDN, MAX_STRING_LENGTH * sizeof( TCHAR ) );
                    dwBufSize = MAX_STRING_LENGTH;
                    lstrcpy( szName, pUserInfo->strUserName );

                    // get the FQDN from the Translate name call
                    TranslateName( szName, NameSamCompatible, NameFullyQualifiedDN, 
                                    szFQDN, &dwBufSize );
                }
                else
                {
                    // Get the FQDN from ADSI directory services
                    lstrcpy( szName, pUserInfo->strUserName );
                    GetFQDNFromADSI( szFQDN, FALSE, szName );
                }
                
                // Store the FQDN into the structure.
                pUserInfo->strUserFQDN = szFQDN;

                // Now display the data
                PrintProgressMsg( m_hOutput, GetResString( IDS_STARTED_RETRIEVAL ), m_csbi );
                DisplayData( pUserInfo, pRsopNameSpace );

                // Get the new output co-ordinates
                if ( m_hOutput != NULL )
                {
                    GetConsoleScreenBufferInfo( m_hOutput, &m_csbi );
                }

                // re-set the buffers and their sizes
                ZeroMemory( szTemp, MAX_STRING_LENGTH * sizeof( TCHAR ) );
                ZeroMemory( szName, MAX_STRING_LENGTH * sizeof( TCHAR ) );
                ZeroMemory( szServer, MAX_STRING_LENGTH * sizeof( TCHAR ) );
                ZeroMemory( szDomain, MAX_STRING_LENGTH * sizeof( TCHAR ) );

                dwName = MAX_STRING_LENGTH;
                dwDomain = MAX_STRING_LENGTH;
            }// for

            // if we have opened a connection then close the same.
            if( m_bLocalSystem == FALSE && bConnFlag == TRUE )
            {
                lstrcpy( szServer, m_strServerName );
                CloseConnection( szServer );
            }
        }
        else
        {
            // No classes were retrieved....display msg
            // erase the last status message
            PrintProgressMsg( m_hOutput, NULL, m_csbi );

            // check if we need to append the domain name
            if ( m_strDomainName.GetLength() != 0 )
            {
                strTemp = m_strDomainName + _T( "\\" ) + m_strUser;
            }
            else
            {
                strTemp = m_strUser;
            }

            // Form the display string
            strDisplay.Format( GetResString( IDS_USER_NO_RSOP ), strTemp );

            ShowMessage( stderr, GetResString( IDS_INFO ) );
            ShowMessage( stderr, strDisplay );
        }

        VariantClear(&vVarVerbose);                 
    }
    catch(  _com_error & error )
    {
        // erase the last status message
        PrintProgressMsg( m_hOutput, NULL, m_csbi );

        // display the error msg
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // release the interface pointers and exit
        SAFEIRELEASE( pRsopNameSpace );
        SAFEIRELEASE( pUserClass );
        SAFEIRELEASE( pInInst );
        SAFEIRELEASE( pOutInst );
        SAFEIRELEASE( pEnumClass );
        
        SAFE_DELETE( pUserInfo );
        SAFE_DELETE( pSidNameUse );

        VariantClear(&vVarVerbose);

        return FALSE;
    }

    // release the interface pointers and exit
    SAFEIRELEASE( pRsopNameSpace );
    SAFEIRELEASE( pUserClass );
    SAFEIRELEASE( pInInst );
    SAFEIRELEASE( pOutInst );
    SAFEIRELEASE( pEnumClass );
    
    SAFE_DELETE( pUserInfo );
    SAFE_DELETE( pSidNameUse );

    return TRUE;
}

/*********************************************************************************************
Routine Description:

    This function gets the user profile data and fills the array with the same
     
Arguments:
 
    [in] PUSERINFO      pUserInfo       :   Structure containing the user information.

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::GetUserProfile( PUSERINFO pUserInfo )
{
    // Local variables
    HRESULT                 hResult = S_OK;

    IWbemServices           *pDefaultNameSpace = NULL;

    TCHAR                   szTemp[ MAX_STRING_LENGTH ];

    try
    {
        // connect to the default namespace
        ConnectWmi( m_pWbemLocator, &pDefaultNameSpace, m_strServerName, 
                    m_strUserName, m_pwszPassword, &m_pAuthIdentity,
                    FALSE, _bstr_t( ROOT_DEFAULT ), &hResult );
        CHECK_HRESULT( hResult );

        // Set the sub key name
        lstrcpy( szTemp, PATH );
        lstrcat( szTemp, pUserInfo->strUserSid );
        
        // Get the local profile
        RegQueryValueWMI( pDefaultNameSpace, HKEY_DEF, szTemp, FPR_LOCAL_VALUE, 
                            pUserInfo->strLocalProfile, V_NOT_AVAILABLE );

        // Get the roaming profile
        RegQueryValueWMI( pDefaultNameSpace, HKEY_DEF, szTemp, FPR_ROAMING_VALUE, 
                            pUserInfo->strRoamingProfile, V_NOT_AVAILABLE );
    }
    catch(  _com_error & error )
    {
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // release the allocated variables
        SAFEIRELEASE( pDefaultNameSpace );
    
        return FALSE;
    }

    // release the interface pointer
    SAFEIRELEASE( pDefaultNameSpace );

    return TRUE;
}

/*********************************************************************************************
Routine Description:

    This function gets the domain information and fills the array with the same
     
Arguments:
 
    [in] PUSERINFO      pUserInfo       :   Structure containing the user information.

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::GetDomainInfo( PUSERINFO pUserInfo )
{
    // Local variables
    HRESULT                     hResult = S_OK;

    BOOL                        bResult = FALSE;
    BOOL                        bDone = FALSE;

    IEnumWbemClassObject        *pEnumClass = NULL;
    IWbemClassObject            *pClass = NULL;

    ULONG                       ulReturn = 0;

    CHString                    strTemp;

    try
    {
        // print the progress message
        PrintProgressMsg( m_hOutput, GetResString( IDS_GET_DOMAIN ), m_csbi );

        // Enumerate the instances to get the domain and site names of the Win32 NT domain
        hResult = m_pWbemServices->CreateInstanceEnum( _bstr_t( CLS_WIN32_SITE ),
                                                        WBEM_FLAG_FORWARD_ONLY | 
                                                        WBEM_FLAG_RETURN_IMMEDIATELY,
                                                        NULL, &pEnumClass );
        CHECK_HRESULT( hResult );
        
        // Set the interface security
        hResult = SetInterfaceSecurity( pEnumClass, m_pAuthIdentity );
        CHECK_HRESULT( hResult );

        // get the data
        //   since there may be more than one instance and we are looking for the instance 
        //   with the domain controller and site name.....using a while loop and as soon as 
        //   we get the instance we need break out of it
        hResult = WBEM_S_NO_ERROR;
        while( hResult == WBEM_S_NO_ERROR )
        {
            hResult = pEnumClass->Next( WBEM_INFINITE, 1, &pClass, &ulReturn );
            CHECK_HRESULT( hResult );

            if( ulReturn == 0 )
            {
                // no more data so break out of the loop
                break;
            }

            // get the server name
            if( bDone == FALSE )
            {
                bDone = TRUE;
                bResult = PropertyGet( pClass, CPV_GPO_SERVER, pUserInfo->strUserServer, 
                                        V_NOT_AVAILABLE );
                CHECK_BRESULT( bResult );
            }

            // get the domain name
            bResult = PropertyGet( pClass, CPV_GPO_NAME, pUserInfo->strUserDomain, 
                                    V_NOT_AVAILABLE );
            CHECK_BRESULT( bResult );

            PrintProgressMsg( m_hOutput, GetResString( IDS_GET_SITE ), m_csbi );

            // get the site name
            bResult = PropertyGet( pClass, CPV_SITE_NAME, pUserInfo->strUserSite, 
                                    V_NOT_AVAILABLE );
            CHECK_BRESULT( bResult );

            // get the domain controller name
            bResult = PropertyGet( pClass, CPV_DC_NAME, strTemp, V_NOT_AVAILABLE );
            CHECK_BRESULT( bResult );

            if( lstrcmp( strTemp, V_NOT_AVAILABLE ) != 0 )
            {
                // this enumeration has the domain controller name...
                //   we have got the enumeration we need so get the other data
                break;
            }
        }// while
    }
    catch(  _com_error & error )
    {
        // erase the last status message
        PrintProgressMsg( m_hOutput, NULL, m_csbi );

        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // release the allocated variables
        SAFEIRELEASE( pEnumClass );
        SAFEIRELEASE( pClass );
        
        return FALSE;
    }

    // release the interface pointers
    SAFEIRELEASE( pEnumClass );
    SAFEIRELEASE( pClass );
        
    return TRUE;
}

/*********************************************************************************************
Routine Description:

    This function returns the domain type

Arguments:

    [in]  lpDomainName     : domain name intends to view Rsop data.
    [out] pbW2K            : contain whether the domain type in W2K.
    [out] pbLocalAccount   : contain whether the account is local.
        
Return Value:

    TRUE  - if DC found/domain name is computer name
    FALSE - if DC not found   
*********************************************************************************************/
BOOL GetDomainType( LPTSTR lpszDomainName, BOOL * pbW2K, BOOL *pbLocalAccount )
{
    PDOMAIN_CONTROLLER_INFO         pDCI;

    DWORD                           dwResult = 0;
    DWORD                           dwSize = 0;

    TCHAR                           szComputerName[ MAX_PATH ];
        
    // Check the incoming pointers
    if( lpszDomainName == NULL || pbW2K == NULL || pbLocalAccount == NULL )
    {
        return FALSE;
    }

    // Check this domain for a Domain Controller
    dwResult = DsGetDcName( NULL, lpszDomainName, NULL, NULL,
                            DS_DIRECTORY_SERVICE_PREFERRED, &pDCI );
    if ( dwResult == ERROR_SUCCESS )
    {
        // Found a DC, does it have a DS ?
        if ( pDCI->Flags & DS_DS_FLAG ) 
        {
            *pbW2K = TRUE;
        }
        
        NetApiBufferFree( pDCI );
        
        return TRUE;
    }
    
    // Check if the domain name is also the computer name (eg: local account)
    dwSize = ARRAYSIZE( szComputerName );
    if ( GetComputerName ( szComputerName, &dwSize )  != 0 )
    {
        if ( lstrcmpi( szComputerName, lpszDomainName ) == 0 )
        {
            *pbLocalAccount = TRUE;
            return TRUE;
        }
    }
    
    return FALSE;
}

/*********************************************************************************************
Routine Description:

    This function displays the data common to both scopes
     
Arguments:
 
    [in] PUSERINFO      pUserInfo       :   Structure containing the user information.

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::DisplayCommonData( PUSERINFO pUserInfo )
{
    // Local variables
    TCHAR                   szMsgBuffer[ MAX_RES_STRING ];
    TCHAR                   szDate[ MAX_RES_STRING ];
    TCHAR                   szTime[ MAX_RES_STRING ];

    BOOL                    bW2KDomain = FALSE;
    BOOL                    bLocalAccount = FALSE;
    BOOL                    bLocaleChanged = FALSE;

    DWORD                   dwLength = 0;

    SYSTEMTIME              systime;

    LCID                    lcid;
    
    // erase the last status message
    PrintProgressMsg( m_hOutput, NULL, m_csbi );

    // Clear the Msg buffer
    ZeroMemory( szMsgBuffer, MAX_RES_STRING );

    // Start displaying the output
    ShowMessage( stdout, NEW_LINE );
    
    // Print the leagal information
    ShowMessage( stdout, GetResString( IDS_LEGAL_INFO1 ) );
    ShowMessage( stdout, GetResString( IDS_LEGAL_INFO2 ) );

    // Print the date and time this report is generated
    GetLocalTime( &systime );

    // verify whether console supports the current locale 100% or not
    lcid = GetSupportedUserLocale( bLocaleChanged );

    // get the formatted date
    GetDateFormat( lcid, 0, &systime, ((bLocaleChanged == TRUE) ? L"MM/dd/yyyy" : NULL), 
                    szDate, SIZE_OF_ARRAY( szDate ) );
    
    // now format the date
    GetTimeFormat( LOCALE_USER_DEFAULT, 0, &systime, ((bLocaleChanged == TRUE) ? L"HH:mm:ss" : NULL), 
                    szTime, SIZE_OF_ARRAY( szTime ) );

    wsprintf( szMsgBuffer, GetResString( IDS_CREATED_ON ), szDate, szTime );
    ShowMessage( stdout, szMsgBuffer );

    ShowMessage( stdout, NEW_LINE );

    // Display the common information....Domain Info
    wsprintf( szMsgBuffer, GetResString( IDS_GPO_TITLE ), pUserInfo->strUserName, 
                pUserInfo->strUserServer );
    ShowMessage( stdout, szMsgBuffer );
    dwLength = lstrlen( szMsgBuffer );
    
    ShowMessage( stdout, NEW_LINE );
    
    // Underline the above heading
    for( ; dwLength > 0; dwLength-- )
    {
        ShowMessage( stdout, GetResString( IDS_DASH ) );
    }
    ShowMessage( stdout, NEW_LINE );

    lstrcpy( szMsgBuffer, pUserInfo->strUserDomain );
    if( lstrlen( szMsgBuffer ) != 0 )
    {
        lstrcpy( szMsgBuffer, _tcstok( szMsgBuffer, GetResString( IDS_LAST_CHAR ) ) );
        lstrcpy( szMsgBuffer, _tcstok( NULL, GetResString( IDS_LAST_CHAR ) ) );
    }
    
    // Show the OS information
    ShowMessage( stdout, GetResString( IDS_OS_TYPE ) ); 
    ShowMessage( stdout, pUserInfo->strOsType );

    ShowMessage( stdout, GetResString( IDS_OS_CONFIG ) );   
    ShowMessage( stdout, pUserInfo->strOsConfig );

    ShowMessage( stdout, GetResString( IDS_OS_VERSION ) );  
    ShowMessage( stdout, pUserInfo->strOsVersion );
    ShowMessage( stdout, NEW_LINE );    

    // Get the domain type information
    GetDomainType (szMsgBuffer, &bW2KDomain, &bLocalAccount);

    ShowMessage( stdout, GetResString( IDS_DOMAIN_NAME ) ); 
    ShowMessage( stdout, szMsgBuffer );
    ShowMessage( stdout, NEW_LINE );    

    ShowMessage( stdout, GetResString( IDS_DOMAIN_TYPE ) ); 
    // if it is a  win2k domain type
    if ( bW2KDomain ) 
    {
        ShowMessage( stdout, GetResString( IDS_W2K_DOMAIN ) );  
    }
    else
    {
        if ( bLocalAccount ) // local account
        {
            ShowMessage( stdout, V_NOT_AVAILABLE ); 
            ShowMessage( stdout, GetResString( IDS_LOCAL_COMP ) );  
        }
        else    //win NT4
        {
            ShowMessage( stdout, GetResString( IDS_NT4_DOMAIN ) );
        }
    }

    // Display the Site name
    ShowMessage( stdout, NEW_LINE );    
    ShowMessage( stdout, GetResString( IDS_SITE_NAME ) );
    ShowMessage( stdout, pUserInfo->strUserSite );

    // Display the roaming profile
    ShowMessage( stdout, NEW_LINE );    
    ShowMessage( stdout, GetResString( IDS_ROAMING_PROFILE ) );
    ShowMessage( stdout, pUserInfo->strRoamingProfile );

    // Display the local profile
    ShowMessage( stdout, NEW_LINE ); 
    ShowMessage( stdout, GetResString( IDS_LOCAL_PROFILE ) );
    ShowMessage( stdout, pUserInfo->strLocalProfile );
    ShowMessage( stdout, NEW_LINE );    

    return TRUE;
}

/*********************************************************************************************
Routine Description:
    This function displays the GPO information from the rsop namespace created.

Arguments:

    [in] IEnumWbemClassObject   :   pointer to the Enumeration class object
    [in] LPCTSTR                :   string containing the scope( USER or COMPUTER )

Return Value:
    
    TRUE  - if SUCCESS
    FALSE - if ERROR
*********************************************************************************************/
BOOL CGpResult::GpoDisplay( IWbemServices *pNameSpace, LPCTSTR pszScopeName )
{
    HRESULT                 hResult = WBEM_S_NO_ERROR;

    BOOL                    bResult = FALSE;
    BOOL                    bFilterAllowed = FALSE;
    BOOL                    bLinkEnabled = FALSE;
    BOOL                    bGpoEnabled = FALSE;
    BOOL                    bAccessDenied = FALSE;
    BOOL                    bConnected = FALSE;
    
    ULONG                   ulReturn = 0;
    ULONG                   ulAppliedOrder = 0;
    ULONG                   ulVersion = 0;

    DWORD                   dwAppliedRow = 0;
    DWORD                   dwFilteredRow = 0;

    CHString                strTemp;
    
    IEnumWbemClassObject    *pRsopLinkClass = NULL;
    IWbemClassObject        *pRsopLinkObj = NULL;
    IWbemClassObject        *pRsopObj = NULL;
    IWbemClassObject        *pSomFilter = NULL;

    IWbemServices           *pPolicyNameSpace = NULL;

    TARRAY                  arrAppliedData = NULL;
    TARRAY                  arrFilteredData = NULL;

    try
    {
        if( pNameSpace == NULL || pszScopeName == NULL )
        {
            _com_issue_error( STG_E_UNKNOWN );
        }

        // Create the Dynamic Arrays
        arrAppliedData = CreateDynamicArray( );
        arrFilteredData = CreateDynamicArray( );

        // Check the memory allocations
        if( arrAppliedData == NULL || arrFilteredData == NULL )
        {
            _com_issue_error( E_OUTOFMEMORY );
        }

        // enumerate the instances of the RSOP GPLink class
        hResult = pNameSpace->CreateInstanceEnum( _bstr_t( CLS_RSOP_GPOLINK ), 
                                                    WBEM_FLAG_FORWARD_ONLY |
                                                    WBEM_FLAG_RETURN_IMMEDIATELY,
                                                    NULL, &pRsopLinkClass );
        CHECK_HRESULT( hResult );

        // set the interface security
        hResult = SetInterfaceSecurity( pRsopLinkClass, m_pAuthIdentity );
        CHECK_HRESULT( hResult );

        // Get the information from the enumerated classes
        while( TRUE )
        {           
            // Get the pointer to the next class
            hResult = pRsopLinkClass->Next( WBEM_INFINITE, 1, &pRsopLinkObj, &ulReturn );
            CHECK_HRESULT( hResult );
            if( ulReturn == 0 )
            {
                break;
            }
            
            // Get the applied order for the link
            bResult = PropertyGet( pRsopLinkObj, CPV_APPLIED_ORDER, ulAppliedOrder, 0 );
            CHECK_BRESULT( bResult );

            // Get the link enabled property
            bResult = PropertyGet( pRsopLinkObj, CPV_ENABLED, bLinkEnabled, FALSE );
            CHECK_BRESULT( bResult );
            
            // Get the reference to the GPO class
            bResult = PropertyGet( pRsopLinkObj, CPV_GPO_REF, strTemp, V_NOT_AVAILABLE );
            CHECK_BRESULT( bResult );
            
            // Check wether the link has a GPO class
            if( strTemp.Find( GPO_REFERENCE ) != VAR_TRUE )
            {
                // Get the object for the GPO reference got
                hResult = pNameSpace->GetObject( _bstr_t( strTemp ), 0, NULL, &pRsopObj, NULL );
                if( FAILED( hResult ) )
                {
                    if( hResult == WBEM_E_NOT_FOUND )
                    {
                        continue;
                    }
                    _com_issue_error( hResult );
                }
            
                // Get the GPO name
                bResult = PropertyGet( pRsopObj, CPV_GPO_NAME, strTemp, V_NOT_AVAILABLE );
                CHECK_BRESULT( bResult );

                // Get the WMI filter status
                bResult = PropertyGet( pRsopObj, CPV_GPO_FILTER_STATUS, bFilterAllowed, FALSE );
                CHECK_BRESULT( bResult );

                // Get the Gpo enabled information
                bResult = PropertyGet( pRsopObj, CPV_ENABLED, bGpoEnabled, FALSE );
                CHECK_BRESULT( bResult );

                // Get the access denied information
                bResult = PropertyGet( pRsopObj, CPV_ACCESS_DENIED, bAccessDenied, FALSE );
                CHECK_BRESULT( bResult );

                // Get the version
                bResult = PropertyGet( pRsopObj, CPV_VERSION, ulVersion, 0 );
                CHECK_BRESULT( bResult );

                // If the applied order id not zero then this GPO is applied
                if( ulAppliedOrder > 0 )
                {
                    // Populate the applied Gpo array
                    DynArrayAppendRow( arrAppliedData, COL_MAX );
                    DynArraySetString2( arrAppliedData, dwAppliedRow, COL_DATA, strTemp, 0 );
                    DynArraySetDWORD2( arrAppliedData, dwAppliedRow, COL_ORDER, ulAppliedOrder );
                    dwAppliedRow++;
                }
                else if( bLinkEnabled != VAR_TRUE )
                {
                    // if the link is disabled...populate the Filtered Array
                    DynArrayAppendRow( arrFilteredData, COL_MAX );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_DATA, strTemp, 0 );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER, 
                                        GetResString( IDS_LINK_DISABLED ), 0 );
                    dwFilteredRow++;
                }
                else if( bGpoEnabled != VAR_TRUE )
                {
                    // if the GPO is disabled...populate the Filtered Array
                    DynArrayAppendRow( arrFilteredData, COL_MAX );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_DATA, strTemp, 0 );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER, 
                                        GetResString( IDS_GPO_DISABLED ), 0 );
                    dwFilteredRow++;
                }
                else if( bAccessDenied == VAR_TRUE )
                {
                    // if the access is denied...populate the Filtered Array
                    DynArrayAppendRow( arrFilteredData, COL_MAX );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_DATA, strTemp, 0 );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER, 
                                        GetResString( IDS_ACCESS_DENIED ), 0 );
                    dwFilteredRow++;
                }
                else if( bFilterAllowed != VAR_TRUE )
                {
                    // if the filter status is false...populate the Filtered Array
                    DynArrayAppendRow( arrFilteredData, COL_MAX_FILTER );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_DATA, strTemp, 0 );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER, 
                                        GetResString( IDS_WMI_DENIED ), 0 );

                    // Get the filter ID
                    bResult = PropertyGet( pRsopObj, CPV_GPO_FILTER_ID, strTemp, V_NOT_AVAILABLE );
                    CHECK_BRESULT( bResult );

                    // Store it in the array
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER_ID, strTemp, 0 );
                    
                    dwFilteredRow++;
                }
                else if( ulVersion == 0 )
                {
                    // if the version is zero...populate the Filtered Array
                    DynArrayAppendRow( arrFilteredData, COL_MAX );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_DATA, strTemp, 0 );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER, 
                                        GetResString( IDS_VERSION_ZERO ), 0 );
                    dwFilteredRow++;
                }
                else
                {
                    // the Gpo is not applied due to an unknown reason...
                    // populate the Filtered Array
                    DynArrayAppendRow( arrFilteredData, COL_MAX );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_DATA, strTemp, 0 );
                    DynArraySetString2( arrFilteredData, dwFilteredRow, COL_FILTER, 
                                        GetResString( IDS_NOT_APPLIED ), 0 );
                    dwFilteredRow++;
                }
            }
            
        }// while

        // Got the data...sort it
        SortAppliedData( arrAppliedData );

        // Display the applied data first
        dwAppliedRow = DynArrayGetCount( arrAppliedData );
        for( DWORD dwi = 0; dwi < dwAppliedRow; dwi++ )
        {
            ShowMessage( stdout, TAB_TWO );
            ShowMessage( stdout, DynArrayItemAsString2( arrAppliedData, dwi, COL_DATA ) );
            ShowMessage( stdout, GetResString( IDS_NEWLINE ) );
        }

        // Check if there was any data displayed
        if( dwAppliedRow <= 0 )
        {
            ShowMessage( stdout, TAB_TWO );
            ShowMessage( stdout, V_NOT_AVAILABLE );
            ShowMessage( stdout, NEW_LINE );
        }

        // Display the filtered GPOs
        // Display the header...if there are any GPO's filtered out
        dwFilteredRow = DynArrayGetCount( arrFilteredData );
        if( dwFilteredRow > 0 )
        {
            ShowMessage( stdout, GetResString( IDS_GPO_FILTERED ) );
            ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );
            for( dwi = lstrlen( GetResString( IDS_GPO_FILTERED ) ); dwi > 4; dwi-- )
            {
                ShowMessage( stdout, GetResString( IDS_DASH ) );
            }
            ShowMessage( stdout, GetResString( IDS_NEWLINE ) );
        }
        else
        {
            // There are no filtered GPO's hence put a new line and continue 
            // displaying the rest of the output
            ShowMessage( stdout, GetResString( IDS_NEWLINE ) );
        }

        // display the data
        for( DWORD dwi = 0; dwi < dwFilteredRow; dwi++ )
        {
            ShowMessage( stdout, TAB_TWO );
            ShowMessage( stdout, DynArrayItemAsString2( arrFilteredData, dwi, COL_DATA ) );
            ShowMessage( stdout, GetResString( IDS_FILTERING ) );
            ShowMessage( stdout, DynArrayItemAsString2( arrFilteredData, dwi, COL_FILTER ) );
            
            // Check if we have to display the filter id for the WMI filter that evaluated to false
            if( lstrcmp( DynArrayItemAsString2( arrFilteredData, dwi, COL_FILTER ), 
                            GetResString( IDS_WMI_DENIED ) ) == 0 )
            {
                if( bConnected == FALSE )
                {
                    // we need to connect to Root\Policy 
                    // connect to the default namespace
                    ConnectWmi( m_pWbemLocator, &pPolicyNameSpace, m_strServerName, 
                                m_strUserName, m_pwszPassword, &m_pAuthIdentity,
                                FALSE, _bstr_t( ROOT_POLICY ), &hResult );
                    CHECK_HRESULT( hResult );

                    bConnected = TRUE;
                }
                                    
                // Get the object
                hResult = pPolicyNameSpace->GetObject( _bstr_t( DynArrayItemAsString2( 
                                                        arrFilteredData, dwi, COL_FILTER_ID ) ), 
                                                        0, NULL, &pSomFilter, NULL );
                CHECK_HRESULT( hResult );

                // Get the name of the filter applied
                bResult = PropertyGet( pSomFilter, CPV_NAME, strTemp, V_NOT_AVAILABLE );

                // display the filter ID
                ShowMessage( stdout, GetResString( IDS_GPO_FILTER_ID ) );
                ShowMessage( stdout, strTemp );
                ShowMessage( stdout, GetResString( IDS_NEWLINE ) );
            }

            ShowMessage( stdout, GetResString( IDS_NEWLINE ) );
        }
        
        // destroy the dynamic arrays
        DESTROY_ARRAY( arrAppliedData );
        DESTROY_ARRAY( arrFilteredData );
    }
    catch( _com_error & error )
    {
        // display the error message
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        SAFEIRELEASE( pRsopLinkObj );
        SAFEIRELEASE( pRsopLinkClass );
        SAFEIRELEASE( pRsopObj );

        // destroy the dynamic arrays
        DESTROY_ARRAY( arrAppliedData );
        DESTROY_ARRAY( arrFilteredData );

        return FALSE;
    }   

    SAFEIRELEASE( pRsopLinkObj );
    SAFEIRELEASE( pRsopLinkClass );
    SAFEIRELEASE( pRsopObj );
    
    return TRUE;
}

/*********************************************************************************************
Routine Description:
     This function Will delete the Rsop namespace created by method RsopCreateSession.

Arguments:
    [in] pClass         :   pointer to IWbemServices.   
    [in] CHString       :   string containing the RsopNamespace.  
    [in] pObject        :   pointer to IWbemClassObject.

Return Value:
  TRUE  - if SUCCESS
  FALSE - if ERROR
*********************************************************************************************/
BOOL RsopDeleteMethod( IWbemClassObject *pClass, CHString strNameSpace, 
                        IWbemServices *pNamespace )
{
    HRESULT                     hResult = S_OK;
    
    BOOL                        bResult  = FALSE; 
     
    IWbemClassObject            *pInClass = NULL;
    IWbemClassObject            *pInInst  = NULL;
    IWbemClassObject            *pOutInst = NULL;

    CHString                    strTemp;
    DWORD                        ulReturn=0;

    try
    {   
        // Check the input Parameters
        if( pClass == NULL )
        {
            _com_issue_error( STG_E_UNKNOWN );
        }

        //Delete the resultant RSOP namespace as the snap shot
        //of RSOP has been obtained
        hResult = pClass->GetMethod( _bstr_t( FN_DELETE_RSOP ), 0, &pInClass, NULL );
        CHECK_HRESULT( hResult );

        hResult = pInClass->SpawnInstance( 0, &pInInst );
        CHECK_HRESULT( hResult );
        
        //Put the input parameter 
        hResult = PropertyPut( pInInst, FPR_RSOP_NAMESPACE, strNameSpace );
        CHECK_HRESULT( hResult );

        // All The required properties are set so, execute method RsopDeleteSession
        hResult = pNamespace->ExecMethod( _bstr_t( CLS_DIAGNOSTIC_PROVIDER ), 
                                            _bstr_t( FN_DELETE_RSOP ), 
                                            0, NULL, pInInst, &pOutInst, NULL );
        if(pOutInst == NULL)
        {
            hResult = E_FAIL;
        }
        if( FAILED( hResult ) )
        {
            // display the error msg
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );

            // release the interface pointers and exit
            SAFEIRELEASE(pInClass);
            SAFEIRELEASE(pInInst);
            SAFEIRELEASE(pOutInst);

            return FALSE;
        } 
        //Get returned paramter to check whether the method was successfull
        bResult = PropertyGet( pOutInst, FPR_RETURN_VALUE, ulReturn, 0);
        CHECK_BRESULT( bResult );

        // Returns some ERROR code.
        if( ulReturn != 0 )
        {
            // Show Error Message
            ShowMessage( stderr, GetResString( IDS_ERROR ) );
            ShowMessage( stderr, GetResString( IDS_METHOD_FAILED ) );
            bResult = FALSE;
        }
        bResult = TRUE;
    }
    catch( _com_error & error ) 
    {
        // display the error message and set the return value to FALSE
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );
        bResult = FALSE;
    }

    // release the interface pointers and exit 
    SAFEIRELEASE(pInClass);
    SAFEIRELEASE(pInInst);
    SAFEIRELEASE(pOutInst);

    return bResult;
}

/*********************************************************************************************
Routine Description:

    This function gets the OS information and fills the array with the same
     
Arguments:
 
    [in] PUSERINFO      pUserInfo       :   Structure containing the user information.

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::GetOsInfo( PUSERINFO pUserInfo )
{
    // Local variables
    HRESULT                         hResult = S_OK;

    BOOL                            bResult = FALSE;
    BOOL                            bDone = FALSE;

    IEnumWbemClassObject            *pEnumClass = NULL;
    IWbemClassObject                *pClass = NULL;

    ULONG                           ulReturn = 0;
    DWORD                           dwDomainRole = 0;

    CHString                        strTemp;

    try
    {
        // print the progress message
        PrintProgressMsg( m_hOutput, GetResString( IDS_GET_OSINFO ), m_csbi );

        // Enumerate the instances to get the domain and site names of the Win32 NT domain
        hResult = m_pWbemServices->CreateInstanceEnum( _bstr_t( CLS_WIN32_OS ),
                                                        WBEM_FLAG_FORWARD_ONLY | 
                                                        WBEM_FLAG_RETURN_IMMEDIATELY,
                                                        NULL, &pEnumClass );
        CHECK_HRESULT( hResult );
        
        // Set the interface security
        hResult = SetInterfaceSecurity( pEnumClass, m_pAuthIdentity );
        CHECK_HRESULT( hResult );

        // get the data
        hResult = pEnumClass->Next( WBEM_INFINITE, 1, &pClass, &ulReturn );
        CHECK_HRESULT( hResult );

        // get the OS version
        bResult = PropertyGet( pClass, CPV_OS_VERSION, pUserInfo->strOsVersion, 
                                V_NOT_AVAILABLE );
        CHECK_BRESULT( bResult );

        // get the OS type
        bResult = PropertyGet( pClass, CPV_OS_CAPTION, pUserInfo->strOsType, 
                                V_NOT_AVAILABLE );
        CHECK_BRESULT( bResult );

        // enumerate the instances of Win32_ComputerSystem class 
        hResult = m_pWbemServices->CreateInstanceEnum( _bstr_t( CLS_WIN32_CS ),
                                                        WBEM_FLAG_RETURN_IMMEDIATELY | 
                                                        WBEM_FLAG_FORWARD_ONLY, 
                                                        NULL, &pEnumClass );
        
        // check the result of enumeration
        CHECK_HRESULT( hResult );
    
        // set the security on the obtained interface
        hResult = SetInterfaceSecurity( pEnumClass, m_pAuthIdentity );
        CHECK_HRESULT( hResult );

        // get the enumerated objects information
        // NOTE: This needs to be traversed only one time. 
        hResult = pEnumClass->Next( WBEM_INFINITE, 1, &pClass, &ulReturn );
        CHECK_HRESULT( hResult );

        // get the OS config
        bResult = PropertyGet( pClass, CPV_DOMAIN_ROLE, dwDomainRole );
        CHECK_BRESULT( bResult );

        // get the domain name information for later use
        hResult = PropertyGet( pClass, CPV_DOMAIN, m_strADSIDomain );
        CHECK_BRESULT( bResult );

        // get the server name for future use by LDAP
        hResult = PropertyGet( pClass, CPV_NAME, m_strADSIServer );
        CHECK_BRESULT( bResult );

        // 
        // Mapping information of Win32_ComputerSystem's DomainRole property
        // NOTE: Refer to the _DSROLE_MACHINE_ROLE enumeration values in DsRole.h header file
        switch( dwDomainRole )
        {
        case DsRole_RoleStandaloneWorkstation:
            pUserInfo->strOsConfig = VALUE_STANDALONEWORKSTATION;
            break;
        case DsRole_RoleMemberWorkstation:
            pUserInfo->strOsConfig = VALUE_MEMBERWORKSTATION;
            break;
            
        case DsRole_RoleStandaloneServer:
            pUserInfo->strOsConfig = VALUE_STANDALONESERVER;
            break;
            
        case DsRole_RoleMemberServer:
            pUserInfo->strOsConfig = VALUE_MEMBERSERVER;
            break;
            
        case DsRole_RoleBackupDomainController:
            pUserInfo->strOsConfig = VALUE_BACKUPDOMAINCONTROLLER;
            break;
            
        case DsRole_RolePrimaryDomainController:
            pUserInfo->strOsConfig = VALUE_PRIMARYDOMAINCONTROLLER;
            break;

        default:
            break;
        }
    }
    catch(  _com_error & error )
    {
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // release the allocated variables
        SAFEIRELEASE( pEnumClass );
        SAFEIRELEASE( pClass );
        
        return FALSE;
    }
    catch( CHeap_Exception )
    {
        // display the error message
        SetLastError( E_OUTOFMEMORY );
        SaveLastError();
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );
    }


    // release the interface pointers
    SAFEIRELEASE( pEnumClass );
    SAFEIRELEASE( pClass );
        
    return TRUE;
}

/*********************************************************************************************
Routine Description:

    This function displays the security groups for system and user
     
Arguments:
 
    IWbemServices       :   pointer to the name space 
    BOOL                :   set to TRUE if the system o/p is to be displayed

Return Value:
 
    None   
*********************************************************************************************/
VOID CGpResult::DisplaySecurityGroups( IWbemServices *pNameSpace, BOOL bComputer )
{
    HRESULT                     hResult = S_OK;

    BOOL                        bResult = FALSE;
    BOOL                        bGotClass = FALSE;

    ULONG                       ulReturned = 0;
    LONG                        lLBound = 0;
    LONG                        lUBound = 0;

    DWORD                       dwLength = 0;
    
    IWbemClassObject            *pClass = NULL;
    IWbemClassObject            *pName = NULL;
    IWbemClassObject            *pDomain = NULL;
    IEnumWbemClassObject        *pEnumClass = NULL;
    IEnumWbemClassObject        *pEnumDomain = NULL;
        
    VARIANT                     vVarVerbose;
    VARTYPE                     vartype;
    
    TCHAR                       szTemp[ MAX_STRING_LENGTH ];
    TCHAR                       szQueryString[ MAX_STRING_LENGTH ];
    CHString                    strTemp;
    CHString                    strDomain;
    
    SAFEARRAY                   *safeArray = NULL;
    
    try
    {
        ZeroMemory( szTemp, sizeof( szTemp ) );
        ZeroMemory( szQueryString, sizeof( szQueryString ) );

        // Enumerate the classes for the user privelege rights
        hResult = pNameSpace->CreateInstanceEnum( _bstr_t( CLS_RSOP_SESSION ),
                                                    WBEM_FLAG_FORWARD_ONLY |
                                                    WBEM_FLAG_RETURN_IMMEDIATELY, 
                                                    NULL, &pEnumClass );
        CHECK_HRESULT( hResult );

        // Set the interface security
        hResult = SetInterfaceSecurity( pEnumClass, m_pAuthIdentity );
        CHECK_HRESULT( hResult );

        hResult = WBEM_S_NO_ERROR;
        while( WBEM_S_NO_ERROR == hResult )
        {
            // Get the next class
            hResult = pEnumClass->Next( WBEM_INFINITE , 1, &pClass, &ulReturned );
            CHECK_HRESULT( hResult );

            if( ulReturned == 0 )
            {
                // No more classes to enumerate
                // Display N/A if there were no classes
                if( bGotClass == FALSE )
                {
                    ShowMessage( stdout, GetResString( IDS_NEWLINETAB ) );
                    ShowMessage( stdout, V_NOT_AVAILABLE );
                    ShowMessage( stdout, NEW_LINE );
                }
                
                break;
            }
            bGotClass = TRUE;

            // Get the security groups
            if( bComputer == TRUE )
            {
                ShowMessage( stdout, GetResString( IDS_SYS_SG ) );
                ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );
                for( dwLength = lstrlen( GetResString( IDS_SYS_SG ) ); dwLength > 4; dwLength-- )
                {
                    ShowMessage( stdout, GetResString( IDS_DASH ) );
                }
                ShowMessage( stdout, GetResString( IDS_NEWLINETAB ) );
            }
            else
            {
                ShowMessage( stdout, GetResString( IDS_USER_SG ) );
                ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );
                for( dwLength = lstrlen( GetResString( IDS_USER_SG ) ); dwLength > 4; dwLength-- )
                {
                    ShowMessage( stdout, GetResString( IDS_DASH ) );
                }
                ShowMessage( stdout, GetResString( IDS_NEWLINETAB ) );
            }
            
            VariantInit( &vVarVerbose );

            hResult = pClass->Get( _bstr_t(CPV_SEC_GRPS), 0, &vVarVerbose, 0, 0 );
            CHECK_HRESULT_VAR( hResult, vVarVerbose );

            if( vVarVerbose.vt != VT_NULL && vVarVerbose.vt != VT_EMPTY )
            {
                // get the type of the elements in the safe array
                vartype = V_VT( &vVarVerbose ) & ~VT_ARRAY;

                //get the array of strings in to the safe array from the variant
                safeArray = (SAFEARRAY *)vVarVerbose.parray;

                //get the number of elements (subkeys)
                if( safeArray != NULL )
                {
                    hResult = SafeArrayGetLBound( safeArray, 1, &lLBound );
                    CHECK_HRESULT( hResult );

                    hResult = SafeArrayGetUBound( safeArray, 1, &lUBound );
                    CHECK_HRESULT( hResult );
                }
                for( ; lLBound <= lUBound; lLBound++ )
                {
                    bResult = GetPropertyFromSafeArray( safeArray, lLBound, strTemp, vartype );
                    CHECK_BRESULT( bResult );
                    
                    // Got a sid, now get it's coressponding name
                    // form the object path using the SID
                    wsprintf( szTemp, OBJECT_PATH, strTemp );

                    // Get the object
                    hResult = m_pWbemServices->GetObject( _bstr_t( szTemp ), 0, NULL, &pName, NULL );
                    CHECK_HRESULT( hResult );

                    // Get the Account name
                    bResult = PropertyGet( pName, CPV_ACCOUNT_NAME, strTemp, V_NOT_AVAILABLE );

                    // Append the appropriate prefix
                    if( strTemp.Compare( _T( "ANONYMOUS LOGON" ) ) == 0 
                                || strTemp.Compare( _T( "BATCH" ) ) == 0
                                || strTemp.Compare( _T( "DIALUP" ) ) == 0
                                || strTemp.Compare( _T( "INTERACTIVE" ) ) == 0
                                || strTemp.Compare( _T( "SERVICE" ) ) == 0
                                || strTemp.Compare( _T( "SYSTEM" ) ) == 0
                                || strTemp.Compare( _T( "TERMINAL SERVICE USER" ) ) == 0
                                || strTemp.Compare( _T( "PROXY" ) ) == 0
                                || strTemp.Compare( _T( "NETWORK" ) ) == 0
                                || strTemp.Compare( _T( "ENTERPRISE DOMAIN CONTROLLERS" ) ) == 0
                                || strTemp.Compare( _T( "Authenticated Users" ) ) == 0
                                || strTemp.Compare( _T( "RESTRICTED" ) ) == 0
                                || strTemp.Compare( _T( "SELF" ) ) == 0 )
                    {
                        ShowMessage( stdout, _T( "NT AUTHORITY\\" ) );
                    }
                    else if( strTemp.Compare( _T( "Administrators" ) ) == 0 
                                || strTemp.Compare( _T( "Backup Operators" ) ) == 0
                                || strTemp.Compare( _T( "Guests" ) ) == 0
                                || strTemp.Compare( _T( "Power Users" ) ) == 0
                                || strTemp.Compare( _T( "Replicator" ) ) == 0
                                || strTemp.Compare( _T( "Pre-Windows 2000 Compatible Access" ) ) == 0
                                || strTemp.Compare( _T( "Users" ) ) == 0 )
                    {
                        ShowMessage( stdout, _T( "BUILTIN\\" ) );
                    }
                                        
                    ShowMessage( stdout, strTemp );
                    ShowMessage( stdout, GetResString( IDS_NEWLINETAB ) );
                }
            }
            else
            {
                ShowMessage( stdout, V_NOT_AVAILABLE );
                ShowMessage( stdout, NEW_LINE );
            }

            VariantClear(&vVarVerbose);
        }
    }
    
    catch( _com_error & error )
    {
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        VariantClear(&vVarVerbose);
    }

    // release the interface pointers
    SAFEIRELEASE(pEnumClass);
    SAFEIRELEASE(pEnumDomain);
    SAFEIRELEASE(pClass);
    SAFEIRELEASE(pName);
    SAFEIRELEASE(pDomain);

    return;
}

/*********************************************************************************************
Routine Description:

    This function gets the link speed information
     
Arguments:
 
    IWbemServices       :   pointer to the name space. 
    COAUTHIDENTITY      :   pointer to the AuthIdentity structure.

Return Value:
 
    None   
*********************************************************************************************/
VOID DisplayLinkSpeed( IWbemServices *pNameSpace, COAUTHIDENTITY *pAuthIdentity )
{
    HRESULT                     hResult = S_OK;

    BOOL                        bResult = FALSE;
    BOOL                        bGotClass = FALSE;
    BOOL                        bTemp = FALSE;

    ULONG                       ulReturned = 0;
    
    IWbemClassObject            *pClass = NULL;
    IEnumWbemClassObject        *pEnumClass = NULL;
    
    CHString                    strTemp;

    VARIANT                     vVarTemp;
    
    try
    {
        // Get the pointer to ennumerate with
        hResult = pNameSpace->CreateInstanceEnum( _bstr_t( CLS_RSOP_SESSION ),
                                                    WBEM_FLAG_FORWARD_ONLY |
                                                    WBEM_FLAG_RETURN_IMMEDIATELY,
                                                    NULL, &pEnumClass );
        CHECK_HRESULT( hResult );

        // Set the interface security
        hResult = SetInterfaceSecurity( pEnumClass, pAuthIdentity );
        CHECK_HRESULT( hResult );
        
        // Enumerate the classes one by one and get the data
        hResult = WBEM_S_NO_ERROR;
        while( WBEM_S_NO_ERROR == hResult )
        {
            // Get the next class
            hResult = pEnumClass->Next( WBEM_INFINITE , 1, &pClass, &ulReturned );
            CHECK_HRESULT( hResult );

            if( ulReturned == 0 )
            {
                // No more classes to enumerate
                // Display N/A if there were no classes
                if( bGotClass == FALSE )
                {
                    ShowMessage( stdout, GetResString( IDS_NEWLINETAB ) );
                    ShowMessage( stdout, V_NOT_AVAILABLE );
                    ShowMessage( stdout, NEW_LINE );
                }

                break;
            }
            bGotClass = TRUE;

            VariantInit( &vVarTemp );
            hResult = pClass->Get( _bstr_t( CPV_SLOW_LINK ), 0, &vVarTemp, 0, 0 );
            CHECK_HRESULT_VAR( hResult, vVarTemp );

            ShowMessage( stdout, GetResString( IDS_LINK_SPEED ) );
            if( vVarTemp.vt != VT_NULL )
            {
                bTemp = vVarTemp.boolVal;
                if( bTemp == VAR_TRUE )
                {
                    ShowMessage( stdout, GetResString( IDS_YES ) );
                }
                else
                {
                    ShowMessage( stdout, GetResString( IDS_NO ) );
                }   
            }
            else
            {
                ShowMessage( stdout, V_NOT_AVAILABLE );
            }

            ShowMessage( stdout, NEW_LINE );
            VariantClear( &vVarTemp );
        }// while
    }
    catch(_com_error & error)
    {
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        VariantClear( &vVarTemp );
    }

    // release the interface pointers
    SAFEIRELEASE(pEnumClass);
    SAFEIRELEASE(pClass);
    
    return;
}

/*********************************************************************************************
Routine Description:

     This function gets the User name and the domain name from WMI..
     
Arguments:
 
    [in]    szSid           :   string containing the SID
    [out]   szName          :   string to hold the user name
    [out]   szDomain        :   string to hold the domain name

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::GetUserNameFromWMI( TCHAR szSid[], TCHAR szName[], TCHAR szDomain[] )
{
    // Local variables
    HRESULT                     hResult = S_OK;

    BOOL                        bResult = FALSE;
    BOOL                        bGotClass = FALSE;
    BOOL                        bGotDomainInfo = FALSE;
    BOOL                        bUserSpecified = FALSE;

    TCHAR                       szQueryString[ MAX_QUERY_STRING ];
    TCHAR                       szTemp[ MAX_STRING_LENGTH ];
    CHString                    strTemp = NULL_STRING;
    
    IEnumWbemClassObject        *pEnumClass = NULL;
    IWbemClassObject            *pClass =  NULL;

    ULONG                       ulReturn = 0;

    try
    {
        // set the strings to NULL
        ZeroMemory( szQueryString, MAX_QUERY_STRING * sizeof( TCHAR ));
        ZeroMemory( szTemp, MAX_STRING_LENGTH * sizeof( TCHAR ) );

        // Form the query string
        lstrcpy( szTemp, QUERY_USER_NAME );
        FORMAT_STRING( szQueryString, szTemp, szSid );
        
        // execute the respective query
        hResult = m_pWbemServices->ExecQuery( _bstr_t( QUERY_LANGUAGE ), 
                                                _bstr_t( szQueryString ), 
                                                WBEM_FLAG_FORWARD_ONLY | 
                                                WBEM_FLAG_RETURN_IMMEDIATELY,
                                                NULL, &pEnumClass );
        CHECK_HRESULT( hResult );

        // set the security parameters
        hResult = SetInterfaceSecurity( pEnumClass, m_pAuthIdentity );
        CHECK_HRESULT( hResult );
        
        // Get the user name
        hResult = pEnumClass->Next( TIME_OUT_NEXT, 1, &pClass, &ulReturn );
        CHECK_HRESULT( hResult );
            
        // if there are no classes to enumerate break out of the loop
        if( ulReturn == 0 )
        {
            // No classes were retrieved....display msg
            // release the interface pointers and exit
            SAFEIRELEASE( pClass );
            SAFEIRELEASE( pEnumClass );

            return FALSE;

        }
            
        // Get the class property(Name)
        bResult = PropertyGet( pClass, CPV_NAME, strTemp, V_NOT_AVAILABLE );
        CHECK_BRESULT( bResult );

        // Got the name...Store it.
        lstrcpy( szName, strTemp );
            
        // Get and add the domain name if it exists
        bResult = PropertyGet( pClass, CPV_DOMAIN, strTemp, V_NOT_AVAILABLE );
        CHECK_BRESULT( bResult );

        if( strTemp.Compare( V_NOT_AVAILABLE ) != 0 )
        {
            // Got the domain name...Store it.
            lstrcpy( szDomain, strTemp );
        }
    }
    catch(  _com_error & error )
    {
        // erase the last status message
        PrintProgressMsg( m_hOutput, NULL, m_csbi );

        // display the error msg
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // release the interface pointers and exit
        SAFEIRELEASE( pClass );
        SAFEIRELEASE( pEnumClass );

        return FALSE;
    }

    // release the interface pointers and exit
    SAFEIRELEASE( pClass );
    SAFEIRELEASE( pEnumClass );

    return TRUE;
}

/*********************************************************************************************
Routine Description:

    This function gets the threshold link speed information.
     
Arguments:
 
    [in] BOOL   :   set to TRUE if the information is to be retrieved for the computer.

Return Value:
 
    TRUE  on SUCCESS
    FALSE on FAILURE
*********************************************************************************************/
BOOL CGpResult::DisplayThresholdSpeedAndLastTimeInfo( BOOL bComputer )
{
    // Local variables
    HRESULT                 hResult = S_OK;

    HKEY                    hKey = NULL;
    HKEY                    hRemoteKey = NULL;

    IWbemServices           *pDefaultNameSpace = NULL;

    TCHAR                   szTemp[ MAX_STRING_LENGTH ];
    TCHAR                   szServer[ MAX_STRING_LENGTH ];
    TCHAR                   szName[ MAX_STRING_LENGTH ];
    TCHAR                   szTime[ MAX_STRING_LENGTH ];
    TCHAR                   szDate[ MAX_STRING_LENGTH ];

    BOOL                    bResult = FALSE;
    BOOL                    bLocaleChanged = FALSE;
    BOOL                    bConnFlag = TRUE;

    CHString                strTemp;

    DWORD                   dwHkey = 0;
    DWORD                   dwValue;
    DWORD                   dwResult = 0;

    FILETIME                ftWrite;
    FILETIME                ftLocal;

    SYSTEMTIME              systime;

    LCID                    lcid;

    try
    {
        // If we have to get the information from a remote machine then...
        // connect to the remote machine for the last time execution information.
        if ( m_bLocalSystem == FALSE )
        {
            lstrcpy( szServer, m_strServerName );
            lstrcpy( szName, m_strUserName );
            
            bResult = EstablishConnection( szServer, szName, MAX_STRING_LENGTH, 
                                            m_pwszPassword, MAX_STRING_LENGTH, FALSE );
            if( bResult != TRUE )
            {
                strTemp = V_NOT_AVAILABLE;
            }
            else
            {
                switch( GetLastError() )
                {
                    case I_NO_CLOSE_CONNECTION:
                        bConnFlag = FALSE;
                        break;
 
                    case E_LOCAL_CREDENTIALS:
                    case ERROR_SESSION_CREDENTIAL_CONFLICT:
                        bConnFlag = FALSE;
                        break;

                    default:
                        break;
                }
            }
        
            // Connect to the remote registry
            lstrcpy( szServer , _T( "\\\\" ) );
            lstrcat( szServer, m_strServerName );
            dwResult = RegConnectRegistry( szServer, bComputer ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
                                            &hRemoteKey );
            if( dwResult != ERROR_SUCCESS )
            {
                strTemp = V_NOT_AVAILABLE;
            }
        }

        // Open the last time execution information key
        dwResult = RegOpenKeyEx (bComputer ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, 
                                    GROUPPOLICY_PATH, 0, KEY_READ, &hKey);


        if( dwResult != ERROR_SUCCESS )
        {
            strTemp = V_NOT_AVAILABLE;
        }

        // Get the last time execution information
        dwResult = RegQueryInfoKey( hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
                                    NULL, &ftWrite );

        if( dwResult == ERROR_SUCCESS )
        {
            FileTimeToLocalFileTime( &ftWrite, &ftLocal );
            FileTimeToSystemTime( &ftLocal, &systime );


            // verify whether console supports the current locale 100% or not
            lcid = GetSupportedUserLocale( bLocaleChanged );

            // get the formatted date
            GetDateFormat( lcid, 0, &systime, ((bLocaleChanged == TRUE) ? L"MM/dd/yyyy" : NULL), 
                            szDate, SIZE_OF_ARRAY( szDate ) );
            
            // now format the date
            GetTimeFormat( LOCALE_USER_DEFAULT, 0, &systime, ((bLocaleChanged == TRUE) ? L"HH:mm:ss" : NULL), 
                            szTime, SIZE_OF_ARRAY( szTime ) );

            wsprintf( szTemp, LAST_TIME_OP, szDate, szTime );
            strTemp = szTemp;
        }
        else
        {
            strTemp = V_NOT_AVAILABLE;
        }

        // Display the retrieved data
        ShowMessage( stdout, GetResString( IDS_LAST_TIME ) );
        ShowMessage( stdout, strTemp );
        ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );

        // if we have opened a connection then close the same.
        if( m_bLocalSystem == FALSE && bConnFlag == TRUE )
        {
            lstrcpy( szServer, m_strServerName );
            CloseConnection( szServer );
        }

        // Close the registry keys
        if( hKey != NULL )
        {
            RegCloseKey( hKey );
        }
        if( hRemoteKey != NULL )
        {
            RegCloseKey( hRemoteKey );
        }

        // connect to the default namespace
        ConnectWmi( m_pWbemLocator, &pDefaultNameSpace, m_strServerName, 
                    m_strUserName, m_pwszPassword, &m_pAuthIdentity,
                    FALSE, _bstr_t( ROOT_DEFAULT ), &hResult );
        CHECK_HRESULT( hResult );

        // form the key
        if( bComputer == TRUE )
        {           
            dwHkey = HKEY_DEF;
        }
        else
        {
            dwHkey = HKEY_CURRENT_USER_DEF;
        }

        // Get the DC name from where the policy was applied last
        RegQueryValueWMI( pDefaultNameSpace, dwHkey, APPLIED_PATH, FPR_APPLIED_FROM, 
                            strTemp, V_NOT_AVAILABLE );
        
        // remove the forward slashes (UNC) if exist in the begining of the server name
        if ( IsUNCFormat( strTemp ) == TRUE )
        {
            strTemp = strTemp.Mid( 2 );
        }

        // Display the retrieved data
        ShowMessage( stdout, GetResString( IDS_APPLIED_FROM ) );
        ShowMessage( stdout, strTemp );
        ShowMessage( stdout, GetResString( IDS_NEWLINE_TAB ) );

        // Get the threshold link speed information
        RegQueryValueWMI( pDefaultNameSpace, dwHkey, GPRESULT_PATH, FPR_LINK_SPEED_VALUE, dwValue, -1 );
        if( dwValue == -1 )
        {
            strTemp = DEFAULT_LINK_SPEED;
        }
        else
        {
            FORMAT_STRING( szTemp, _T( "%d kbps" ), dwValue );
            strTemp = szTemp;
        }

        // Display the retrieved data
        ShowMessage( stdout, GetResString( IDS_THRESHOLD_LINK_SPEED ) );
        ShowMessage( stdout, strTemp );
        ShowMessage( stdout, NEW_LINE );
    }
    catch(  _com_error & error )
    {
        WMISaveError( error.Error() );
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );

        // release the allocated variables
        SAFEIRELEASE( pDefaultNameSpace );
    
        return FALSE;
    }
    catch( CHeap_Exception )
    {
        // display the error message
        SetLastError( E_OUTOFMEMORY );
        SaveLastError();
        ShowMessage( stderr, GetResString( IDS_ERROR ) );
        ShowMessage( stderr, GetReason() );
    }

    // release the interface pointer
    SAFEIRELEASE( pDefaultNameSpace );

    return TRUE;
}

/*********************************************************************************************
Routine Description: 

    This function checks if the current locale is supported or not.

Arguments: 

    [in] bLocaleChanged

Return Value: 

    LCID of the current locale.
*********************************************************************************************/
LCID GetSupportedUserLocale( BOOL& bLocaleChanged )
{
    // local variables
    LCID lcid;

    // get the current locale
    lcid = GetUserDefaultLCID();

    // check whether the current locale is supported by our tool or not
    // if not change the locale to the english which is our default locale
    bLocaleChanged = FALSE;
    if ( PRIMARYLANGID( lcid ) == LANG_ARABIC || PRIMARYLANGID( lcid ) == LANG_HEBREW ||
         PRIMARYLANGID( lcid ) == LANG_THAI   || PRIMARYLANGID( lcid ) == LANG_HINDI  ||
         PRIMARYLANGID( lcid ) == LANG_TAMIL  || PRIMARYLANGID( lcid ) == LANG_FARSI )
    {
        bLocaleChanged = TRUE;
        lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ), SORT_DEFAULT ); // 0x409;
    }

    // return the locale
    return lcid;
}

/*********************************************************************************************
Routine Description: 

    This function sorts the applied Gpo data in the order applied.

Arguments: 

    [in/out] TARRAY     :   Array to be sorted

Return Value: 

    None
*********************************************************************************************/
VOID SortAppliedData( TARRAY arrAppliedData )
{
    // Local variables
    TARRAY          arrSortedData = NULL;

    DWORD           dwMax = 0;
    DWORD           dwCount = 0;
    DWORD           dwi = 0;
    DWORD           dwOrder = 0;
    DWORD           dwIndex = 0;

    // Create the dynamic array to hold the sorted data temporarily
    arrSortedData = CreateDynamicArray( );

    dwCount = DynArrayGetCount( arrAppliedData );

    // Get the max applied order in the array
    for( dwi = 0; dwi < dwCount; dwi++ )
    {
        dwOrder = DynArrayItemAsDWORD2( arrAppliedData, dwi, COL_ORDER );
        if( dwOrder > dwMax )
        {
            dwMax = dwOrder;
        }
    }

    // Create the sorted array in the descending order of the applied order
    for( dwi = 0; dwi < dwCount; dwi++ )
    {
        // re-set the index variable
        dwIndex = 0;

        // Get the index of the row whose order = dwMax
        while( TRUE )
        {
            dwOrder = DynArrayItemAsDWORD2( arrAppliedData, dwIndex, COL_ORDER );
            if( dwOrder == dwMax )
            {
                break;
            }

            // increment the index
            dwIndex++;

            // Additional check...just in case the order does not exist
            // avoid an AV
            if( dwIndex == dwCount )
            {
                break;
            }
        }

        // Additional check...just in case the order does not exist
        // avoid an AV
        if( dwIndex == dwCount )
        {
            // could not find the index
            // decrement the max order
            dwMax--;

            continue;
        }

        // Store the contents of the row
        DynArrayAppendRow( arrSortedData, COL_MAX );
        DynArraySetString2( arrSortedData, dwi, COL_DATA, 
                            DynArrayItemAsString2( arrAppliedData, dwIndex, COL_DATA ), 0 );
        DynArraySetDWORD2( arrSortedData, dwi, COL_ORDER, dwOrder );

        // decrement the max order
        dwMax--;
    }

    // copy the sorted data onto the applied data array
    for( dwi = 0; dwi < dwCount; dwi++ )
    {
        DynArraySetString2( arrAppliedData, dwi, COL_DATA, 
                            DynArrayItemAsString2( arrSortedData, dwi, COL_DATA ), 0 );
        DynArraySetDWORD2( arrAppliedData, dwi, COL_ORDER, 
                            DynArrayItemAsDWORD2( arrSortedData, dwi, COL_ORDER ) );
    }

    // destroy the temporarily created dynamic array
    DESTROY_ARRAY( arrSortedData );

    return;
}

/*********************************************************************************************
Routine Description: 

    This function retrieves the FQDN from ADSI

Arguments: 

    [out] TCHAR []      :   Array to hold the FQDN
    [in]  BOOL          :   flag to specify wether the FQDN is to be retrieved for
                            the computer or the user
    [in] LPCTSTR        :   The name for whom the FQDN is to be retrieved

Return Value: 

    None
*********************************************************************************************/
VOID CGpResult::GetFQDNFromADSI( TCHAR szFQDN[], BOOL bComputer, LPCTSTR pszName )
{
    // Local variables
    HRESULT                 hResult = S_OK;
    
    HANDLE                  hDS = NULL;

    DWORD                   dwReturn = 0;

    DS_NAME_RESULT          *pNameResult = NULL;
    
    ZeroMemory( szFQDN, MAX_STRING_LENGTH * sizeof( TCHAR ) );



    // Bind to the ADSI directory service
    dwReturn = DsBindWithCred( NULL, m_strADSIDomain, m_pAuthIdentity, &hDS );
    if( dwReturn != NO_ERROR )
    {
        return;
    }

    // Get the FQDN information
    dwReturn = DsCrackNames( hDS, DS_NAME_NO_FLAGS, 
                             bComputer ? DS_DISPLAY_NAME : DS_NT4_ACCOUNT_NAME, DS_FQDN_1779_NAME,
                             1, &pszName, &pNameResult );
    if( dwReturn != NO_ERROR )
    {
        return;
    }

    // store the retrieved FQDN
    lstrcpy( szFQDN, pNameResult->rItems->pName );

    // Free the handle to the ADSI directory services
    DsUnBind( &hDS );

    // Free the allocated memory
    DsFreeNameResult( pNameResult );
    return;
}

BOOL CGpResult::CreateRsopMutex( LPWSTR szMutexName )
{
    BOOL bResult = FALSE;
    SECURITY_ATTRIBUTES sa;
    PSECURITY_DESCRIPTOR psd = NULL;

    //
    // first try to open the mutex object by its name
    // if that fails it means the mutex is not yet created and 
    // so create it now
    //
    m_hMutex = OpenMutex( SYNCHRONIZE, FALSE, szMutexName );
    if ( m_hMutex == NULL )
    {
        // check the error code why it failed to open
        if ( GetLastError() == ERROR_FILE_NOT_FOUND )
        {
            // create the security descriptor -- just set the 
            // Dicretionary Access Control List (DACL)
            // in order to provide security, we will deny WRITE_OWNER and WRITE_DAC
            // permission to Everyone except to the owner 
             bResult = ConvertStringSecurityDescriptorToSecurityDescriptor( 
                 L"D:(D;;WOWD;;;WD)(A;;GA;;;WD)", SDDL_REVISION_1, &psd, NULL );
            if ( bResult == FALSE )
            {
                // we encountered error while creating a security descriptor
                SaveLastError();
                ShowMessage( stderr, GetResString(IDS_ERROR) );
                ShowMessage( stderr, GetReason() );
                return FALSE;
            }

            // initialize the SECURITY_ATTRIBUTES structure
            SecureZeroMemory( &sa, sizeof( SECURITY_ATTRIBUTES ) );
            sa.nLength = sizeof( SECURITY_ATTRIBUTES );
            sa.lpSecurityDescriptor = psd;
            sa.bInheritHandle = FALSE;

            // mutex doesn't exist -- so we need to create it now
            m_hMutex = CreateMutex( &sa, FALSE, szMutexName );
            if (m_hMutex == NULL )
            {
                // we are not able to create the mutex
                // cannot proceed furthur
                SaveLastError();
                ShowMessage( stderr, GetResString(IDS_ERROR) );
                ShowMessage( stderr, GetReason() );
                return FALSE;
            }
            LocalFree(psd);
        }
        else
        {
            // we encounter some error 
            // cannot proceed furthur
            SaveLastError();
            ShowMessage( stderr, GetResString(IDS_ERROR) );
            ShowMessage( stderr, GetReason() );
            return FALSE;
        }
    }

    return TRUE;
}