//////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2000-2002 Microsoft Corporation
//
//  Module Name:
//      WmiHelpers.cpp
//
//  Description:
//      This file contains the implementation of WMI help functions.
//
//  Documentation:
//
//  Header File:
//      WmiHelpers.h
//
//  Maintained By:
//      Galen Barbee (GalenB) 27-Apr-2000
//
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
#include "pch.h"
#include "PrivateInterfaces.h"
#include "CEnumClusCfgNetworks.h"
#include <ClusRtl.h>


//////////////////////////////////////////////////////////////////////////////
//++
//
//  HrGetWMIProperty
//
//  Description:
//      Get a named property from a WMI object.
//
//  Arguments:
//
//  Return Value:
//      S_OK
//          Success
//
//      E_POINTER
//          The IWbemClassObject param is NULL.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetWMIProperty(
    IWbemClassObject *  pWMIObjectIn,
    LPCWSTR             pcszPropertyNameIn,
    ULONG               ulPropertyTypeIn,
    VARIANT *           pVariantOut
    )
{
    TraceFunc1( "pcszPropertyNameIn = '%ws'", pcszPropertyNameIn );

    Assert( pWMIObjectIn != NULL );
    Assert( pcszPropertyNameIn != NULL );
    Assert( pVariantOut != NULL );

    HRESULT hr;
    BSTR    bstrProp = NULL;

    VariantClear( pVariantOut );

    bstrProp = TraceSysAllocString( pcszPropertyNameIn );
    if ( bstrProp == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
        goto Cleanup;
    } // if:

    hr = THR( pWMIObjectIn->Get( bstrProp, 0L, pVariantOut, NULL, NULL ) );
    if ( FAILED( hr ) )
    {
        LogMsg( L"[SRV] Could not get the value for WMI property '%ws'. (hr = %#08x)", bstrProp, hr );
        goto Cleanup;
    } // if:

    //
    //  KB: 28-JUN-2000 GalenB
    //
    //  For reasons only known to WMI boolean properties are of type VT_NULL instead of
    //  VT_BOOL when they are not set or false...
    //
    //  KB: 27-JUL-2000 GalenB
    //
    //  Added the special case check for signature.  We know that signature will be NULL
    //  when the spindle is under ClusDisk control...
    //
    if ( ( ulPropertyTypeIn != VT_BOOL ) && ( NStringCchCompareNoCase( bstrProp, SysStringLen( bstrProp ) + 1, L"Signature", RTL_NUMBER_OF( L"Signature" ) ) != 0 ) )
    {
        if ( pVariantOut->vt != ulPropertyTypeIn )
        {
            LogMsg( L"[SRV] Variant type for WMI Property '%ws' was supposed to be '%d', but was '%d' instead.", pcszPropertyNameIn, ulPropertyTypeIn, pVariantOut->vt );
            hr = THR( E_PROPTYPEMISMATCH );
        } // if:
    } // if:

Cleanup:

    TraceSysFreeString( bstrProp );

    HRETURN( hr );

} //*** HrGetWMIProperty

//////////////////////////////////////////////////////////////////////////////
//++
//
//  HrSetWbemServices
//
//  Description:
//      Set the WBemServices object into the passed in punk.
//
//  Arguments:
//
//  Return Value:
//      S_OK
//          Success
//
//      E_POINTER
//          The IUnknown param is NULL.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrSetWbemServices( IUnknown * punkIn, IWbemServices * pIWbemServicesIn )
{
    TraceFunc( "" );
    Assert( punkIn != NULL );

    HRESULT                 hr;
    IClusCfgWbemServices *  pWbemProvider;

    if ( punkIn == NULL )
    {
        hr = THR( E_POINTER );
        goto Exit;
    } // if:

    hr = punkIn->TypeSafeQI( IClusCfgWbemServices, &pWbemProvider );
    if ( SUCCEEDED( hr ) )
    {
        hr = THR( pWbemProvider->SetWbemServices( pIWbemServicesIn ) );
        pWbemProvider->Release();
    } // if:
    else if ( hr == E_NOINTERFACE )
    {
        hr = S_OK;
    } // else if:
    else
    {
        THR( hr );
    }

Exit:

    HRETURN( hr );

} //*** HrSetWbemServices


//////////////////////////////////////////////////////////////////////////////
//++
//
//  HrSetInitialize
//
//  Description:
//      Initialize the passed in punk.
//
//  Arguments:
//
//  Return Value:
//      S_OK
//          Success
//
//      E_POINTER
//          The IUnknown param is NULL.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrSetInitialize(
    IUnknown *          punkIn,
    IClusCfgCallback *  picccIn,
    LCID                lcidIn
    )
{
    TraceFunc( "" );
    Assert( punkIn != NULL );

    HRESULT                 hr;
    IClusCfgInitialize *    pcci;
    IUnknown *              punkCallback = NULL;

    if ( punkIn == NULL )
    {
        hr = THR( E_POINTER );
        goto Cleanup;
    } // if:

    if ( picccIn != NULL )
    {
        hr = THR( picccIn->TypeSafeQI( IUnknown, &punkCallback ) );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:
    } // if:

    hr = THR( punkIn->TypeSafeQI( IClusCfgInitialize, &pcci ) );
    if ( SUCCEEDED( hr ) )
    {
        hr = STHR( pcci->Initialize( punkCallback, lcidIn ) );
        pcci->Release();
    } // if:
    else if ( hr == E_NOINTERFACE )
    {
        hr = S_OK;
    } // else if:

Cleanup:

    if ( punkCallback != NULL )
    {
        punkCallback->Release();
    } // if:

    HRETURN( hr );

} //*** HrSetInitialize


//////////////////////////////////////////////////////////////////////////////
//++
//
//  HrCreateNetworksEnum
//
//  Description:
//      Create a network enumerator.
//
//  Arguments:
//
//  Return Value:
//      S_OK
//          Success
//
//      E_POINTER
//          The IUnknown param is NULL.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrCreateNetworksEnum(
    IClusCfgCallback *  picccIn,
    LCID                lcidIn,
    IWbemServices *     pIWbemServicesIn,
    IUnknown **         ppunkOut
    )
{
    TraceFunc( "" );

    HRESULT hr;

    if ( ppunkOut == NULL )
    {
        hr = THR( E_POINTER );
        LogMsg( L"[SRV] HrCreateNetworksEnum() was given a NULL pointer argument." );
        goto Exit;
    } // if:

    hr = THR( CEnumClusCfgNetworks::S_HrCreateInstance( ppunkOut ) );
    if ( FAILED( hr ) )
    {
        goto Exit;
    } // if:

    *ppunkOut = TraceInterface( L"CEnumClusCfgNetworks", IUnknown, *ppunkOut, 1 );

    hr = THR( HrSetInitialize( *ppunkOut, picccIn, lcidIn ) );
    if ( FAILED( hr ) )
    {
        goto Exit;
    } // if:

    hr = THR( HrSetWbemServices( *ppunkOut, pIWbemServicesIn ) );
    if ( FAILED( hr ) )
    {
        goto Exit;
    } // if:

Exit:

    HRETURN( hr );

} //*** HrCreateNetworksEnum

/*
/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrLoadOperatingSystemInfo
//
//  Description:
//      Load the Win32_OperatingSystem object and determine which partition
//      were booted and have the OS installed on them.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrLoadOperatingSystemInfo(
    IClusCfgCallback *  picccIn,
    IWbemServices *     pIWbemServicesIn,
    BSTR *              pbstrBootDeviceOut,
    BSTR *              pbstrSystemDeviceOut
    )
{
    TraceFunc( "" );
    Assert( picccIn != NULL );
    Assert( pIWbemServicesIn != NULL );
    Assert( pbstrBootDeviceOut != NULL );
    Assert( pbstrSystemDeviceOut != NULL );

    HRESULT     hr = S_OK;

    BSTR                    bstrClass;
    IEnumWbemClassObject *  pOperatingSystems = NULL;
    ULONG                   ulReturned;
    IWbemClassObject *      pOperatingSystem = NULL;
    int                     c;
    VARIANT                 var;
    HRESULT                 hrTemp;

    VariantInit( &var );

    bstrClass = TraceSysAllocString( L"Win32_OperatingSystem" );
    if ( bstrClass == NULL )
    {
        goto OutOfMemory;
    } // if:

    hr = THR( pIWbemServicesIn->CreateInstanceEnum( bstrClass, WBEM_FLAG_SHALLOW, NULL, &pOperatingSystems ) );
    if ( FAILED( hr ) )
    {
        hrTemp = THR( HrSendStatusReport(
              picccIn
            , TASKID_Major_Find_Devices
            , TASKID_Minor_WMI_OS_Qry_Failed
            , 0
            , 1
            , 1
            , hr
            , IDS_ERROR_WMI_OS_QRY_FAILED
            , IDS_ERROR_WMI_OS_QRY_FAILED_REF
            ) );
        if ( FAILED( hrTemp ) )
        {
            hr = hrTemp;
        } // if:

        goto Cleanup;
    } // if:

    for ( c = 1; ; c++ )
    {
        hr = pOperatingSystems->Next( WBEM_INFINITE, 1, &pOperatingSystem, &ulReturned );
        if ( ( hr == S_OK ) && ( ulReturned == 1 ) )
        {
            Assert( c < 2 );        // only expect one of these!

            hr = THR( HrGetWMIProperty( pOperatingSystem, L"BootDevice", VT_BSTR, &var ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            *pbstrBootDeviceOut = TraceSysAllocString( var.bstrVal );
            if ( *pbstrBootDeviceOut == NULL )
            {
                goto OutOfMemory;
            } // if:

            VariantClear( &var );

            hr = THR( HrGetWMIProperty( pOperatingSystem, L"SystemDevice", VT_BSTR, &var ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            *pbstrSystemDeviceOut = TraceSysAllocString( var.bstrVal );
            if ( *pbstrSystemDeviceOut == NULL )
            {
                goto OutOfMemory;
            } // if:

            pOperatingSystem->Release();
            pOperatingSystem = NULL;
        } // if:
        else if ( ( hr == S_FALSE ) && ( ulReturned == 0 ) )
        {
            hr = S_OK;
            break;
        } // else if:
        else
        {
            hrTemp = THR( HrSendStatusReport(
                              picccIn
                            , TASKID_Major_Find_Devices
                            , TASKID_Minor_WMI_OS_Qry_Next_Failed
                            , 0
                            , 1
                            , 1
                            , hr
                            , IDS_ERROR_WMI_OS_QRY_FAILED
                            , IDS_ERROR_WMI_OS_QRY_FAILED_REF
                            ) );
            if ( FAILED( hrTemp ) )
            {
                hr = hrTemp;
            } // if:

            goto Cleanup;
        } // else:
    } // for:

    goto Cleanup;

OutOfMemory:

    hr = THR( E_OUTOFMEMORY );

Cleanup:

    VariantClear( &var );

    if ( pOperatingSystem != NULL )
    {
        pOperatingSystem->Release();
    } // if:

    if ( pOperatingSystems != NULL )
    {
        pOperatingSystems->Release();
    } // if:

    TraceSysFreeString( bstrClass );

    HRETURN( hr );

} //*** HrLoadOperatingSystemInfo
*/

/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrConvertDeviceVolumeToLogicalDisk
//
//  Description:
//      Convert a device volume to a logical disk.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrConvertDeviceVolumeToLogicalDisk(
    BSTR    bstrDeviceVolumeIn,
    BSTR *  pbstrLogicalDiskOut
    )
{
    TraceFunc( "" );
    Assert( pbstrLogicalDiskOut != NULL );

    HRESULT     hr = S_OK;
    BOOL        fRet;
    size_t      cchMountPoint;
    WCHAR *     pszMountPoint = NULL;
    WCHAR       szVolume[  MAX_PATH ];
    DWORD       sc;
    DWORD       cchPaths = 16;
    WCHAR *     pszPaths = NULL;
    int         c;
    DWORD       cch;
    WCHAR *     pszEOS = NULL;

    cchMountPoint = wcslen( g_szNameSpaceRoot ) + wcslen( bstrDeviceVolumeIn ) + 2;
    pszMountPoint = new WCHAR[ cchMountPoint ];
    if ( pszMountPoint == NULL )
    {
        goto OutOfMemory;
    } // if:

    hr = THR( StringCchCopyW( pszMountPoint, cchMountPoint, g_szNameSpaceRoot ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( StringCchCatExW( pszMountPoint, cchMountPoint, bstrDeviceVolumeIn, &pszEOS, NULL, 0 ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    //
    //  Append a trailing \ and re-terminate the string.
    //

    *pszEOS = L'\\';
    *( pszEOS + 1 ) = L'\0';

    fRet = GetVolumeNameForVolumeMountPoint( pszMountPoint, szVolume, ARRAYSIZE( szVolume ) );
    if ( !fRet )
    {
        sc = TW32( GetLastError() );
        hr = HRESULT_FROM_WIN32( sc );

        LogMsg( L"[SRV] GetVolumeNameForVolumeMountPoint() failed.  Mount point is '%ws'. (hr = %#08x)", pszMountPoint, hr );

        //
        //  GetVolumeNameForVolumeMountPoint() is no longer supported for IA64 EFI partitions.  If the error is
        //  ERROR_INVALID_FUNCTION then we should try to get the device number using an IOCTL.
        //
        if ( HRESULT_CODE( hr ) == ERROR_INVALID_FUNCTION )
        {
            LogMsg( L"[SRV] Device volume '%ws' must be an IA64 EFI volume.", bstrDeviceVolumeIn );
        } // if:

        goto Cleanup;
    } // if:

    pszPaths = new WCHAR[ cchPaths ];
    if ( pszPaths == NULL )
    {
        goto OutOfMemory;
    } // if:

    //
    //  KB: 16 JAN 2001 GalenB
    //
    //  Since the device name that is passed in is for a volume there will never be more than
    //  one logical disk in the multisz pszPaths.
    //
    for ( c = 0; ; c++ )
    {
        Assert( c < 2 );            // expect to go through here no more than twice.

        fRet = GetVolumePathNamesForVolumeName( szVolume, pszPaths, cchPaths, &cch );
        if ( fRet )
        {
            break;
        } // if:
        else
        {
            sc = GetLastError();
            if ( sc == ERROR_MORE_DATA )
            {
                cchPaths = cch;

                delete [] pszPaths;
                pszPaths = new WCHAR[ cchPaths ];
                if ( pszPaths == NULL )
                {
                    goto OutOfMemory;
                } // if:

                continue;
            } // if:

            hr = THR( HRESULT_FROM_WIN32( sc ) );
            LogMsg( L"[SRV] GetVolumePathNamesForVolumeName() failed. Volume is is '%ws'. (hr = %#08x)", szVolume, hr );
            goto Cleanup;
        } // else:
    } // for:

    *pbstrLogicalDiskOut = TraceSysAllocString( pszPaths );
    if ( *pbstrLogicalDiskOut == NULL )
    {
        goto OutOfMemory;
    } // if:

    goto Cleanup;

OutOfMemory:

    hr = THR( E_OUTOFMEMORY );

Cleanup:

    delete [] pszPaths;

    delete [] pszMountPoint;

    HRETURN( hr );

} //*** HrConvertDeviceVolumeToLogicalDisk


/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrConvertDeviceVolumeToWMIDeviceID
//
//  Description:
//      Since IA64 EFI partitions no longer support the call to
//      GetVolumeNameForVolumeMountPoint() to convert the device name
//      into a logical disk, since there will not longer be logical disks
//      for these partitions.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrConvertDeviceVolumeToWMIDeviceID(
    BSTR    bstrDeviceVolumeIn,
    BSTR *  pbstrWMIDeviceIDOut
    )
{
    TraceFunc( "" );

    HRESULT                 hr = S_OK;
    HANDLE                  hVolume = NULL;
    DWORD                   dwSize;
    DWORD                   sc;
    STORAGE_DEVICE_NUMBER   sdnDevNumber;
    BOOL                    fRet;
    size_t                  cchDevice;
    WCHAR *                 pszDevice = NULL;
    WCHAR                   sz[ 64 ];

    cchDevice = wcslen( g_szNameSpaceRoot ) + wcslen( bstrDeviceVolumeIn ) + 2;
    pszDevice = new WCHAR[ cchDevice ];
    if ( pszDevice == NULL )
    {
        goto OutOfMemory;
    } // if:

    hr = THR( StringCchCopyW( pszDevice, cchDevice, g_szNameSpaceRoot ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( StringCchCatW( pszDevice, cchDevice, bstrDeviceVolumeIn ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    //
    // get handle to partition
    //

    hVolume = CreateFileW(
                        pszDevice
                      , GENERIC_READ
                      , FILE_SHARE_READ
                      , NULL
                      , OPEN_EXISTING
                      , FILE_ATTRIBUTE_NORMAL
                      , NULL
                      );

    if ( hVolume == INVALID_HANDLE_VALUE )
    {
        sc = TW32( GetLastError() );
        hr = HRESULT_FROM_WIN32( sc );
        goto Cleanup;
    } // if:

    //
    // issue storage class ioctl to get drive and partition numbers
    // for this device
    //

    fRet = DeviceIoControl(
                          hVolume
                        , IOCTL_STORAGE_GET_DEVICE_NUMBER
                        , NULL
                        , 0
                        , &sdnDevNumber
                        , sizeof( sdnDevNumber )
                        , &dwSize
                        , NULL
                        );
    if ( !fRet )
    {
        sc = TW32( GetLastError() );
        hr = HRESULT_FROM_WIN32( sc );
        goto Cleanup;
    } // if:

    hr = THR( StringCchPrintfW( sz, ARRAYSIZE( sz ), g_szPhysicalDriveFormat, sdnDevNumber.DeviceNumber ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    *pbstrWMIDeviceIDOut = SysAllocString( sz );
    if ( *pbstrWMIDeviceIDOut == NULL )
    {
        goto OutOfMemory;
    } // if:

    goto Cleanup;

OutOfMemory:

    hr = THR( E_OUTOFMEMORY );
    LogMsg( L"[SRV] HrConvertDeviceVolumeToWMIDeviceID() is out of memory. (hr = %#08x)", hr );

Cleanup:

    if ( hVolume != NULL )
    {
        CloseHandle( hVolume );
    } // if:

    delete [] pszDevice;

    HRETURN( hr );

} //*** HrConvertDeviceVolumeToWMIDeviceID


/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrGetPageFileLogicalDisks
//
//  Description:
//      Mark the drives that have paging files on them.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetPageFileLogicalDisks(
    IClusCfgCallback *  picccIn,
    IWbemServices *     pIWbemServicesIn,
    WCHAR               szLogicalDisksOut[ 26 ],
    int *               pcLogicalDisksOut
    )
{
    TraceFunc( "" );

    HRESULT                 hr = S_FALSE;
    IEnumWbemClassObject *  pPagingFiles = NULL;
    BSTR                    bstrClass;
    ULONG                   ulReturned;
    IWbemClassObject *      pPagingFile = NULL;
    VARIANT                 var;
    int                     idx;
    HRESULT                 hrTemp;

    bstrClass = TraceSysAllocString( L"Win32_PageFile" );
    if ( bstrClass == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
        goto Cleanup;
    } // if:

    hr = THR( pIWbemServicesIn->CreateInstanceEnum( bstrClass, WBEM_FLAG_SHALLOW, NULL, &pPagingFiles ) );
    if ( FAILED( hr ) )
    {
        hrTemp = THR( HrSendStatusReport(
                          picccIn
                        , TASKID_Major_Find_Devices
                        , TASKID_Minor_WMI_PageFile_Qry_Failed
                        , 0
                        , 1
                        , 1
                        , hr
                        , IDS_ERROR_WMI_PAGEFILE_QRY_FAILED
                        , IDS_ERROR_WMI_PAGEFILE_QRY_FAILED_REF
                        ) );
        if ( FAILED( hrTemp ) )
        {
            hr = hrTemp;
        } // if:

        goto Cleanup;
    } // if:

    VariantInit( &var );

    for ( idx = 0; idx < sizeof( szLogicalDisksOut ); idx++ )
    {
        hr = pPagingFiles->Next( WBEM_INFINITE, 1, &pPagingFile, &ulReturned );
        if ( ( hr == S_OK ) && ( ulReturned == 1 ) )
        {
            VariantClear( &var );

            hr = THR( HrGetWMIProperty( pPagingFile, L"Drive", VT_BSTR, &var ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            CharUpper( var.bstrVal );

            szLogicalDisksOut[ idx ] = var.bstrVal[ 0 ];

            pPagingFile->Release();
            pPagingFile = NULL;
        } // if:
        else if ( ( hr == S_FALSE ) && ( ulReturned == 0 ) )
        {
            hr = S_OK;
            break;
        } // else if:
        else
        {
            hrTemp = THR( HrSendStatusReport(
                              picccIn
                            , TASKID_Major_Find_Devices
                            , TASKID_Minor_WMI_PageFile_Qry_Next_Failed
                            , 0
                            , 1
                            , 1
                            , hr
                            , IDS_ERROR_WMI_PAGEFILE_QRY_FAILED
                            , IDS_ERROR_WMI_PAGEFILE_QRY_FAILED_REF
                            ) );
            if ( FAILED( hrTemp ) )
            {
                hr = hrTemp;
            } // if:

            goto Cleanup;
        } // else:
    } // for:

    if ( pcLogicalDisksOut != NULL )
    {
        *pcLogicalDisksOut = idx;
    } // if:

Cleanup:

    VariantClear( &var );

    TraceSysFreeString( bstrClass );

    if ( pPagingFile != NULL )
    {
        pPagingFile->Release();
    } // if:

    if ( pPagingFiles != NULL )
    {
        pPagingFiles->Release();
    } // if:

    HRETURN( hr );

} //*** HrGetPageFileLogicalDisks


/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrGetSystemDevice
//
//  Description:
//      Returns the system (booted) device.
//
//  Arguments:
//
//
//  Return Value:
//      None.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetSystemDevice( BSTR * pbstrSystemDeviceOut )
{
    TraceFunc( "" );
    Assert( pbstrSystemDeviceOut != NULL );

    HRESULT hr = S_OK;
    DWORD   sc;
    HKEY    hKey = NULL;
    WCHAR * pszSystemDevice = NULL;
    DWORD   cbSystemDevice = 0; // no need to but prefix complains #318170
    DWORD   dwType;

    sc = TW32( RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System\\Setup", 0, KEY_READ, &hKey ) );
    if ( sc != ERROR_SUCCESS )
    {
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] RegOpenKeyEx() failed. (hr = %#08x)", hr );
        goto Cleanup;
    } // if:

    sc = TW32( RegQueryValueEx( hKey, L"SystemPartition", NULL, NULL, NULL, &cbSystemDevice ) );
    if ( sc != ERROR_SUCCESS )
    {
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] RegQueryValueEx() failed. (hr = %#08x)", hr );
        goto Cleanup;
    } // if:

    pszSystemDevice = new WCHAR[ cbSystemDevice / sizeof( WCHAR ) ];
    if ( pszSystemDevice == NULL )
    {
        goto OutOfMemory;
    } // if:

    sc = TW32( RegQueryValueEx( hKey, L"SystemPartition", NULL, &dwType, (BYTE *) pszSystemDevice, &cbSystemDevice ) );
    if ( sc != ERROR_SUCCESS )
    {
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] RegQueryValueEx() failed. (hr = %#08x)", hr );
        goto Cleanup;
    } // if:

    if (dwType != REG_SZ) 
    {
        hr = ERROR_DATATYPE_MISMATCH;
        LogMsg( L"[SRV] RegQueryValueEx() invalid type %d", dwType);
        goto Cleanup;
    } // if:

    *pbstrSystemDeviceOut = TraceSysAllocString( pszSystemDevice );
    if ( *pbstrSystemDeviceOut == NULL )
    {
        goto OutOfMemory;
    } // if:

    goto Cleanup;

OutOfMemory:

    hr = THR( E_OUTOFMEMORY );
    LogMsg( L"[SRV] HrGetSystemDevice() is out of memory. (hr = %#08x)", hr );

Cleanup:

    delete [] pszSystemDevice;

    if ( hKey != NULL )
    {
        RegCloseKey( hKey );
    } // if:

    HRETURN( hr );

} //*** HrGetSystemDevice


/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrGetBootLogicalDisk
//
//  Description:
//      Returns the boot (system) logical disk.
//
//  Arguments:
//
//
//  Return Value:
//      None.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetBootLogicalDisk( BSTR * pbstrBootLogicalDiskOut )
{
    TraceFunc( "" );
    Assert( pbstrBootLogicalDiskOut != NULL );

    HRESULT hr = S_OK;
    DWORD   sc;
    WCHAR   szWindowsDir[ MAX_PATH ];
    WCHAR   szVolume[ MAX_PATH ];
    BOOL    fRet;

    sc = GetWindowsDirectoryW( szWindowsDir, ARRAYSIZE( szWindowsDir ) );
    if ( sc == 0 )
    {
        sc = TW32( GetLastError() );
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] GetWindowsDirectory() failed. (hr = %#08x)", hr );
        goto Exit;
    } // if:

    fRet = GetVolumePathName( szWindowsDir, szVolume, ARRAYSIZE( szVolume ) );
    if ( !fRet )
    {
        sc = TW32( GetLastError() );
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] GetVolumePathName() failed. (hr = %#08x)", hr );
        goto Exit;
    } // if:

    *pbstrBootLogicalDiskOut = TraceSysAllocString( szVolume );
    if ( *pbstrBootLogicalDiskOut == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
    } // if:

Exit:

    HRETURN( hr );

} //*** HrGetBootLogicalDisk


/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrCheckSecurity
//
//  Description:
//      Checks the server security level.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Secutity is high enough.
//
//      E_ACCESSDENIED
//          Security is not high enough.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrCheckSecurity( void )
{
    TraceFunc( "" );

    HRESULT             hr = S_OK;
    IServerSecurity *   piss = NULL;
    DWORD               dwAuthnSvc;
    DWORD               dwAuthzSvc;
    BSTR                bstrServerPrincName = NULL;
    DWORD               dwAuthnLevel;
    DWORD               dwImpersonationLevel;
    void *              pvPrivs = NULL;
    DWORD               dwCapabilities;

    hr = THR( CoGetCallContext( IID_IServerSecurity, reinterpret_cast< void ** >( &piss  ) ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( piss->QueryBlanket(
                &dwAuthnSvc,
                &dwAuthzSvc,
                &bstrServerPrincName,
                &dwAuthnLevel,
                &dwImpersonationLevel,
                &pvPrivs,
                &dwCapabilities ) );

Cleanup:

    SysFreeString( bstrServerPrincName );

    if ( piss != NULL )
    {
        piss->Release();
    } // if:

    HRETURN( hr );

} //*** HrCheckSecurity


/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrGetCrashDumpLogicalDisk
//
//  Description:
//      Returns the logical disk of the system crash dump file.
//
//  Arguments:
//      pbstrCrashDumpLogicalDiskOut
//
//  Return Value:
//      S_OK
//          Success.
//
//      Other HRESULTs as errors.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetCrashDumpLogicalDisk(
    BSTR * pbstrCrashDumpLogicalDiskOut
    )
{
    TraceFunc( "" );
    Assert( pbstrCrashDumpLogicalDiskOut != NULL );

    HRESULT hr = S_OK;
    DWORD   sc;
    HKEY    hKey = NULL;
    WCHAR * pszDumpFile = NULL;
    WCHAR * pszExpandedDumpFile = NULL;
    DWORD   cbDumpFile = 0; // no need to but prefix complains #318170
    BSTR    bstr = NULL;
    DWORD dwType;

    sc = TW32( RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\CrashControl", 0, KEY_READ, &hKey ) );
    if ( sc != ERROR_SUCCESS )
    {
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] [HrGetCrashDumpLogicalDisk] RegOpenKeyEx() failed. (hr = %#08x)", hr );
        goto Cleanup;
    } // if:

    sc = TW32( RegQueryValueEx( hKey, L"DumpFile", NULL, NULL, NULL, &cbDumpFile ) );
    if ( sc != ERROR_SUCCESS )
    {
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] [HrGetCrashDumpLogicalDisk] RegQueryValueEx() failed. (hr = %#08x)", hr );
        goto Cleanup;
    } // if:

    pszDumpFile = new WCHAR[ cbDumpFile / sizeof( WCHAR ) ];
    if ( pszDumpFile == NULL )
    {
        goto OutOfMemory;
    } // if:

    sc = TW32( RegQueryValueEx( hKey, L"DumpFile", NULL, &dwType, (BYTE *) pszDumpFile, &cbDumpFile ) );
    if ( sc != ERROR_SUCCESS )
    {
        hr = HRESULT_FROM_WIN32( sc );
        LogMsg( L"[SRV] [HrGetCrashDumpLogicalDisk] RegQueryValueEx() failed. (hr = %#08x)", hr );
        goto Cleanup;
    } // if:

    if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
    {
        hr = ERROR_DATATYPE_MISMATCH;
        LogMsg( L"[SRV] RegQueryValueEx() invalid type %d", dwType);
        goto Cleanup;
    } // if:

    pszExpandedDumpFile = ClRtlExpandEnvironmentStrings( pszDumpFile );     // must use LocalFree()
    if ( pszExpandedDumpFile == NULL )
    {
        hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
        goto Cleanup;
    } // if:

    bstr = TraceSysAllocString( pszExpandedDumpFile );
    if ( bstr == NULL )
    {
        goto OutOfMemory;
    } // if:

    *pbstrCrashDumpLogicalDiskOut = bstr;
    bstr = NULL;

    goto Cleanup;

OutOfMemory:

    hr = THR( E_OUTOFMEMORY );
    LogMsg( L"[SRV] [HrGetCrashDumpLogicalDisk] is out of memory. (hr = %#08x)", hr );

Cleanup:

    LocalFree( pszExpandedDumpFile );
    TraceSysFreeString( bstr );

    delete [] pszDumpFile;

    if ( hKey != NULL )
    {
        RegCloseKey( hKey );
    } // if:

    HRETURN( hr );

} //*** HrGetCrashDumpLogicalDisk

/*
/////////////////////////////////////////////////////////////////////////////
//++
//
//  HrGetVolumeInformation
//
//  Description:
//      Wrapper for the Win32 API GetVolumeInformation.
//
//  Arguments:
//      pcszRootPathIn
//          The path to the volume to get the information about.
//
//      pdwFlagsOut
//          The flags returned.
//
//      pbstrFileSystemOut
//          The filesystem on the volume.
//
//  Return Value:
//      S_OK
//          Success.
//
//      HRESULT errors.
//
//  Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetVolumeInformation(
      const WCHAR * pcszRootPathIn
    , DWORD *       pdwFlagsOut
    , BSTR *        pbstrFileSystemOut
    )
{
    TraceFunc( "" );
    Assert( pcszRootPathIn != NULL );

    HRESULT hr = S_OK;
    int     cTemp;
    BOOL    fRet;
    WCHAR * psz = NULL;
    DWORD   cch = 32;
    DWORD   sc = ERROR_SUCCESS;
    DWORD   dwFlags = 0;

    psz = new WCHAR[ cch ];
    if ( psz == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
        goto Cleanup;
    } // if:

    for ( cTemp = 0 ; cTemp < 3; cTemp++ )
    {
        fRet = GetVolumeInformationW(
                      pcszRootPathIn
                    , NULL
                    , 0
                    , NULL
                    , NULL
                    , &dwFlags
                    , psz
                    , cch
                    );
        if ( fRet == FALSE )
        {
            sc = GetLastError();
            if ( sc == ERROR_BAD_LENGTH )
            {
                //
                //  Grow the buffer and try again.
                //

                cch += 32;

                delete [] psz;

                psz = new WCHAR[ cch ];
                if ( psz == NULL )
                {
                    hr = THR( E_OUTOFMEMORY );
                    goto Cleanup;
                } // if:

                continue;
            } // if:
            else
            {
                TW32( sc );
                hr = HRESULT_FROM_WIN32( sc );
                goto Cleanup;
            } // else:
        } // if:
        else
        {
            sc = ERROR_SUCCESS;
            break;
        } // else:
    } // for:

    if ( sc != ERROR_SUCCESS )
    {
        TW32( sc );
        hr = HRESULT_FROM_WIN32( sc );
        goto Cleanup;
    } // if:

    if ( pdwFlagsOut != NULL )
    {
        *pdwFlagsOut = dwFlags;
    } // if:

    if ( pbstrFileSystemOut != NULL )
    {
        *pbstrFileSystemOut = TraceSysAllocString( psz );
        if ( *pbstrFileSystemOut == NULL )
        {
            hr = THR( E_OUTOFMEMORY );
            goto Cleanup;
        } // if:
    } // if:

Cleanup:

    delete [] psz;

    HRETURN( hr );

} //*** HrGetVolumeInformation
*/

/////////////////////////////////////////////////////////////////////////////
//++
//
//  TraceWMIProperties
//
//  Description:
//      Trace the properties to the debugger.
//
//  Arguments:
//
//
//  Return Value:
//      None.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
#ifdef DEBUG
void
TraceProperties( IWbemClassObject * pDiskIn )
{
    TraceFunc( "" );

    HRESULT hr = S_FALSE;
    VARIANT var;
    BSTR    bstrPropName;
    CIMTYPE cimType;
    LONG    lFlags;

    VariantInit( &var );

    hr = THR( pDiskIn->BeginEnumeration( 0 ) );
    if ( FAILED( hr ) )
    {
        goto Exit;
    } // if:

    for ( ; ; )
    {
        VariantClear( &var );

        hr = pDiskIn->Next( 0, &bstrPropName, &var, &cimType, &lFlags );
        if ( FAILED( hr ) )
        {
            break;
        } // if:
        else if ( hr == S_OK )
        {
            if ( var.vt == VT_BSTR )
            {
                DebugMsg( L"Property %ws = %ws", bstrPropName, var.bstrVal );
            } // if:

            if ( var.vt == VT_I4 )
            {
                DebugMsg( L"Property %ws = %d", bstrPropName, var.iVal );
            } // if:

            if ( var.vt == VT_BOOL )
            {
                if ( var.boolVal == VARIANT_TRUE )
                {
                    DebugMsg( L"Property %ws = True", bstrPropName );
                } // if:
                else
                {
                    DebugMsg( L"Property %ws = False", bstrPropName );
                } // else:
            } // if:

            if ( var.vt == VT_NULL )
            {
                DebugMsg( L"Property %ws = NULL", bstrPropName );
            } // if:

            TraceSysFreeString( bstrPropName );
            VariantClear( &var );
        } // else if:
        else
        {
            break;
        } // else:
    } // for:

Exit:

    VariantClear( &var );

    TraceFuncExit( );

} //*** TraceWMIProperties
#endif