/*++

Copyright (C) 1995-1999 Microsoft Corporation

Module Name:

    wmi.c

Abstract:

    WMI interface functions exported by PDH.DLL

--*/

#include <windows.h>
#include <winperf.h>
#include "mbctype.h"
#include <mbctype.h>
#include <pdh.h>
#include <pdhmsg.h>
#include <assert.h>
#include "wbemdef.h"
#include "pdhitype.h"
#include "pdhidef.h"
#include "strings.h"

#define PERF_TIMER_FIELD \
    (PERF_TIMER_TICK | PERF_TIMER_100NS | PERF_OBJECT_TIMER)

__inline 
VOID
PdhiSysFreeString( 
    BSTR *x
) 
{
    if (x != NULL) {
        if (*x != NULL) {
            SysFreeString(*x);
            *x = NULL;
        }
    }
}

// at this point, calling the refresher while adding items to the refresher
// doesn't work. so for the time being, we'll use this interlock to prevent
// a collision
static BOOL bDontRefresh = FALSE;

// Prototype
HRESULT WbemSetProxyBlanket(
    IUnknown                 *pInterface,
    DWORD                     dwAuthnSvc,
    DWORD                     dwAuthzSvc,
    OLECHAR                  *pServerPrincName,
    DWORD                     dwAuthLevel,
    DWORD                     dwImpLevel,
    RPC_AUTH_IDENTITY_HANDLE  pAuthInfo,
    DWORD                     dwCapabilities );

HRESULT SetWbemSecurity( IUnknown *pInterface )
{
    return WbemSetProxyBlanket( pInterface, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
                RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
}


// This is the same timeout value the refresher uses so we can pretend
// we're doing the same thing.

#define WBEM_REFRESHER_TIMEOUT  10000

//  This class is designed to encapsulate the IWbemRefresher functionality
//  The definition and implementation are all in this source file

class CWbemRefresher : public IUnknown
{
protected:
    LONG                        m_lRefCount;

    // The primitives that will control the multithreading stuff
    HANDLE                      m_hQuitEvent;
    HANDLE                      m_hDoWorkEvent;
    HANDLE                      m_hWorkDoneEvent;
    HANDLE                      m_hRefrMutex;
    HANDLE                      m_hInitializedEvent;
    HANDLE                      m_hThread;
    DWORD                       m_dwThreadId;
    BOOL                        m_fThreadOk;

    // These are the pass-thru variables we will use as placeholders
    // as we perform our operations.  Note that a couple are missing.
    // This is because we are not really using them in our code, so
    // no sense in adding anything we don't really need.

    IStream*            m_pNSStream;
    LPCWSTR             m_wszPath;
    LPCWSTR             m_wszClassName;
    long                m_lFlags;
    IWbemClassObject**  m_ppRefreshable;
    IWbemHiPerfEnum**   m_ppEnum;
    long*               m_plId;
    long                m_lId;
    HRESULT             m_hOperResult;

    // This is what will be set to indicate to the thread which operation
    // it is supposed to perform.

    typedef enum
    {
        eRefrOpNone,
        eRefrOpRefresh,
        eRefrOpAddByPath,
        eRefrOpAddEnum,
        eRefrOpRemove,
        eRefrOpLast
    }   tRefrOps;

    tRefrOps            m_eRefrOp;

    // Thread ebtryt
    class XRefresher : public IWbemRefresher
    {
    protected:
        CWbemRefresher* m_pOuter;

    public:
        XRefresher( CWbemRefresher* pOuter ) : m_pOuter( pOuter ) {};
        ~XRefresher()   {};

        STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj);
        STDMETHOD_(ULONG, AddRef)(THIS);
        STDMETHOD_(ULONG, Release)(THIS);
        STDMETHOD(Refresh)(long lFlags);

    } m_xRefresher;

    class XConfigRefresher : public IWbemConfigureRefresher
    {
    protected:
        CWbemRefresher* m_pOuter;

    public:
        XConfigRefresher( CWbemRefresher* pOuter ) : m_pOuter( pOuter ) {};
        ~XConfigRefresher() {};

        STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj);
        STDMETHOD_(ULONG, AddRef)(THIS);
        STDMETHOD_(ULONG, Release)(THIS);
        STDMETHOD(AddObjectByPath)(IWbemServices* pNamespace, LPCWSTR wszPath,
            long lFlags, IWbemContext* pContext,
            IWbemClassObject** ppRefreshable, long* plId);

        STDMETHOD(AddObjectByTemplate)(IWbemServices* pNamespace,
            IWbemClassObject* pTemplate,
            long lFlags, IWbemContext* pContext,
            IWbemClassObject** ppRefreshable, long* plId);

        STDMETHOD(AddRefresher)(IWbemRefresher* pRefresher, long lFlags,
            long* plId);

        STDMETHOD(Remove)(long lId, long lFlags);

        STDMETHOD(AddEnum)( IWbemServices*  pNamespace, LPCWSTR wscClassName,
            long lFlags, IWbemContext* pContext, IWbemHiPerfEnum** ppEnum,
            long* plId );

    } m_xConfigRefresher;

protected:

    void Initialize( void );
    void Cleanup( void );

    // Operation helpers
    HRESULT SignalRefresher( void );
    HRESULT SetRefresherParams( IWbemServices* pNamespace, tRefrOps eOp,
            LPCWSTR pwszPath, LPCWSTR pwszClassName, long lFlags,
            IWbemClassObject** ppRefreshable, IWbemHiPerfEnum** ppEnum, long* plId,
            long lId );
    void ClearRefresherParams( void );

    DWORD WINAPI RealEntry( void );

    static DWORD WINAPI ThreadProc( void * pThis )
    {
        return ((CWbemRefresher*) pThis)->RealEntry();
    }

public:
    CWbemRefresher();
    virtual ~CWbemRefresher();

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)(THIS);
    STDMETHOD_(ULONG, Release)(THIS);

    // The real implementations
    STDMETHOD(AddObjectByPath)(IWbemServices* pNamespace, LPCWSTR wszPath,
        long lFlags, IWbemContext* pContext,
        IWbemClassObject** ppRefreshable, long* plId);

    STDMETHOD(AddObjectByTemplate)(IWbemServices* pNamespace,
        IWbemClassObject* pTemplate,
        long lFlags, IWbemContext* pContext,
        IWbemClassObject** ppRefreshable, long* plId);

    STDMETHOD(AddRefresher)(IWbemRefresher* pRefresher, long lFlags,
        long* plId);

    STDMETHOD(Remove)(long lId, long lFlags);

    STDMETHOD(AddEnum)( IWbemServices*  pNamespace, LPCWSTR wscClassName,
        long lFlags, IWbemContext* pContext, IWbemHiPerfEnum** ppEnum,
        long* plId );

    STDMETHOD(Refresh)(long lFlags);

};

/*
**  Begin CWbemRefresher Implementation
*/

#if _MSC_VER >= 1200
#pragma warning(push)
#endif

#pragma warning(disable:4355)

// CTor and DTor
CWbemRefresher::CWbemRefresher( void )
: m_lRefCount(0), m_xRefresher( this ), m_xConfigRefresher( this ),
        m_hQuitEvent( NULL ),
        m_hDoWorkEvent( NULL ), m_hRefrMutex( NULL ), m_hInitializedEvent( NULL ),
        m_hThread( NULL ), m_hWorkDoneEvent( NULL ), m_dwThreadId( 0 ),
        m_pNSStream( NULL ), m_wszPath( NULL ), m_wszClassName( NULL ),
        m_lFlags( 0L ), m_ppRefreshable( NULL ), m_ppEnum( NULL ), m_plId( NULL ),
        m_eRefrOp( eRefrOpRefresh ), m_hOperResult( WBEM_S_NO_ERROR ), m_fThreadOk( FALSE ),
        m_lId( 0 )
{
    Initialize();
}

#if _MSC_VER >= 1200
#pragma warning(pop)
#else
#pragma warning(default:4355)
#endif

CWbemRefresher::~CWbemRefresher( void )
{
    Cleanup();
}

void CWbemRefresher::Initialize( void )
{
    // Now create the events, mutexes and our pal, the MTA thread on which all of
    // the operations will run

    m_hQuitEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
    m_hDoWorkEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
    m_hInitializedEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
    m_hWorkDoneEvent = CreateEventW( NULL, FALSE, FALSE, NULL );

    m_hRefrMutex = CreateMutexW( NULL, FALSE, NULL );

    // If we don't have all these, something's gone south
    if (    NULL    ==  m_hQuitEvent        ||
            NULL    ==  m_hDoWorkEvent      ||
            NULL    ==  m_hInitializedEvent ||
            NULL    ==  m_hWorkDoneEvent    ||
            NULL    ==  m_hRefrMutex        )
    {
        return;
    }

    // Kick off the thread and wait for the initialized event signal (we'll give it
    // 5 seconds...if it don't get signalled in that timeframe, something is most likely
    // wrong, but we'll bounce out so whoever allocated us isn't left wondering what
    // to do).

    m_hThread = CreateThread( NULL, 0, CWbemRefresher::ThreadProc,
                    (void*) this, 0, &m_dwThreadId );

    if ( NULL == m_hThread )
    {
        return;
    }

    WaitForSingleObject( m_hInitializedEvent, 5000 );

}

void CWbemRefresher::Cleanup( void )
{
    // If we have a thread, tell it to go away
    if ( NULL != m_hThread )
    {
        // Signal the quit event and give the thread a 5 second grace period
        // to shutdown.  If it don't, don't worry, just close the handle and go away.

        SetEvent( m_hQuitEvent );
        WaitForSingleObject( m_hThread, 5000 );

        CloseHandle( m_hThread );
        m_hThread = NULL;
    }

    // Cleanup the primitives

    if ( NULL != m_hQuitEvent )
    {
        CloseHandle( m_hQuitEvent );
        m_hQuitEvent = NULL;
    }

    if ( NULL != m_hDoWorkEvent )
    {
        CloseHandle( m_hDoWorkEvent );
        m_hDoWorkEvent = NULL;
    }

    if ( NULL != m_hInitializedEvent )
    {
        CloseHandle( m_hInitializedEvent );
        m_hInitializedEvent = NULL;
    }

    if ( NULL != m_hWorkDoneEvent )
    {
        CloseHandle( m_hWorkDoneEvent );
        m_hWorkDoneEvent = NULL;
    }

    if ( NULL != m_hRefrMutex )
    {
        CloseHandle( m_hRefrMutex );
        m_hRefrMutex = NULL;
    }

}

DWORD CWbemRefresher::RealEntry( void )
{
    // Grab hold of all the things we may care about in case some evil timing
    // problem occurs, so we don't get left trying to hit on member variables that
    // don't exist anymore.

    HANDLE  hQuitEvent          =   m_hQuitEvent,
            hDoWorkEvent        =   m_hDoWorkEvent,
            hInitializedEvent   =   m_hInitializedEvent,
            hWorkDoneEvent      =   m_hWorkDoneEvent;

    DWORD   dwWait = 0;

    HANDLE  ahEvents[2];

    ahEvents[0] = hDoWorkEvent;
    ahEvents[1] = hQuitEvent;

    // Initialize this thread
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (hr == S_FALSE) {
        // COM library is already initialized, we can continue;
        //
        hr = S_OK;
    }

    // Now get the refresher and config refresher pointers.

    IWbemRefresher*             pWbemRefresher = NULL;
    IWbemConfigureRefresher*    pWbemConfig = NULL;

    if ( SUCCEEDED( hr ) )
    {
        hr = CoCreateInstance (CLSID_WbemRefresher, 0, CLSCTX_SERVER,
                        IID_IWbemRefresher, (LPVOID *)&pWbemRefresher);

        if ( SUCCEEDED( hr ) )
        {
            pWbemRefresher->QueryInterface( IID_IWbemConfigureRefresher, (LPVOID *) &pWbemConfig );
        }

    }

    //  Obviously we can't go any further if we don't have our pointers correctly
    //  setup.
    m_fThreadOk = SUCCEEDED( hr );

    // Ready to go --- Signal the Initialized Event
    SetEvent( hInitializedEvent );

    if ( m_fThreadOk )
    {

        while ( ( dwWait = WaitForMultipleObjects( 2, ahEvents, FALSE,  INFINITE ) ) == WAIT_OBJECT_0 )
        {
            // Don't continue if quit is signalled
            if ( WaitForSingleObject( hQuitEvent, 0 ) == WAIT_OBJECT_0 )
            {
                break;
            }

            // This is where we'll do the real operation

            switch( m_eRefrOp )
            {
                case eRefrOpRefresh:
                {
                    m_hOperResult = pWbemRefresher->Refresh( m_lFlags );
                    break;
                }

                // For both of these ops, we will need to umarshal the
                // namespace
                case eRefrOpAddEnum:
                case eRefrOpAddByPath:
                {
                    IWbemServices*  pNamespace = NULL;

                    // Unmarshal the interface, then set security
                    m_hOperResult = CoGetInterfaceAndReleaseStream(
                        m_pNSStream, IID_IWbemServices,
                        (void**) &pNamespace );
                    m_pNSStream = NULL;

                    if ( SUCCEEDED( m_hOperResult ) )
                    {
                        m_hOperResult = SetWbemSecurity( pNamespace );

                        if ( SUCCEEDED( m_hOperResult ) )
                        {
                            if ( eRefrOpAddByPath == m_eRefrOp )
                            {
                                m_hOperResult = pWbemConfig->AddObjectByPath(
                                    pNamespace, m_wszPath, m_lFlags, NULL,
                                    m_ppRefreshable, m_plId );
                            }
                            else
                            {
                                m_hOperResult = pWbemConfig->AddEnum(
                                    pNamespace, m_wszClassName, m_lFlags, NULL,
                                    m_ppEnum, m_plId );
                            }
                        }

                        pNamespace->Release();
                    }

                    break;
                }

                case eRefrOpRemove:
                {
                    m_hOperResult = pWbemConfig->Remove( m_lId, m_lFlags );
                    break;
                }

                default:
                {
                    m_hOperResult = WBEM_E_FAILED;
                }
            }

            // Signal the event to let a waiting thread know we're done doing
            // what it asked us to do.
            SetEvent( hWorkDoneEvent );
        }

    }

    // This means we're not processing anymore (for whatever reason)
    m_fThreadOk = FALSE;

    // Cleanup our pointers
    if ( NULL != pWbemRefresher )
    {
        pWbemRefresher->Release();
    }

    if ( NULL != pWbemConfig )
    {
        pWbemConfig->Release();
    }

    CoUninitialize();

    return 0;
}

// CWbemRefresher class functions
SCODE CWbemRefresher::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
    *ppvObj = 0;

    if (IID_IUnknown==riid)
    {
        *ppvObj = (IUnknown*)this;
        AddRef();
        return NOERROR;
    }
    else if ( IID_IWbemRefresher == riid )
    {
        *ppvObj = (IWbemRefresher*) &m_xRefresher;
        AddRef();
        return NOERROR;
    }
    else if ( IID_IWbemConfigureRefresher == riid )
    {
        *ppvObj = (IWbemConfigureRefresher*) &m_xConfigRefresher;
        AddRef();
        return NOERROR;
    }

    return ResultFromScode(E_NOINTERFACE);
}

ULONG CWbemRefresher::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

ULONG CWbemRefresher::Release()
{
    long lRef = InterlockedDecrement(&m_lRefCount);

    if (0 != lRef)
        return lRef;

    delete this;
    return 0;
}

HRESULT CWbemRefresher::SignalRefresher( void )
{
    HRESULT hr = WBEM_S_NO_ERROR;

    if ( SetEvent( m_hDoWorkEvent ) )
    {
        if ( WaitForSingleObject( m_hWorkDoneEvent, INFINITE ) == WAIT_OBJECT_0 )
        {
            hr = m_hOperResult;
        }
        else
        {
            hr = WBEM_E_FAILED;
        }
    }
    else
    {
        hr = WBEM_E_FAILED;
    }

    ClearRefresherParams();

    return hr;
}

HRESULT CWbemRefresher::SetRefresherParams( IWbemServices* pNamespace, tRefrOps eOp,
            LPCWSTR pwszPath, LPCWSTR pwszClassName, long lFlags,
            IWbemClassObject** ppRefreshable, IWbemHiPerfEnum** ppEnum, long* plId,
            long lId )
{
    HRESULT hr = WBEM_S_NO_ERROR;

    if ( NULL != pNamespace )
    {
        // Marshal the namespace pointer into the stream member
        hr = CoMarshalInterThreadInterfaceInStream( IID_IWbemServices, pNamespace,
            &m_pNSStream );
    }
    else
    {
        m_pNSStream = NULL;
    }

    if ( SUCCEEDED( hr ) )
    {
        m_eRefrOp = eOp;
        m_wszPath = pwszPath;
        m_wszClassName = pwszClassName,
        m_lFlags = lFlags;
        m_ppRefreshable = ppRefreshable;
        m_ppEnum = ppEnum;
        m_plId = plId;
        m_lId = lId;
    }

    return hr;
}

void CWbemRefresher::ClearRefresherParams( void )
{
    m_pNSStream = NULL;
    m_eRefrOp = eRefrOpNone;
    m_wszPath = NULL;
    m_wszClassName = NULL,
    m_lFlags = 0L;
    m_ppRefreshable = NULL;
    m_ppEnum = NULL;
    m_plId = NULL;
    m_lId = 0L;
    m_hOperResult = WBEM_S_NO_ERROR;
}

// These are the real method implementations
STDMETHODIMP CWbemRefresher::AddObjectByPath(
    IWbemServices* pNamespace, LPCWSTR wszPath,
    long lFlags, IWbemContext* pContext,
    IWbemClassObject** ppRefreshable, long* plId)
{
    HRESULT hr = WBEM_E_FAILED;

    UNREFERENCED_PARAMETER (pContext);

    if ( WaitForSingleObject( m_hRefrMutex, WBEM_REFRESHER_TIMEOUT ) == WAIT_OBJECT_0 )
    {
        // Check that the thread is still running
        if ( m_fThreadOk )
        {
            // Setup the parameters and perform the operation
            hr = SetRefresherParams( pNamespace, eRefrOpAddByPath, wszPath, NULL,
                    lFlags, ppRefreshable, NULL, plId, 0L );

            if ( SUCCEEDED( hr ) )
            {
                // This is where we ask the thread to do the work
                hr = SignalRefresher();
            }
        }
        else
        {
            hr = WBEM_E_FAILED;
        }

        ReleaseMutex( m_hRefrMutex );
    }
    else
    {
        hr = WBEM_E_REFRESHER_BUSY;
    }

    return hr;
}

STDMETHODIMP CWbemRefresher::AddObjectByTemplate(
    IWbemServices* pNamespace,
    IWbemClassObject* pTemplate,
    long lFlags, IWbemContext* pContext,
    IWbemClassObject** ppRefreshable, long* plId)
{
    UNREFERENCED_PARAMETER (pNamespace);
    UNREFERENCED_PARAMETER (pTemplate);
    UNREFERENCED_PARAMETER (lFlags);
    UNREFERENCED_PARAMETER (pContext);
    UNREFERENCED_PARAMETER (ppRefreshable);
    UNREFERENCED_PARAMETER (plId);

    // We don't call this internally, so don't implement
    return WBEM_E_METHOD_NOT_IMPLEMENTED;
}

STDMETHODIMP CWbemRefresher::Remove(long lId, long lFlags)
{

    HRESULT hr = WBEM_E_FAILED;

    UNREFERENCED_PARAMETER (lId);
    UNREFERENCED_PARAMETER (lFlags);

    if ( WaitForSingleObject( m_hRefrMutex, WBEM_REFRESHER_TIMEOUT ) == WAIT_OBJECT_0 )
    {
        // Check that the thread is still running
        if ( m_fThreadOk )
        {
            // Setup the parameters and perform the operation
            hr = SetRefresherParams( NULL, eRefrOpRemove, NULL, NULL,
                    lFlags, NULL, NULL, NULL, lId );

            if ( SUCCEEDED( hr ) )
            {
                // This is where we ask the thread to do the work
                hr = SignalRefresher();
            }
        }
        else
        {
            hr = WBEM_E_FAILED;
        }

        ReleaseMutex( m_hRefrMutex );
    }
    else
    {
        hr = WBEM_E_REFRESHER_BUSY;
    }

    return hr;

}

STDMETHODIMP CWbemRefresher::AddRefresher(
                    IWbemRefresher* pRefresher, long lFlags, long* plId)
{
    UNREFERENCED_PARAMETER (lFlags);
    UNREFERENCED_PARAMETER (pRefresher);
    UNREFERENCED_PARAMETER (plId);

    // We don't call this internally, so don't implement
    return WBEM_E_METHOD_NOT_IMPLEMENTED;
}

HRESULT CWbemRefresher::AddEnum(
        IWbemServices* pNamespace, LPCWSTR wszClassName,
        long lFlags, IWbemContext* pContext, IWbemHiPerfEnum** ppEnum,
        long* plId)
{

    HRESULT hr = WBEM_E_FAILED;

    UNREFERENCED_PARAMETER (pContext);

    if ( WaitForSingleObject( m_hRefrMutex, WBEM_REFRESHER_TIMEOUT ) == WAIT_OBJECT_0 )
    {
        // Check that the thread is still running
        if ( m_fThreadOk )
        {
            // Setup the parameters and perform the operation
            hr = SetRefresherParams( pNamespace, eRefrOpAddEnum, NULL, wszClassName,
                    lFlags, NULL, ppEnum, plId, 0L );

            if ( SUCCEEDED( hr ) )
            {
                // This is where we ask the thread to do the work
                hr = SignalRefresher();
            }
        }
        else
        {
            hr = WBEM_E_FAILED;
        }

        ReleaseMutex( m_hRefrMutex );
    }
    else
    {
        hr = WBEM_E_REFRESHER_BUSY;
    }

    return hr;

}

STDMETHODIMP CWbemRefresher::Refresh( long lFlags )
{
    HRESULT hr = WBEM_E_FAILED;

    if ( WaitForSingleObject( m_hRefrMutex, WBEM_REFRESHER_TIMEOUT ) == WAIT_OBJECT_0 )
    {
        // Check that the thread is still running
        if ( m_fThreadOk )
        {
            // Setup the parameters and perform the operation
            hr = SetRefresherParams( NULL, eRefrOpRefresh, NULL, NULL,
                    lFlags, NULL, NULL, NULL, 0L );

            if ( SUCCEEDED( hr ) )
            {
                // This is where we ask the thread to do the work
                hr = SignalRefresher();
            }
        }
        else
        {
            hr = WBEM_E_FAILED;
        }

        ReleaseMutex( m_hRefrMutex );
    }
    else
    {
        hr = WBEM_E_REFRESHER_BUSY;
    }

    return hr;
}

// XRefresher
SCODE CWbemRefresher::XRefresher::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
    return m_pOuter->QueryInterface( riid, ppvObj );
}

ULONG CWbemRefresher::XRefresher::AddRef()
{
    return m_pOuter->AddRef();
}

ULONG CWbemRefresher::XRefresher::Release()
{
    return m_pOuter->Release();
}

STDMETHODIMP CWbemRefresher::XRefresher::Refresh( long lFlags )
{
    // Pass through
    return m_pOuter->Refresh( lFlags );
}

// XConfigRefresher
SCODE CWbemRefresher::XConfigRefresher::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
    return m_pOuter->QueryInterface( riid, ppvObj );
}

ULONG CWbemRefresher::XConfigRefresher::AddRef()
{
    return m_pOuter->AddRef();
}

ULONG CWbemRefresher::XConfigRefresher::Release()
{
    return m_pOuter->Release();
}

STDMETHODIMP CWbemRefresher::XConfigRefresher::AddObjectByPath(
    IWbemServices* pNamespace, LPCWSTR wszPath,
    long lFlags, IWbemContext* pContext,
    IWbemClassObject** ppRefreshable, long* plId)
{
    // Pass through
    return m_pOuter->AddObjectByPath( pNamespace, wszPath, lFlags, pContext,
            ppRefreshable, plId );
}

STDMETHODIMP CWbemRefresher::XConfigRefresher::AddObjectByTemplate(
    IWbemServices* pNamespace,
    IWbemClassObject* pTemplate,
    long lFlags, IWbemContext* pContext,
    IWbemClassObject** ppRefreshable, long* plId)
{
    // Pass through
    return m_pOuter->AddObjectByTemplate( pNamespace, pTemplate, lFlags, pContext,
            ppRefreshable, plId );
}

STDMETHODIMP CWbemRefresher::XConfigRefresher::Remove(long lId, long lFlags)
{
    return m_pOuter->Remove( lId, lFlags );
}

STDMETHODIMP CWbemRefresher::XConfigRefresher::AddRefresher(
                    IWbemRefresher* pRefresher, long lFlags, long* plId)
{
    return m_pOuter->AddRefresher( pRefresher, lFlags, plId );
}

HRESULT CWbemRefresher::XConfigRefresher::AddEnum(
        IWbemServices* pNamespace, LPCWSTR wszClassName,
        long lFlags, IWbemContext* pContext, IWbemHiPerfEnum** ppEnum,
        long* plId)
{
    return m_pOuter->AddEnum( pNamespace, wszClassName, lFlags, pContext,
            ppEnum, plId );
}

/*
**  End CWbemRefresher Implementation!
*/

// HELPER Function to establish the CWbemRefresher Interface pass-thru
HRESULT CoCreateRefresher( IWbemRefresher** ppRefresher )
{
    HRESULT hr = WBEM_S_NO_ERROR;

    // Allocate the pass-thru object then, if successful, get
    // the interface pointer out of it
    CWbemRefresher* pWbemRefresher = new CWbemRefresher;

    if ( NULL != pWbemRefresher )
    {
        hr = pWbemRefresher->QueryInterface( IID_IWbemRefresher, (LPVOID*) ppRefresher );
    }
    else
    {
        hr = WBEM_E_OUT_OF_MEMORY;
    }

    return hr;
}

PPDHI_WBEM_SERVER_DEF pFirstWbemServer = NULL;
//BOOL    bWbemInitialized = FALSE;

BOOL    bSecurityInitialized = FALSE;
IGlobalInterfaceTable * gp_GIT = NULL;

BOOL PdhiCoInitialize( void )
{
    HRESULT sc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if ( !bSecurityInitialized )
    {
        // In case it hasn't been
        HRESULT hr = CoInitializeSecurity(
            NULL,   //Points to security descriptor
            -1L,     //Count of entries in asAuthSvc -1 means use default
            NULL,   //Array of names to register
            NULL,   //Reserved for future use
            RPC_C_AUTHN_LEVEL_PKT,  //The default authentication level
                                // for proxies
            RPC_C_IMP_LEVEL_IMPERSONATE,    //The default impersonation level
                                // for proxies
            NULL,   //Authentication information for
                    // each authentication service
            EOAC_NONE,   //Additional client and/or
                            // server-side capabilities
            NULL    //Reserved for future use
            );

        bSecurityInitialized = (hr == S_OK || hr == RPC_E_TOO_LATE);
    }

    if (gp_GIT == NULL) {
        HRESULT hr1 = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 
                                       NULL,
                                       CLSCTX_INPROC_SERVER, 
                                       IID_IGlobalInterfaceTable,
                                       (void **) & gp_GIT); 
        if (hr1 != ERROR_SUCCESS) {
            gp_GIT = NULL;
        }
    }

    // We will only return that this succeeded if the call to CoInitializeEx
    // returned S_FALSE.  If it didn't, it either errored or returned S_OK.
    // If S_OK, we will assume that the client isn't doing any COM stuff
    // natively.  If S_FALSE, the client already CoInitialized this thread
    // so we just bumped up the ref count and should cleanup on the way
    // out

    return (S_FALSE == sc);
}

void PdhiCoUninitialize( void )
{
    CoUninitialize();
}

PDH_FUNCTION PdhiCloseWbemServer (PPDHI_WBEM_SERVER_DEF pWbemServer);

PDH_FUNCTION
PdhiDisconnectWbemServer (
    PPDHI_WBEM_SERVER_DEF pWbemServer
)
{
    PDH_STATUS  pdhReturn = ERROR_SUCCESS;
    if (pWbemServer != NULL) {
        pWbemServer->lRefCount--;
        if (pWbemServer->lRefCount < 0) {
            pWbemServer->lRefCount = 0;
        }
    }

    return pdhReturn;
}

PDH_FUNCTION
PdhiFreeWbemQuery (
    PPDHI_QUERY     pThisQuery
)
{
    HRESULT hRes;

    if (!bProcessIsDetaching) {
        if ((pThisQuery->pRefresherCfg) != NULL) {
            hRes = pThisQuery->pRefresherCfg->Release ();
            pThisQuery->pRefresherCfg = NULL;
        }

        if ((pThisQuery->pRefresher) != NULL) {
            hRes = pThisQuery->pRefresher->Release ();
            pThisQuery->pRefresher = NULL;
        }
    }
    return ERROR_SUCCESS;
}

PDH_FUNCTION
PdhiCloseWbemCounter (
    PPDHI_COUNTER   pThisCounter
)
{
    HRESULT hRes;
    BOOLEAN bRemoveRefresher = TRUE;

    if (!bProcessIsDetaching) {
        if (pThisCounter->pOwner->pRefresherCfg != NULL) {
            PPDHI_QUERY   pQuery   = pThisCounter->pOwner;
            PPDHI_COUNTER pCounter = pQuery->pCounterListHead;

            do {
                if (pCounter == NULL) {
                    bRemoveRefresher = FALSE;
                }
                else if (pCounter != pThisCounter && pCounter->lWbemRefreshId
                                == pThisCounter->lWbemRefreshId) {
                    bRemoveRefresher = FALSE;
                }
                else {
                    pCounter = pCounter->next.flink;
                }
            }
            while (bRemoveRefresher && pCounter != NULL
                                    && pCounter != pQuery->pCounterListHead);

            if (bRemoveRefresher) {
                hRes = pThisCounter->pOwner->pRefresherCfg->Remove(
                                pThisCounter->lWbemRefreshId, 0L);
            }
            // assert (hRes == S_OK); the function returns a BOOL even though it's defined as an HRESULT
//            pThisCounter->pOwner->pRefresherCfg->Release();
//            pThisCounter->pOwner->pRefresherCfg = NULL;
        }

        if (pThisCounter->pWbemAccess != NULL) {
            pThisCounter->pWbemAccess->Release();
            pThisCounter->pWbemAccess = NULL;
        }

        if (pThisCounter->pWbemObject != NULL) {
            pThisCounter->pWbemObject->Release();
            pThisCounter->pWbemObject = NULL;
        }
    }

    return ERROR_SUCCESS;
}

PDH_FUNCTION
PdhiBreakWbemMachineName (
    LPCWSTR     szMachineAndNamespace,
    LPWSTR      szMachine,
    LPWSTR      szNamespace
)
/*
    assumes szMachine and szPath are large enough to hold the result
*/
{
    LPWSTR  szSrc = NULL;
    LPWSTR  szDest = NULL;

    assert (szMachine != NULL);
    assert (szNamespace != NULL);

    szSrc = (LPWSTR)szMachineAndNamespace;

    if (szSrc == NULL) {
        // then use local machine and default namespace
        lstrcpyW (szMachine, szStaticLocalMachineName); // local machine
        lstrcpyW (szNamespace, cszWbemDefaultPerfRoot);
        return ERROR_SUCCESS;
    } else {
        // break into components
        if (*szSrc  != NULL) {
            // there's a string, see if it's a machine or a namespace
            if ((szSrc[0] == L'\\') && (szSrc[1] == L'\\')) {
                szDest = szMachine;
                // then there's a machine name
                *szDest++ = *szSrc++;
                *szDest++ = *szSrc++;
                while ((*szSrc != 0) && (*szSrc != L'\\')){
                    *szDest++ = *szSrc++;
                }
                *szDest = 0;
            } else {
                // no machine so use default
                // it must be just a namespace
            }
        } else {
            // no machine so use default
        }

        if (szDest == NULL) {
            // nothing found yet, so insert local machine as default
            szDest = szMachine;
            lstrcpyW (szDest, szStaticLocalMachineName);
        }

        szDest = szNamespace;

        if (*szSrc != 0) {
            // if there's a namespace then copy it
            szSrc++;    // move past backslash
            while (*szSrc != 0) {
                *szDest++ = *szSrc++;
            }
            *szDest = 0;
        } else {
            // else return the default;
            lstrcpyW (szDest, cszWbemDefaultPerfRoot);
        }
        return ERROR_SUCCESS;
    }
}

PDH_FUNCTION
PdhiMakeWbemInstancePath (
    IN      PDH_COUNTER_PATH_ELEMENTS_W *pCounterPathElements,
    IN      LPWSTR                      szFullPathBuffer,
    IN      BOOL                        bMakeRelativePath
)
{
    WCHAR   szMachine[MAX_PATH];
    WCHAR   szNamespace[MAX_PATH];
    WCHAR   szWbemInstance[MAX_PATH];

    LPWSTR  szSrc, szDest;
    //  the function assumes that the path buffer is sufficiently large
    //  to hold the result
    //
    //
    // the wbem class instance path consists of one of the following formats:
    // for perf objects with one and only one instance (singleton classes in
    // WBEM parlance) the format is
    //
    //      <objectname>=@
    //
    // for object with instances, the format is
    //
    //      <objectname>.Name="<instancename>"
    //
    if (!bMakeRelativePath) {
        PdhiBreakWbemMachineName (
            pCounterPathElements->szMachineName,
            szMachine,
            szNamespace);
        lstrcpyW (szFullPathBuffer, szMachine);
        lstrcatW (szFullPathBuffer, cszBackSlash);
        lstrcatW (szFullPathBuffer, szNamespace);
        lstrcatW (szFullPathBuffer, cszColon);
    } else {
        *szFullPathBuffer = 0;
    }

    if (pCounterPathElements->szInstanceName == NULL) {
        // then apply the singleton logic
        lstrcatW (szFullPathBuffer, pCounterPathElements->szObjectName);
        lstrcatW (szFullPathBuffer, cszSingletonInstance);
    } else {
        // wbem will interpret the backslash character as an
        // escape char (as "C" does) so we'll have to double each
        // backslash in the string to make it come out OK
        szDest = &szWbemInstance[0];
        if (pCounterPathElements->szParentInstance != NULL) {
            szSrc = pCounterPathElements->szParentInstance;
            while (*szSrc != 0) {
                *szDest = *szSrc;
                if (*szSrc == BACKSLASH_L) {
                    *++szDest = BACKSLASH_L;
                }
                szDest++;
                szSrc++;
                assert (szDest < &szWbemInstance[MAX_PATH]);
            }
            *szDest++ = '/'; // parent/child delimiter
        }
        szSrc = pCounterPathElements->szInstanceName;
        while (*szSrc != 0) {
            *szDest = *szSrc;
            if (*szSrc == BACKSLASH_L) {
                *++szDest = BACKSLASH_L;
            }
            szDest++;
            szSrc++;
            assert (szDest < &szWbemInstance[MAX_PATH]);
        }
        *szDest = 0;
        // apply the instance name format
        lstrcatW (szFullPathBuffer, pCounterPathElements->szObjectName);
        lstrcatW (szFullPathBuffer, cszNameParam);
        lstrcatW (szFullPathBuffer, szWbemInstance);
        lstrcatW (szFullPathBuffer, cszDoubleQuote);
    }
    return ERROR_SUCCESS;
}

PDH_FUNCTION
PdhiWbemGetCounterPropertyName (
    IWbemClassObject        *pThisClass,
    LPCWSTR                 szCounterDisplayName,
    LPWSTR                  szPropertyName,
    DWORD                   dwPropertyNameSize
)
{
    HRESULT         hResult;
    PDH_STATUS      pdhStatus = PDH_CSTATUS_NO_COUNTER;
    SAFEARRAY       *psaNames = NULL;
    long            lLower; 
    long            lUpper = 0;
    long            lCount;
    BSTR            bsPropName = NULL;
    BSTR            bsCountertype = NULL;
    BSTR            bsDisplayname = NULL;
    VARIANT         vName, vCountertype;
    IWbemQualifierSet       *pQualSet = NULL;

    VariantInit (&vName);
    VariantInit (&vCountertype);

    // get the properties of this class as a Safe Array
    hResult = pThisClass->GetNames (NULL,
        WBEM_FLAG_NONSYSTEM_ONLY, NULL, &psaNames);
    if (hResult == WBEM_NO_ERROR) {
        hResult = SafeArrayGetLBound (psaNames, 1, &lLower);
        if (hResult == S_OK) {
            hResult = SafeArrayGetUBound (psaNames, 1, &lUpper);
        }
        if (hResult == S_OK) {
            bsCountertype = SysAllocString (cszCountertype);
            bsDisplayname = SysAllocString (cszDisplayname);
            if (bsCountertype && bsDisplayname) {
                for (lCount = lLower; lCount <= lUpper; lCount++) {
                    hResult = SafeArrayGetElement (psaNames, &lCount, &bsPropName);
                    if (hResult == S_OK) {
                        // this is the desired counter so
                        // get the qualifier set for this property
                        hResult = pThisClass->GetPropertyQualifierSet (
                            bsPropName, &pQualSet);
                        if (hResult == WBEM_NO_ERROR) {
                            LONG    lCounterType;
                            // make sure this is a perf counter property
                            hResult = pQualSet->Get (bsCountertype, 0, &vCountertype, NULL);
                            if (hResult == WBEM_NO_ERROR) {
                                lCounterType = V_I4(&vCountertype);
                                // then see if this is a displayable counter
                                if (!(lCounterType & PERF_DISPLAY_NOSHOW) ||
                                    (lCounterType == PERF_AVERAGE_BULK)) {
                                    // by testing for the counter type
                                    // get the display name for this property
                                    hResult = pQualSet->Get (bsDisplayname, 0, &vName, NULL);
                                    if (hResult == WBEM_NO_ERROR) {
                                        // display name found compare it
                                        if (lstrcmpiW(szCounterDisplayName, V_BSTR(&vName)) == 0) {
                                            // then this is the correct property so return
                                            if ((DWORD)lstrlenW(bsPropName) < dwPropertyNameSize) {
                                                lstrcpyW (szPropertyName, (LPWSTR)bsPropName);
                                                pdhStatus = ERROR_SUCCESS;
                                                pQualSet->Release();
                                                pQualSet = NULL;
                                                break;
                                            } else {
                                                pdhStatus = PDH_MORE_DATA;
                                            }
                                        } else {
                                            //not this property so continue
                                        }
                                    }
                                } else {
                                    // this is a "don't show" counter so skip it
                                }
                            } else {
                                // unable to get the counter type so it's probably
                                // not a perf counter property, skip it and continue
                            }
                            VariantClear (&vName);
                            VariantClear (&vCountertype);
                            pQualSet->Release();
                            pQualSet = NULL;
                        } else {
                            // unable to read qualifiers so skip
                            continue;
                        }
                    } else {
                        // unable to read element in SafeArray
                        pdhStatus = PDH_WBEM_ERROR;
                        SetLastError(hResult);
                    }
                } // end for each element in SafeArray
            } else {
                pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
            }
            PdhiSysFreeString (&bsCountertype);
            PdhiSysFreeString (&bsDisplayname);
        } else {
            // unable to get array boundries
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        }

    } else {
        // unable to get property strings
        pdhStatus = PDH_WBEM_ERROR;
        SetLastError (hResult);
    }

    VariantClear (&vName);
    VariantClear (&vCountertype);

    if (psaNames != NULL) {
        // Clear the SafeArray if it exists
        SafeArrayDestroy( psaNames );
    }

    // make sure it was released
    assert (pQualSet == NULL);

    return pdhStatus;
}

PDH_FUNCTION
PdhiWbemGetCounterDisplayName (
    IWbemClassObject        *pThisClass,
    LPCWSTR                 szCounterName,
    LPWSTR                  szDisplayName,
    DWORD                   dwDisplayNameSize
)
{
    HRESULT         hResult;
    PDH_STATUS      pdhStatus = PDH_CSTATUS_NO_COUNTER;
    SAFEARRAY       *psaNames = NULL;
    long            lLower; 
    long            lUpper = 0;
    long            lCount;
    BSTR            bsPropName = NULL;
    BSTR            bsCountertype = NULL;
    BSTR            bsDisplayname = NULL;
    VARIANT         vName, vCountertype;
    IWbemQualifierSet       *pQualSet = NULL;

    VariantInit (&vName);
    VariantInit (&vCountertype);

    // get the properties of this class as a Safe Array
    hResult = pThisClass->GetNames (NULL,
        WBEM_FLAG_NONSYSTEM_ONLY, NULL, &psaNames);
    if (hResult == WBEM_NO_ERROR) {
        hResult = SafeArrayGetLBound (psaNames, 1, &lLower);
        if (hResult == S_OK) {
            hResult = SafeArrayGetUBound (psaNames, 1, &lUpper);
        }
        if (hResult == S_OK) {
            bsCountertype = SysAllocString (cszCountertype);
            bsDisplayname = SysAllocString (cszDisplayname);
            if (bsCountertype && bsDisplayname) {
                for (lCount = lLower; lCount <= lUpper; lCount++) {
                    hResult = SafeArrayGetElement (psaNames, &lCount, &bsPropName);
                    if (hResult == S_OK) {
                        if (lstrcmpiW ((LPWSTR)bsPropName, szCounterName) == 0) {
                            // this is the desired counter so
                            // get the qualifier set for this property
                            hResult = pThisClass->GetPropertyQualifierSet (
                                bsPropName, &pQualSet);
                            if (hResult == WBEM_NO_ERROR) {
                                LONG    lCounterType;
                                // make sure this is a perf counter property
                                hResult = pQualSet->Get (bsCountertype, 0, &vCountertype, NULL);
                                if (hResult == WBEM_NO_ERROR) {
                                    lCounterType = V_I4(&vCountertype);
                                    // then see if this is a displayable counter
                                    if (!(lCounterType & PERF_DISPLAY_NOSHOW) ||
                                        (lCounterType == PERF_AVERAGE_BULK)) {
                                        // by testing for the counter type
                                        // get the display name for this property
                                        hResult = pQualSet->Get (bsDisplayname, 0, &vName, NULL);
                                        if (hResult == WBEM_NO_ERROR) {
                                            // display name found so copy and break
                                            if ((DWORD)lstrlenW(V_BSTR(&vName)) < dwDisplayNameSize) {
                                                lstrcpyW (szDisplayName, V_BSTR(&vName));
                                                pdhStatus = ERROR_SUCCESS;
                                                pQualSet->Release();
                                                pQualSet = NULL;
                                                break;
                                            } else {
                                                pdhStatus = PDH_MORE_DATA;
                                            }
                                        }
                                    } else {
                                        // this is a "don't show" counter so skip it
                                    }
                                } else {
                                    // unable to get the counter type so it's probably
                                    // not a perf counter property, skip it and continue
                                }
                                VariantClear (&vName);
                                VariantClear (&vCountertype);
                                pQualSet->Release();
                                pQualSet = NULL;
                            } else {
                                // unable to read qualifiers so skip
                                continue;
                            }
                        } else {
                            // aren't interested in this property, so
                            continue;
                        }
                    } else {
                        // unable to read element in SafeArray
                        pdhStatus = PDH_WBEM_ERROR;
                        SetLastError(hResult);
                    }
                } // end for each element in SafeArray
            } else {
                pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
            }
            PdhiSysFreeString (&bsCountertype);
            PdhiSysFreeString (&bsDisplayname);
        } else {
            // unable to get array boundries
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        }

    } else {
        // unable to get property strings
        pdhStatus = PDH_WBEM_ERROR;
        SetLastError (hResult);
    }

    VariantClear (&vName);
    VariantClear (&vCountertype);

    // Clear the SafeArray if it exists
    if ( NULL != psaNames )
    {
        SafeArrayDestroy( psaNames );
    }
    // make sure it was released
    assert (pQualSet == NULL);

    return pdhStatus;
}

PDH_FUNCTION
PdhiWbemGetClassObjectByName (
    PPDHI_WBEM_SERVER_DEF   pThisServer,
    LPCWSTR                 szClassName,
    IWbemClassObject        **pReturnClass
)
{
    PDH_STATUS  pdhStatus = ERROR_SUCCESS;

    HRESULT hResult;
    BSTR    bsClassName;

    IWbemClassObject        *pThisClass = NULL;

    bsClassName = SysAllocString (szClassName);

    if (bsClassName) {
        hResult = pThisServer->pSvc->GetObject (
            bsClassName, // class name
            WBEM_FLAG_USE_AMENDED_QUALIFIERS, NULL,
            &pThisClass,
            NULL);
        PdhiSysFreeString (&bsClassName);

        if (hResult != WBEM_NO_ERROR) {
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        } else {
            *pReturnClass = pThisClass;
        }
    } else {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    return (pdhStatus);
}

PDH_FUNCTION
PdhiWbemGetClassDisplayName (
    PPDHI_WBEM_SERVER_DEF   pThisServer,
    LPCWSTR                 szClassName,
    LPWSTR                  szClassDisplayName,
    DWORD                   dwClassDisplayNameSize,
    IWbemClassObject        **pReturnClass
)
{
    PDH_STATUS  pdhStatus = ERROR_SUCCESS;

    HRESULT hResult;
    BSTR    bsClassName;
    BSTR    bsClass;
    BSTR    bsDisplayName;
    VARIANT vName;
    LPWSTR  szDisplayName;

    IWbemClassObject        *pThisClass = NULL;
    IWbemQualifierSet       *pQualSet = NULL;

    VariantInit (&vName);

    bsClassName = SysAllocString (szClassName);

    if (bsClassName) {
        hResult = pThisServer->pSvc->GetObject (
            bsClassName, // class name
            WBEM_FLAG_USE_AMENDED_QUALIFIERS, NULL,
            &pThisClass,
            NULL);
        if (hResult != WBEM_NO_ERROR) {
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        }
        PdhiSysFreeString (&bsClassName);
    } else {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // get the display name property of this class
        pThisClass->GetQualifierSet (&pQualSet);
        if (pQualSet != NULL) {
            bsDisplayName = SysAllocString (cszDisplayname);
            if (bsDisplayName) {
                hResult = pQualSet->Get (bsDisplayName, 0, &vName, 0);

                if (hResult == WBEM_E_NOT_FOUND) {
                    // then this has not display name so
                    // pull the class name
                    bsClass = SysAllocString (cszClass);
                    if (bsClass) {
                        hResult = pThisClass->Get (bsClass, 0, &vName, 0, 0);
                        PdhiSysFreeString (&bsClass);
                    } else {
                        hResult = WBEM_E_OUT_OF_MEMORY;
                    }
                } else {
                    hResult = WBEM_E_OUT_OF_MEMORY;
                }
                pQualSet->Release();
            } else {
                hResult = WBEM_E_OUT_OF_MEMORY;
            }
        } else {
            hResult = WBEM_E_NOT_FOUND;
        }

        if (hResult == WBEM_E_NOT_FOUND) {
            //unable to look up a display name so nothing to return
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        } else if (hResult == WBEM_E_OUT_OF_MEMORY) {
            pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
            SetLastError(hResult);
        } else if (hResult == S_OK) {
            // copy string to caller's buffers
            szDisplayName = V_BSTR(&vName);
            if ((DWORD)lstrlenW(szDisplayName) < dwClassDisplayNameSize) {
                lstrcpyW (szClassDisplayName, szDisplayName);
                pdhStatus = ERROR_SUCCESS;
            }
            if (pReturnClass != NULL) {
                // return the class pointer, the caller will close it
                *pReturnClass = pThisClass;
            } else {
                // close it
                pThisClass->Release();
            }
        }
    }

    VariantClear (&vName);

    return pdhStatus;
}
BOOL
PdhiIsSingletonClass (
    IWbemClassObject        *pThisClass
)
{
    HRESULT                 hResult;
    BOOL                    bReturnValue = FALSE;   //
    BSTR                    bsSingleton = NULL;
    VARIANT                 vValue;
    IWbemQualifierSet       *pQualSet = NULL;

    bsSingleton = SysAllocString (cszSingleton);

    if (bsSingleton) {
        VariantInit (&vValue);
        // get the display name of this class
        pThisClass->GetQualifierSet (&pQualSet);
        if (pQualSet != NULL) {
            hResult = pQualSet->Get (bsSingleton, 0, &vValue, 0);
            pQualSet->Release();
        } else {
            hResult = WBEM_E_NOT_FOUND;
        }

        if (hResult == ERROR_SUCCESS) {
            bReturnValue = TRUE;
        }

        VariantClear (&vValue);
        PdhiSysFreeString (&bsSingleton);
    } else {
        bReturnValue = FALSE;
    }

    return bReturnValue;
}

#pragma warning ( disable : 4127 )
PDH_FUNCTION
PdhiEnumWbemServerObjects(
    IN  PPDHI_WBEM_SERVER_DEF   pThisServer,
    IN  LPVOID                  mszObjectList,
    IN  LPDWORD                 pcchBufferSize,
    IN  DWORD                   dwDetailLevel,
    IN  BOOL                    bRefresh,
    IN  BOOL                    bUnicode
);

PDH_FUNCTION
PdhiWbemGetObjectClassName (
    PPDHI_WBEM_SERVER_DEF   pThisServer,
    LPCWSTR                 szObjectName,
    LPWSTR                  szObjectClassName,
    DWORD                   dwObjectClassNameSize,
    IWbemClassObject        **pReturnClass
)
{
    PDH_STATUS    pdhStatus = ERROR_SUCCESS;
    HRESULT       hResult;
    LONG          lResult;

    assert(pThisServer != NULL);
    assert(szObjectName != NULL);
    assert(szObjectClassName != NULL);
    assert(dwObjectClassNameSize > 0);

    if (pThisServer->pObjList == NULL) {
        DWORD dwSize = 0;
        pdhStatus = PdhiEnumWbemServerObjects(
                        pThisServer,
                        NULL,
                        & dwSize,
                        PERF_DETAIL_WIZARD | PERF_DETAIL_COSTLY,
                        TRUE,
                        TRUE);
        if (pThisServer->pObjList != NULL) {
            pdhStatus = ERROR_SUCCESS;
        }
    }

    if (pThisServer->pObjList != NULL) {
        PPDHI_WBEM_OBJECT_DEF pObject = pThisServer->pObjList;

        pdhStatus = PDH_CSTATUS_NO_OBJECT;
        while (pObject != NULL) {
            lResult = lstrcmpiW(pObject->szDisplay, szObjectName);
            if (lResult == 0) {
                if (  ((DWORD) lstrlenW(pObject->szObject))
                    < dwObjectClassNameSize) {
                    pdhStatus = ERROR_SUCCESS;
                    lstrcpyW(szObjectClassName, pObject->szObject);
                }
                else {
                    pdhStatus = PDH_MORE_DATA;
                }

                if (pObject->pClass == NULL) {
                    BSTR bsClassName = SysAllocString(pObject->szObject);
                    if (bsClassName) {
                        hResult = pThisServer->pSvc->GetObject(
                                bsClassName, WBEM_FLAG_USE_AMENDED_QUALIFIERS, NULL, & pObject->pClass, NULL);
                        if (hResult != WBEM_NO_ERROR) {
                            SetLastError(hResult);
                            pdhStatus = PDH_WBEM_ERROR;
                        }
                        else if (pReturnClass != NULL) {
                            * pReturnClass = pObject->pClass;
                        }
                    }
                    else {
                        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
                    }
                }
                else if (pReturnClass != NULL) {
                    * pReturnClass = pObject->pClass;
                }
                break;
            }
            pObject = pObject->pNext;
        }
    }

    return pdhStatus;
}
#pragma warning ( default : 4127 )

PDH_FUNCTION
PdhiAddWbemServer (
    LPCWSTR  szMachineName,
    PPDHI_WBEM_SERVER_DEF *pWbemServer
)
{
    IWbemLocator    *pWbemLocator = 0;
    IWbemServices   *pWbemServices = 0;
    PDH_STATUS      pdhStatus = ERROR_SUCCESS;
    HRESULT         hResult;
    DWORD           dwResult;
    DWORD           dwStrLen = 0;
    PPDHI_WBEM_SERVER_DEF pNewServer = NULL;
    WCHAR           szLocalMachineName[MAX_PATH];
    WCHAR           szLocalServerPath[MAX_PATH];
    WCHAR           szLocalNameSpaceString[MAX_PATH];
    WCHAR           szLocale[32];

    // szMachineName can be null,
    // that means use the local machine and default namespace
    assert (pWbemServer != NULL);

    // connect to locator
    dwResult = CoCreateInstance (CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID *)&pWbemLocator);
    if (dwResult != S_OK) {
        SetLastError (dwResult);
        pdhStatus = PDH_CANNOT_CONNECT_MACHINE;
    }

    if (pdhStatus == ERROR_SUCCESS) {
        PdhiBreakWbemMachineName (
            szMachineName,
            szLocalMachineName,
            szLocalNameSpaceString);
        lstrcpyW (szLocalServerPath, szLocalMachineName);
        lstrcatW (szLocalServerPath, szLocalNameSpaceString);

        // Create the locale
        swprintf( szLocale, L"MS_%hX", GetUserDefaultUILanguage());

        // try to connect to the service
        hResult = pWbemLocator->ConnectServer (
            szLocalServerPath,
            NULL, NULL, szLocale,
            0L,
            0,0,
            &pWbemServices);
        if (hResult) {
            SetLastError (hResult);
            pdhStatus =  PDH_CANNOT_CONNECT_WMI_SERVER;
        } else {
            dwStrLen = lstrlenW (szLocalMachineName ) + 1;

        }
        // free the locator
        pWbemLocator->Release();
    }

    // If we succeeded, we need to set Interface Security on the proxy and its
    // IUnknown in order for Impersonation to correctly work.

    if ( pdhStatus == ERROR_SUCCESS )
    {
        pdhStatus = SetWbemSecurity( pWbemServices );
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // everything went ok so save this connection
        if (*pWbemServer == NULL) {
            // then this is a new connection
            pNewServer = (PPDHI_WBEM_SERVER_DEF)G_ALLOC (sizeof (PDHI_WBEM_SERVER_DEF) + (dwStrLen * sizeof (WCHAR)));
            if (pNewServer == NULL) {
                pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
            } else {
                // insert this at the head of the list
                pNewServer->pNext = pFirstWbemServer;
                pFirstWbemServer = pNewServer;
                pNewServer->szMachine = (LPWSTR)&pNewServer[1];
                lstrcpyW (pNewServer->szMachine, szLocalMachineName);
                pNewServer->lRefCount = 0; // it'll be incremented in the connect function
                *pWbemServer = pNewServer;
            }
        } else {
            // we are reconnecting and reusing an old memory block
            // so just update the pointer
            pNewServer = *pWbemServer;
        }
        // if reconnecting or connecting for the first time, this should be NULL
        assert (pNewServer->pSvc == NULL);

        if (pdhStatus == ERROR_SUCCESS) {
            // update fields
            // load the name fields
            pNewServer->pSvc     = pWbemServices;
            pNewServer->pObjList = NULL;
            pNewServer->dwCache  = 0;
            if (gp_GIT != NULL) {
                HRESULT hrTmp = gp_GIT->RegisterInterfaceInGlobal(
                                                pWbemServices,
                                                IID_IWbemServices,
                                                & (pNewServer->dwCache));
                DebugPrint((3,"RegisterInterfaceInGlobal(0x%08X,0x%08X,%d)\n",
                            hrTmp, pNewServer->pSvc, pNewServer->dwCache));
                if (! SUCCEEDED(hrTmp)) {
                    pWbemServices->Release();
                    pNewServer->pSvc    = NULL;
                    pNewServer->dwCache = 0;
                    pdhStatus           = PDH_WBEM_ERROR;
                }
            }
            else {
                pWbemServices->Release();
                pNewServer->pSvc    = NULL;
                pNewServer->dwCache = 0;
                pdhStatus           = PDH_WBEM_ERROR;
            }
        } else {
            // something failed so return a NULL for the server pointer
            *pWbemServer = NULL;
        }
    } else {
        // unable to connect so return NULL
        *pWbemServer = NULL;
    }

    // if there was an eror, then free the new sever memory
    if ((* pWbemServer) == NULL) G_FREE(pNewServer);

    return pdhStatus;
}

PDH_FUNCTION
PdhiCloseWbemServer (
    PPDHI_WBEM_SERVER_DEF pWbemServer
)
{
    assert (pWbemServer != NULL);

    if (!bProcessIsDetaching) {
        if (pWbemServer != NULL) {
            if (pWbemServer->pObjList != NULL) {
                PPDHI_WBEM_OBJECT_DEF pObject = pWbemServer->pObjList;
                PPDHI_WBEM_OBJECT_DEF pNext;

                pWbemServer->pObjList = NULL;
                while (pObject != NULL) {
                    pNext = pObject->pNext;
                    if (pObject->pClass != NULL) pObject->pClass->Release();
                    G_FREE(pObject);
                    pObject = pNext;
                }
            }
            if (pWbemServer->pSvc != NULL) {
                // this is about all that's currently required
                pWbemServer->pSvc->Release();
                pWbemServer->pSvc = NULL;
            } else {
                // no server is connected
            }
        } else {
            // no structure exists
        }
    }

    return ERROR_SUCCESS;
}

PDH_FUNCTION
PdhiConnectWbemServer (
    LPCWSTR  szMachineName,
    PPDHI_WBEM_SERVER_DEF *pWbemServer
)
{
    PDH_STATUS  pdhStatus = PDH_CANNOT_CONNECT_MACHINE;
    PPDHI_WBEM_SERVER_DEF pThisServer = NULL;

    LPWSTR  szWideMachineName = NULL;
    LPWSTR  szWideNamespace = NULL;
    LPWSTR  szMachineNameArg = NULL;

    // get the local machine name & default name space if the caller
    // has passed in a NULL machine name

    if (szMachineName == NULL) {
        szWideMachineName = (LPWSTR) G_ALLOC (2048 + 1024); // this should be long enough
        if (szWideMachineName == NULL) {
            pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
        } else {
            szWideNamespace = (LPWSTR)((LPBYTE)szWideMachineName + 2048);
        }

        if (pdhStatus != PDH_MEMORY_ALLOCATION_FAILURE) {
            pdhStatus = PdhiBreakWbemMachineName (
                NULL,
                szWideMachineName,
                szWideNamespace);
//            lstrcatW (szWideMachineName, cszBackSlash);
//            lstrcatW (szWideMachineName, szWideNamespace);
            szMachineNameArg = szWideMachineName;
        }
    } else {
        szMachineNameArg = (LPWSTR)szMachineName;
        pdhStatus = ERROR_SUCCESS;
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // walk down list of connected servers and find the requested one
        assert (pWbemServer != NULL);

        for (pThisServer = pFirstWbemServer;
             pThisServer != NULL;
             pThisServer = pThisServer->pNext) {
            // machine name includes the namespace
            if (lstrcmpiW(pThisServer->szMachine, szMachineNameArg) == 0) {
                pdhStatus = ERROR_SUCCESS;
                break;
            }
        }

        if (pThisServer == NULL) {
             // then add it to the list and return it
             pdhStatus = PdhiAddWbemServer (
                szMachineNameArg,
                &pThisServer);
        } else {
            // make sure the server is really there
            // this is just a dummy call to see if the server will respond
            // with an error or RPC will respond with an error that there's
            // no server anymore.
            HRESULT hrTest;

            if (gp_GIT != NULL) {
                IWbemServices * pSvc = NULL;

                hrTest = gp_GIT->GetInterfaceFromGlobal(
                                pThisServer->dwCache,
                                IID_IWbemServices,
                                (void **) & pSvc);
                if (SUCCEEDED(hrTest)) {
                    if (pSvc != pThisServer->pSvc) {
                        DebugPrint((3,"GetInterfaceFromGlobal(0x%08X,%d,0x%08X,0x%08X)\n",
                                hrTest, pThisServer->dwCache, pThisServer->pSvc, pSvc));
                        pThisServer->pSvc = NULL;
                        if (pThisServer->pObjList != NULL) {
                            PPDHI_WBEM_OBJECT_DEF pObject;
                            PPDHI_WBEM_OBJECT_DEF pNext;
                            pObject = pThisServer->pObjList;
                            pThisServer->pObjList = NULL;
                            while (pObject != NULL) {
                                pNext = pObject->pNext;
                                G_FREE(pObject);
                                pObject = pNext;
                            }
                        }
                    }
                }
                else {
                    DebugPrint((3,"GetInterfaceFromGlobal(0x%08X,%d,0x%08X,0x%08X)\n",
                            hrTest, pThisServer->dwCache, pThisServer->pSvc, pSvc));
                    pThisServer->pSvc   = NULL;
                    if (pThisServer->pObjList != NULL) {
                        PPDHI_WBEM_OBJECT_DEF pObject;
                        PPDHI_WBEM_OBJECT_DEF pNext;
                        pObject = pThisServer->pObjList;
                        pThisServer->pObjList = NULL;
                        while (pObject != NULL) {
                            pNext = pObject->pNext;
                            G_FREE(pObject);
                            pObject = pNext;
                        }
                    }
                }
            }
            else {
                pThisServer->pSvc  = NULL;
                if (pThisServer->pObjList != NULL) {
                    PPDHI_WBEM_OBJECT_DEF pObject;
                    PPDHI_WBEM_OBJECT_DEF pNext;
                    pObject = pThisServer->pObjList;
                    pThisServer->pObjList = NULL;
                    while (pObject != NULL) {
                        pNext = pObject->pNext;
                        G_FREE(pObject);
                        pObject = pNext;
                    }
                }
            }
            if (pThisServer->pSvc != NULL) {
                hrTest = pThisServer->pSvc->CancelAsyncCall(NULL);
            } else {
                // there is no service connected so set the HRESULT to
                // get the next block to try and reconnect
                hrTest = 0x800706BF; // some bad status value thats NOT WBEM_E_INVALID_PARAMETER
            }

            // if the error is WBEM_E_INVALID_PARAMETER then the server is there
            // so we can continue
            // else if the error is something else then try to reconnect by closing and
            // reopening this connection

            if (hrTest != WBEM_E_INVALID_PARAMETER) {
                PdhiCloseWbemServer(pThisServer);
                pdhStatus = PdhiAddWbemServer (
                    szMachineNameArg,
                    &pThisServer);
            }
        }

        *pWbemServer = pThisServer;

        if (pdhStatus == ERROR_SUCCESS) pThisServer->lRefCount++;
    }

    if (szWideMachineName != NULL)  G_FREE (szWideMachineName);

    return pdhStatus;
}

PDH_FUNCTION
PdhiFreeAllWbemServers (
)
{
    PPDHI_WBEM_SERVER_DEF pThisServer;
    PPDHI_WBEM_SERVER_DEF pNextServer;

    pThisServer = pFirstWbemServer;
    while (pThisServer != NULL) {
        pNextServer = pThisServer->pNext;
        PdhiCloseWbemServer (pThisServer);
        G_FREE(pThisServer);
        pThisServer = pNextServer;
    }
    pFirstWbemServer = NULL;

    if (gp_GIT != NULL) {
        gp_GIT->Release();
        gp_GIT = NULL;
    }

    return ERROR_SUCCESS;
}

PDH_FUNCTION
PdhiGetWbemExplainText (
    IN  LPCWSTR     szMachineName,
    IN  LPCWSTR     szObjectName,
    IN  LPCWSTR     szCounterName,
    IN  LPWSTR      szExplain,
    IN  LPDWORD     pdwExplain
)
{
    PDH_STATUS Status      = ERROR_SUCCESS;
    HRESULT    hResult;
    BOOL       bDisconnect = FALSE;
    VARIANT    vsExplain;
    WCHAR      szObjectClassName[MAX_PATH];

    PPDHI_WBEM_SERVER_DEF   pThisServer = NULL;
    IEnumWbemClassObject  * pEnum       = NULL;
    IWbemClassObject      * pThisObject = NULL;
    IWbemQualifierSet     * pQualSet    = NULL;
    BOOL                    fCoInitialized = PdhiCoInitialize();

    if (szMachineName == NULL || szObjectName == NULL) {
        Status = PDH_INVALID_ARGUMENT;
    }
    if (szExplain != NULL && * pdwExplain != 0) {
        ZeroMemory(szExplain, * pdwExplain);
    }

    if (Status == ERROR_SUCCESS) {
        Status = PdhiConnectWbemServer(szMachineName, &pThisServer);
    }
    if (Status == ERROR_SUCCESS) {
        bDisconnect = TRUE;
        Status = PdhiWbemGetObjectClassName(
                pThisServer,
                szObjectName,
                szObjectClassName,
                MAX_PATH,
                & pThisObject);
    }

    if (Status == ERROR_SUCCESS) {
        VariantInit(& vsExplain);

        if (szCounterName != NULL) {
            SAFEARRAY * psaNames      = NULL;
            LONG        lLower        = 0; 
            LONG        lUpper        = 0;
            LONG        lCount        = 0;
            BSTR        bsPropName    = NULL;
            VARIANT     vName;
            VARIANT     vCountertype;
            LONG        lCounterType;

            VariantInit (& vName);
            VariantInit (& vCountertype);

            hResult = pThisObject->GetNames(
                        NULL,
                        WBEM_FLAG_NONSYSTEM_ONLY,
                        NULL,
                        & psaNames);
            if (hResult == WBEM_NO_ERROR) {
                hResult = SafeArrayGetLBound(psaNames, 1, & lLower);
                if (hResult == S_OK) {
                    hResult = SafeArrayGetUBound(psaNames, 1, & lUpper);
                }
                if (hResult == S_OK) {
                    for (lCount = lLower; lCount <= lUpper; lCount++) {
                        hResult = SafeArrayGetElement(
                                    psaNames,
                                    & lCount,
                                    & bsPropName);
                        if (hResult == S_OK) {
                            hResult = pThisObject->GetPropertyQualifierSet(
                                        bsPropName,
                                        & pQualSet);
                            if (hResult == S_OK) {
                                hResult = pQualSet->Get(
                                        cszCountertype,
                                        0,
                                        & vCountertype,
                                        NULL);
                                if (hResult == S_OK) {
                                    lCounterType = V_I4(& vCountertype);
                                    if (   ! (lCounterType & PERF_DISPLAY_NOSHOW)
                                        || (lCounterType == PERF_AVERAGE_BULK)) {
                                        hResult = pQualSet->Get(
                                                cszDisplayname,
                                                0,
                                                & vName,
                                                NULL);
                                        if (   hResult == S_OK
                                            && vName.vt == VT_BSTR) {
                                            if (lstrcmpiW(szCounterName,
                                                          V_BSTR(& vName)) == 0) {
                                                hResult = pQualSet->Get(
                                                        cszExplainText,
                                                        0,
                                                        & vsExplain,
                                                        NULL);
                                                if (   hResult == S_OK
                                                    && vsExplain.vt == VT_BSTR) {
                                                    LPWSTR szResult = V_BSTR(& vsExplain);
                                                    if (((DWORD) lstrlenW(szResult)) < (* pdwExplain)) {
                                                        lstrcpyW(szExplain, szResult);
                                                        Status = ERROR_SUCCESS;
                                                    }
                                                    else {
                                                        * pdwExplain = (DWORD) lstrlenW(szResult);
                                                        Status       = PDH_MORE_DATA;
                                                    }
                                                }
                                                pQualSet->Release();
                                                break;
                                            }
                                        }
                                    }
                                }
                                pQualSet->Release();
                            }
                        }
                        else {
                            SetLastError(hResult);
                            Status = PDH_WBEM_ERROR;
                        }
                    }
                }
                else {
                    SetLastError(hResult);
                    Status = PDH_WBEM_ERROR;
                }
            }
            else {
                SetLastError(hResult);
                Status = PDH_WBEM_ERROR;
            }
            VariantClear(& vName);
            VariantClear(& vCountertype);
        }
        else {
            // get counter object explain text
            //
            pThisObject->GetQualifierSet(& pQualSet);
            if (pQualSet != NULL) {
                hResult = pQualSet->Get(cszExplainText, 0, & vsExplain, 0);
                if (hResult == S_OK) {
                    LPWSTR szResult = V_BSTR(& vsExplain);
                    if (((DWORD) lstrlenW(szResult)) < (* pdwExplain)) {
                        lstrcpyW(szExplain, szResult);
                        Status = ERROR_SUCCESS;
                    }
                    else {
                        * pdwExplain = (DWORD) lstrlenW(szResult);
                        Status       = PDH_MORE_DATA;
                    }
                }
                else {
                    SetLastError(hResult);
                    Status = PDH_WBEM_ERROR;
                }
                pQualSet->Release();
            }
            else {
                SetLastError(WBEM_E_NOT_FOUND);
                Status = PDH_WBEM_ERROR;
            }
        }
        //pThisObject->Release();
        VariantClear(& vsExplain);
    }

    if (bDisconnect) {
        if (Status == ERROR_SUCCESS) {
            Status = PdhiDisconnectWbemServer(pThisServer);
        }
        else {
            PdhiDisconnectWbemServer(pThisServer);
        }
    }

    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }
    return Status;
}

PDH_FUNCTION
PdhiEnumWbemMachines (
    IN      LPVOID      pMachineList,
    IN      LPDWORD     pcchBufferSize,
    IN      BOOL        bUnicode
)
{
    PDH_STATUS  pdhStatus;
    PPDHI_WBEM_SERVER_DEF pThisServer = NULL;
    DWORD   dwCharsLeftInBuffer = *pcchBufferSize;
    DWORD   dwBufferSize = 0;
    DWORD   dwStrLen;
    DWORD   dwResult;

    assert (pcchBufferSize != NULL);

    // CoInitialize() if we need to
    BOOL    fCoInitialized = PdhiCoInitialize();

    // test to see if we've connected to the local machine yet, if not then do it
    if (pFirstWbemServer == NULL) {
        // add local machine
        pdhStatus = PdhiAddWbemServer (
            NULL,
            &pThisServer);
    }

    // walk down list of known machines and find the machines that are using
    // the specified name space.

    pThisServer = pFirstWbemServer;
    while (pThisServer != NULL) {
        dwStrLen = lstrlenW (pThisServer->szMachine) + 1;
        if ((pMachineList != NULL) && (dwCharsLeftInBuffer > dwStrLen)) {
            // then it will fit so add it
            dwResult = AddUniqueWideStringToMultiSz (
                pMachineList, pThisServer->szMachine, bUnicode);
            if (dwResult > 0) {
                dwBufferSize = dwResult;
                dwCharsLeftInBuffer = *pcchBufferSize - dwBufferSize;
            } // else
            // this string is already in the list so
            // nothing was added
        } else {
            // just add the string length to estimate the buffer size
            // required
            dwCharsLeftInBuffer = 0; // to prevent any other strings from being added
            dwBufferSize += dwStrLen;
        }
        pThisServer = pThisServer->pNext;
    }// end of while loop

    if (dwBufferSize <= *pcchBufferSize) {
        // the buffer size includes both term nulls
        pdhStatus = ERROR_SUCCESS;
    } else {
        // add terminating MSZ Null char size
        dwBufferSize++;
        // there wasn't enough room. See if a buffer was passed in
        pdhStatus = PDH_MORE_DATA;
    }
    // return the size used or required
    *pcchBufferSize = dwBufferSize;

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }

    return pdhStatus;
}

#pragma warning ( disable : 4127 )
PDH_FUNCTION
PdhiEnumWbemServerObjects(
    IN  PPDHI_WBEM_SERVER_DEF   pThisServer,
    IN  LPVOID                  mszObjectList,
    IN  LPDWORD                 pcchBufferSize,
    IN  DWORD                   dwDetailLevel,
    IN  BOOL                    bRefresh,       // ignored
    IN  BOOL                    bUnicode)
{
    // this function enumerates the classes that are subclassed
    // from the Win32_PerfRawData Superclass
    PDH_STATUS              pdhStatus = ERROR_SUCCESS;
    HRESULT                 hResult;
    DWORD                   dwCharsLeftInBuffer = *pcchBufferSize;
    DWORD                   dwBufferSize = 0;
    DWORD                   dwStrLen;
    DWORD                   dwRtnCount;
    DWORD                   dwResult;
    DWORD                   dwDetailLevelDesired;
    DWORD                   dwItemDetailLevel = 0;
    LPWSTR                  szClassName;
    VARIANT                 vName;
    VARIANT                 vClass;
    VARIANT                 vDetailLevel;
    BOOL                    bPerfDefault = FALSE;
    BSTR                    bsTemp = NULL;
    BSTR                    bsDisplayName = NULL;
    BSTR                    bsClass = NULL;
    BSTR                    bsCostly = NULL;
    BSTR                    bsDetailLevel = NULL;
    BSTR                    bsPerfDefault = NULL;

    BOOL                    bGetCostlyItems = FALSE;
    BOOL                    bIsCostlyItem = FALSE;
    BOOL                    bDisconnectServer = FALSE;

    IEnumWbemClassObject  * pEnum = NULL;
    IWbemClassObject      * pThisClass = NULL;
    IWbemQualifierSet     * pQualSet = NULL;

    PPDHI_WBEM_OBJECT_DEF   pHead   = NULL;
    PPDHI_WBEM_OBJECT_DEF   pObject = NULL;

    DBG_UNREFERENCED_PARAMETER(bRefresh);

    VariantInit(& vName);
    VariantInit(& vClass);
    VariantInit(& vDetailLevel);

    if (pThisServer->pObjList != NULL) {
        PPDHI_WBEM_OBJECT_DEF pObject = pThisServer->pObjList;
        PPDHI_WBEM_OBJECT_DEF pNext;

        pThisServer->pObjList = NULL;
        while (pObject != NULL) {
            pNext = pObject->pNext;
            if (pObject->pClass != NULL) pObject->pClass->Release();
            G_FREE(pObject);
            pObject = pNext;
        }
    }

    // create an enumerator of the PerfRawData class
    bsTemp = SysAllocString (cszPerfRawData);
    if (bsTemp) {
        hResult = pThisServer->pSvc->CreateClassEnum (
                bsTemp,
                WBEM_FLAG_DEEP | WBEM_FLAG_USE_AMENDED_QUALIFIERS,
                NULL,
                & pEnum);
        PdhiSysFreeString(&bsTemp);

        bDisconnectServer = TRUE;
        // Set security on the proxy
        if (SUCCEEDED(hResult))
        {
            hResult = SetWbemSecurity(pEnum);
        }

        if (hResult != WBEM_NO_ERROR) {
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        }
    } else {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // set costly flag
        bGetCostlyItems = ((dwDetailLevel & PERF_DETAIL_COSTLY) == PERF_DETAIL_COSTLY);
        dwDetailLevelDesired = (DWORD)(dwDetailLevel & PERF_DETAIL_STANDARD);
        bsCostly = SysAllocString (cszCostly);
        bsDisplayName = SysAllocString (cszDisplayname);
        bsClass = SysAllocString (cszClass);
        bsDetailLevel = SysAllocString (cszPerfdetail);
        bsPerfDefault = SysAllocString(cszPerfdefault);

        if (bsCostly && bsDisplayName && bsClass && bsDetailLevel) {
            while (TRUE) {
                hResult = pEnum->Next (
                    WBEM_INFINITE,      // timeout
                    1,      // return only 1 object
                    &pThisClass,
                    &dwRtnCount);

                // no more classes
                if ((pThisClass == NULL) || (dwRtnCount == 0)) break;

                // get the display name of this class
                bIsCostlyItem = FALSE; // assume it's not unless proven otherwise
                bPerfDefault  = FALSE;
                hResult = pThisClass->Get(bsClass, 0, & vClass, 0, 0);

                pThisClass->GetQualifierSet (&pQualSet);
                if (pQualSet != NULL) {
                    VariantClear (&vName);
                    hResult = pQualSet->Get (bsCostly, 0, &vName, 0);
                    if (hResult == S_OK) {
                        bIsCostlyItem = TRUE;
                    }
                    hResult = pQualSet->Get (bsDetailLevel, 0, &vDetailLevel, 0);
                    if (hResult == S_OK) {
                        dwItemDetailLevel = (DWORD)V_I4(&vDetailLevel);
                    } else {
                        dwItemDetailLevel = 0;
                    }

                    VariantClear(&vName);
                    hResult = pQualSet->Get(bsPerfDefault, 0, & vName, 0);
                    if (hResult != WBEM_E_NOT_FOUND) {
                        bPerfDefault = (BOOL) V_BOOL(& vName);
                    }

                    VariantClear(&vName);
                    hResult = pQualSet->Get(bsDisplayName, 0, & vName, 0);
                    pQualSet->Release();
                } else {
                    hResult = WBEM_E_NOT_FOUND;
                }

                if (hResult == WBEM_E_NOT_FOUND) {
                    // then this has not display name so
                    // pull the class name
                    hResult = pThisClass->Get(bsClass, 0, & vName, 0, 0);
                }

                if (hResult == WBEM_E_NOT_FOUND) {
                    szClassName = (LPWSTR) cszNotFound;
                } else {
                    szClassName = (LPWSTR) V_BSTR(&vName);
                }

                if (((bIsCostlyItem && bGetCostlyItems) || // if costly and we want them
                    (!bIsCostlyItem)) && (dwItemDetailLevel <= dwDetailLevelDesired)) {
                    dwStrLen = lstrlenW (szClassName) + 1;
                    if ((mszObjectList != NULL) && (dwCharsLeftInBuffer > dwStrLen)) {
                        // then it will fit so add it
                        dwResult = AddUniqueWideStringToMultiSz (
                            mszObjectList, szClassName, bUnicode);
                        if (dwResult > 0) {
                            dwBufferSize = dwResult;
                            dwCharsLeftInBuffer = *pcchBufferSize - dwBufferSize;
                        } // else
                    } else {
                        // just add the string length to estimate the buffer size
                        // required
                        dwCharsLeftInBuffer = 0; // to prevent any other strings from being added
                        dwBufferSize += dwStrLen;
                    }
                }

                if (lstrcmpiW(szClassName, cszNotFound) != 0) {
                    LPWSTR szClass = (LPWSTR) V_BSTR(& vClass);
                    DWORD dwSize   = sizeof(PDHI_WBEM_OBJECT_DEF)
                                   + sizeof(WCHAR) * (  lstrlenW(szClassName)
                                                      + lstrlenW(szClass) + 2);
                    pObject = (PPDHI_WBEM_OBJECT_DEF) G_ALLOC(dwSize);
                    if (pObject != NULL) {
                        pObject->bDefault  = bPerfDefault;
                        pObject->szObject  = (LPWSTR) (((LPBYTE) pObject)
                                           + sizeof(PDHI_WBEM_OBJECT_DEF));
                        lstrcpyW(pObject->szObject, szClass);
                        pObject->szDisplay = (LPWSTR) (((LPBYTE) pObject)
                                           + sizeof(PDHI_WBEM_OBJECT_DEF)
                                           + sizeof(WCHAR) * (lstrlenW(szClass) + 1));
                        lstrcpyW(pObject->szDisplay, szClassName);
                        pObject->pNext = pHead;
                        pHead          = pObject;
                    }
                    else {
                        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
                        pThisClass->Release();
                        break;
                    }
                }

                // clear the variant
                VariantClear(& vName);
                VariantClear(& vClass);
                VariantClear(& vDetailLevel);

                // free this class
                pThisClass->Release();
            }
            dwBufferSize ++; // the final NULL

            if (dwBufferSize <= *pcchBufferSize) {
                pdhStatus = ERROR_SUCCESS;
            } else {
                // there wasn't enough room. See if a buffer was passed in
                pdhStatus = PDH_MORE_DATA;
            }
            // return the size used or required
            *pcchBufferSize = dwBufferSize;
        }
    } else {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    PdhiSysFreeString(& bsDisplayName);
    PdhiSysFreeString(& bsClass);
    PdhiSysFreeString(& bsCostly);
    PdhiSysFreeString(& bsDetailLevel);
    PdhiSysFreeString(& bsPerfDefault);

    VariantClear(& vName);
    VariantClear(& vClass);
    VariantClear(& vDetailLevel);

    if (pEnum != NULL) pEnum->Release();

    if (pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA) {
        pThisServer->pObjList = pHead;
    }
    else {
        pObject = pHead;
        while (pObject != NULL) {
            pHead   = pObject->pNext;
            G_FREE(pObject);
            pObject = pHead;
        }
    }

    if (bDisconnectServer) {
        if (pdhStatus == ERROR_SUCCESS) {
            pdhStatus = PdhiDisconnectWbemServer (pThisServer);
        } else {
            // keep error code from function body
            PdhiDisconnectWbemServer (pThisServer);
        }
    }

    return pdhStatus;
}

PDH_FUNCTION
PdhiEnumWbemObjects(
    IN  LPCWSTR     szWideMachineName,
    IN  LPVOID      mszObjectList,
    IN  LPDWORD     pcchBufferSize,
    IN  DWORD       dwDetailLevel,
    IN  BOOL        bRefresh,       // ignored
    IN  BOOL        bUnicode)
{
    PDH_STATUS             pdhStatus;
    PPDHI_WBEM_SERVER_DEF  pThisServer;
    BOOL                   fCoInitialized = PdhiCoInitialize();

    pdhStatus = PdhiConnectWbemServer(szWideMachineName, & pThisServer);
    if (pdhStatus == ERROR_SUCCESS) {
        pdhStatus = PdhiEnumWbemServerObjects(pThisServer,
                                              mszObjectList,
                                              pcchBufferSize,
                                              dwDetailLevel,
                                              bRefresh,
                                              bUnicode);
    }

    if (fCoInitialized) {
        PdhiCoUninitialize();
    }

    return pdhStatus;
}

PDH_FUNCTION
PdhiGetDefaultWbemObject (
    IN  LPCWSTR     szMachineName,
    IN  LPVOID      szDefaultObjectName,
    IN  LPDWORD     pcchBufferSize,
    IN  BOOL        bUnicode)
{
    // walk down the list of WBEM perf classes and find the one with the
    // default qualifier

    PDH_STATUS              pdhStatus;
    PPDHI_WBEM_SERVER_DEF   pThisServer;
    HRESULT                 hResult;
    DWORD                   dwBufferSize = 0;
    DWORD                   dwStrLen;
    BOOL                    bDisconnectServer = FALSE;

    // CoInitialize() if we need to
    BOOL fCoInitialized = PdhiCoInitialize();

    pdhStatus = PdhiConnectWbemServer (
        szMachineName,
        &pThisServer);

    if (pdhStatus == ERROR_SUCCESS) {
        bDisconnectServer = TRUE;
        if (pThisServer->pObjList == NULL) {
            DWORD dwSize = 0;
            pdhStatus = PdhiEnumWbemServerObjects(
                            pThisServer,
                            NULL,
                            & dwSize,
                            PERF_DETAIL_WIZARD | PERF_DETAIL_COSTLY,
                            TRUE,
                            TRUE);
            if (pThisServer->pObjList != NULL) {
                pdhStatus = ERROR_SUCCESS;
            }
        }

        if (pThisServer->pObjList != NULL) {
            PPDHI_WBEM_OBJECT_DEF pObject = pThisServer->pObjList;

            pdhStatus = PDH_CSTATUS_NO_OBJECT;
            while (pObject != NULL) {
                if (pObject->bDefault) {
                    pdhStatus = ERROR_SUCCESS;
                    if (bUnicode) {
                        dwStrLen = lstrlenW(pObject->szDisplay);
                        if (   szDefaultObjectName != NULL
                            && dwStrLen < * pcchBufferSize) {
                            lstrcpyW((LPWSTR) szDefaultObjectName,
                                     pObject->szDisplay);
                        }
                        else {
                            pdhStatus = PDH_MORE_DATA;
                        }
                        dwBufferSize = dwStrLen + 1;
                    }
                    else {
                        dwStrLen = * pcchBufferSize;
                        pdhStatus = PdhiConvertUnicodeToAnsi( _getmbcp(),
                                        pObject->szDisplay,
                                        (LPSTR) szDefaultObjectName,
                                        & dwStrLen);
                        dwBufferSize = dwStrLen;
                    }
                }
                pObject = pObject->pNext;
            }
        }
    }

    // return the size used or required
    * pcchBufferSize = dwBufferSize;

    if (bDisconnectServer) {
        if (pdhStatus == ERROR_SUCCESS) {
            pdhStatus = PdhiDisconnectWbemServer (pThisServer);
        } else {
            // keep error code from function body
            PdhiDisconnectWbemServer (pThisServer);
        }
    }

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }

    return pdhStatus;
}

PDH_FUNCTION
PdhiEnumWbemObjectItems (
    IN LPCWSTR      szWideMachineName,
    IN LPCWSTR      szWideObjectName,
    IN LPVOID       mszCounterList,
    IN LPDWORD      pcchCounterListLength,
    IN LPVOID       mszInstanceList,
    IN LPDWORD      pcchInstanceListLength,
    IN DWORD        dwDetailLevel,
    IN DWORD        dwFlags,
    IN BOOL         bUnicode
)
{
    PDH_STATUS          pdhStatus      = ERROR_SUCCESS;
    PDH_STATUS          CounterStatus  = ERROR_SUCCESS;
    PDH_STATUS          InstanceStatus = ERROR_SUCCESS;
    DWORD               dwStrLen;
    PPDHI_WBEM_SERVER_DEF   pThisServer;
    HRESULT                 hResult;
    DWORD               dwReturnCount;
    DWORD               dwCounterStringLen = 0;
    DWORD               dwInstanceStringLen = 0;
    LPWSTR              szNextWideString = NULL;
    LPSTR               szNextAnsiString = NULL;
    WCHAR               szObjectClassName[MAX_PATH];
    BSTR                bsName = NULL;
    BSTR                bsClassName = NULL;
    BOOL                bSingletonClass = FALSE;
    VARIANT             vName;
    DWORD               bDisconnectServer = FALSE;

    IWbemClassObject        *pThisClass = NULL;
    IWbemQualifierSet       *pQualSet = NULL;

    DBG_UNREFERENCED_PARAMETER (dwFlags);

    assert (szWideObjectName != NULL);
    assert (pcchCounterListLength != NULL);
    assert (pcchInstanceListLength != NULL);

    // CoInitialize() if we need to
    BOOL    fCoInitialized = PdhiCoInitialize();

    pdhStatus = PdhiConnectWbemServer (
        szWideMachineName,
        &pThisServer);

    // enumerate the instances
    if (pdhStatus == ERROR_SUCCESS) {
        pdhStatus = PdhiWbemGetObjectClassName (
            pThisServer,
            szWideObjectName,
            &szObjectClassName[0],
            sizeof(szObjectClassName) / sizeof(szObjectClassName[0]),
            &pThisClass);

        assert (pThisClass != NULL);

        bDisconnectServer = TRUE;

        if (pdhStatus == ERROR_SUCCESS) {
            bSingletonClass = PdhiIsSingletonClass (pThisClass);
        } else if (pThisClass == NULL) {
            pdhStatus = PDH_CSTATUS_NO_OBJECT;
        } else {
            // unable to find matching perf class
            // return status returned by method
        }
    }

    //enumerate the counter properties

    if (pdhStatus == ERROR_SUCCESS) {
        SAFEARRAY   *psaNames = NULL;
        long        lLower; 
        long        lUpper = 0;
        long        lCount;
        BSTR        bsPropName = NULL;
        BSTR        bsCountertype = NULL;
        BSTR        bsDisplayname = NULL;
        BSTR        bsDetailLevel = NULL;
        VARIANT     vCountertype;
        VARIANT     vDetailLevel;
        DWORD       dwItemDetailLevel;

        VariantInit (&vName);
        VariantInit (&vCountertype);
        VariantInit (&vDetailLevel);

        assert (pThisClass != NULL);

        dwDetailLevel &= PERF_DETAIL_STANDARD; // mask off any inappropriate bits

        // get the properties of this class as a Safe Array
        hResult = pThisClass->GetNames (NULL,
            WBEM_FLAG_NONSYSTEM_ONLY, NULL, &psaNames);
        if (hResult == WBEM_NO_ERROR) {
            hResult = SafeArrayGetLBound (psaNames, 1, &lLower);
            if (hResult == S_OK) {
                hResult = SafeArrayGetUBound (psaNames, 1, &lUpper);
            }
            if (hResult == S_OK) {
                szNextAnsiString = (LPSTR)mszCounterList;
                szNextWideString = (LPWSTR)mszCounterList;
                bsCountertype = SysAllocString (cszCountertype);
                bsDisplayname = SysAllocString (cszDisplayname);
                bsDetailLevel = SysAllocString (cszPerfdetail);
                if (bsCountertype && bsDisplayname && bsDetailLevel) {
                    for (lCount = lLower; lCount <= lUpper; lCount++) {
                        hResult = SafeArrayGetElement (psaNames, &lCount, &bsPropName);
                        if (hResult == S_OK) {
                            // get the qualifier set for this property
                            hResult = pThisClass->GetPropertyQualifierSet (
                                bsPropName, &pQualSet);
                            if (hResult == WBEM_NO_ERROR) {
                                LONG    lCounterType;
                                hResult = pQualSet->Get (bsDetailLevel, 0, &vDetailLevel, 0);
                                if (hResult == S_OK) {
                                    dwItemDetailLevel = (DWORD)V_I4(&vDetailLevel);
                                } else {
                                    dwItemDetailLevel = 0;
                                }

                                // make sure this is a perf counter property
                                hResult = pQualSet->Get (bsCountertype, 0, &vCountertype, NULL);
                                if (hResult == WBEM_NO_ERROR) {
                                    lCounterType = V_I4(&vCountertype);
                                    // then see if this is a displayable counter
                                    if ((!(lCounterType & PERF_DISPLAY_NOSHOW) ||
                                         (lCounterType == PERF_AVERAGE_BULK)) &&
                                        (dwItemDetailLevel <= dwDetailLevel)) {
                                        // by testing for the counter type
                                        // get the display name for this property
                                        hResult = pQualSet->Get (bsDisplayname, 0, &vName, NULL);
                                        if (hResult == WBEM_NO_ERROR && vName.vt == VT_BSTR) {
                                            // display name found
                                            if (bUnicode) {
                                                dwStrLen = lstrlenW (V_BSTR(&vName)) + 1;
                                                if (   (mszCounterList != NULL)
                                                    && (   (dwCounterStringLen + dwStrLen)
                                                        <= (* pcchCounterListLength))) {
                                                    lstrcpyW (szNextWideString, V_BSTR(&vName));
                                                    szNextWideString += dwStrLen;
                                                }
                                                else {
                                                    pdhStatus = PDH_MORE_DATA;
                                                }
                                            } else {
                                                dwStrLen = (dwCounterStringLen < * pcchCounterListLength)
                                                         ? (* pcchCounterListLength - dwCounterStringLen)
                                                         : (0);
                                                 pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                                         V_BSTR(& vName), szNextAnsiString, & dwStrLen);
                                                 if (pdhStatus == ERROR_SUCCESS) {
                                                    szNextAnsiString += dwStrLen;
                                                 }
                                            }
                                            dwCounterStringLen += dwStrLen;
                                        }
                                    } else {
                                        // this is a "don't show" counter so skip it
                                    }
                                } else {
                                    // unable to get the counter type so it's probably
                                    // not a perf counter property, skip it and continue
                                }
                                VariantClear (&vName);
                                VariantClear (&vCountertype);
                                VariantClear (&vDetailLevel);

                                pQualSet->Release();
                            } else {
                                // no properties so continue with the next one
                            }
                        } else {
                            // unable to read element in SafeArray
                            pdhStatus = PDH_WBEM_ERROR;
                            SetLastError(hResult);
                        }
                    } // end for each element in SafeArray
                } else {
                    pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
                }
                PdhiSysFreeString (&bsCountertype);
                PdhiSysFreeString (&bsDisplayname);
                PdhiSysFreeString (&bsDetailLevel);
            } else {
                // unable to get array boundries
                pdhStatus = PDH_WBEM_ERROR;
                SetLastError (hResult);
            }
        } else {
            // unable to get property strings
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        }

        dwCounterStringLen ++; // final NULL for MSZ
        if (dwCounterStringLen > * pcchCounterListLength) {
            pdhStatus = PDH_MORE_DATA;
        }

        if (pdhStatus == ERROR_SUCCESS) {
            if (bUnicode) {
                if (szNextWideString != NULL) {
                    if (szNextWideString != (LPWSTR)mszCounterList) {
                        *szNextWideString++ = 0;
                    } else {
                        // nothing returned
                        dwCounterStringLen = 0;
                    }
                } else {
                    // then this is just a length query so return
                    // include the the MSZ term null char
                    CounterStatus = PDH_MORE_DATA;
                }
            } else {
                if (szNextAnsiString != NULL) {
                    if (szNextAnsiString != (LPSTR)mszCounterList) {
                        *szNextAnsiString ++ = 0;
                    } else {
                        dwCounterStringLen = 0;
                    }
                } else {
                    // then this is just a length query so return
                    // include the the MSZ term null char
                    CounterStatus = PDH_MORE_DATA;
                }
            }
        }
        else {
            CounterStatus = pdhStatus;
        }

        VariantClear (&vName);
        VariantClear (&vCountertype);
        VariantClear (&vDetailLevel);

                // Clear the SafeArray if it exists
        if ( NULL != psaNames )
        {
            SafeArrayDestroy( psaNames );
            psaNames = NULL;
        }

        *pcchCounterListLength = dwCounterStringLen;

        //pThisClass->Release();
    }

    // Get instance strings if necessary

    if (pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA) {
        szNextAnsiString = (LPSTR)  mszInstanceList;
        szNextWideString = (LPWSTR) mszInstanceList;

        if (!bSingletonClass) {
            IWbemRefresher           * pRefresher    = NULL;
            IWbemConfigureRefresher  * pConfig       = NULL;
            IWbemHiPerfEnum          * pEnum         = NULL;
            LONG                       lID;
            DWORD                      dwNumReturned = 1;
            DWORD                      dwNumObjects  = 0;
            DWORD                      i;
            IWbemObjectAccess       ** apEnumAccess  = NULL;
            CIMTYPE                    cimType;
            WCHAR                      szName[SMALL_BUFFER_SIZE];
            LONG                       lNameHandle   = -1;
            LONG                       lSize1        = SMALL_BUFFER_SIZE;
            LONG                       lSize2        = 0;

            hResult = CoCreateInstance(CLSID_WbemRefresher,
                                       NULL,
                                       CLSCTX_INPROC_SERVER,
                                       IID_IWbemRefresher,
                                       (void **) & pRefresher);
            if (SUCCEEDED(hResult)) {
                hResult = pRefresher->QueryInterface(
                                IID_IWbemConfigureRefresher,
                                (void **) & pConfig);
                if (SUCCEEDED(hResult)) {
                    hResult = pConfig->AddEnum(pThisServer->pSvc,
                                               szObjectClassName,
                                               0,
                                               NULL,
                                               & pEnum,
                                               & lID);
                    if (SUCCEEDED(hResult)) {
                        hResult = pRefresher->Refresh(0L);
                        if (SUCCEEDED(hResult)) {
                            hResult = pEnum->GetObjects(0L,
                                                        dwNumObjects,
                                                        apEnumAccess,
                                                        & dwNumReturned);
                            if (hResult == WBEM_E_BUFFER_TOO_SMALL) {
                                apEnumAccess = (IWbemObjectAccess **)
                                        G_ALLOC(dwNumReturned
                                                * sizeof(IWbemObjectAccess *));
                                if (apEnumAccess != NULL) {
                                    ZeroMemory(apEnumAccess, dwNumReturned
                                             * sizeof(IWbemObjectAccess *));
                                    dwNumObjects = dwNumReturned;
                                    hResult = pEnum->GetObjects(0L,
                                                            dwNumObjects,
                                                            apEnumAccess,
                                                            & dwNumReturned);
                                }
                                else {
                                    hResult = WBEM_E_OUT_OF_MEMORY;
                                }
                            }
                            if (SUCCEEDED(hResult)) {
                                for (i = 0; i < dwNumReturned; i ++) {
                                    hResult = apEnumAccess[i]->GetPropertyHandle(
                                                    cszName,
                                                    & cimType,
                                                    & lNameHandle);
                                    if (SUCCEEDED(hResult) && lNameHandle != -1) {
                                        ZeroMemory(szName,
                                                   SMALL_BUFFER_SIZE * sizeof(WCHAR));
                                        hResult = apEnumAccess[i]->ReadPropertyValue(
                                                lNameHandle,
                                                lSize1,
                                                & lSize2,
                                                (LPBYTE) szName);
                                        if (SUCCEEDED(hResult) && lstrlenW(szName) > 0) {
                                            if (bUnicode) {
                                                dwStrLen = lstrlenW(szName) + 1;
                                                if (   (mszInstanceList != NULL)
                                                    && (   (dwInstanceStringLen + dwStrLen)
                                                         < (* pcchInstanceListLength))) {
                                                    lstrcpyW (szNextWideString, szName);
                                                    szNextWideString += dwStrLen;
                                                }
                                                else {
                                                    pdhStatus = PDH_MORE_DATA;
                                                }
                                            }
                                            else {
                                                dwStrLen = (dwInstanceStringLen <= * pcchInstanceListLength)
                                                         ? (* pcchInstanceListLength - dwInstanceStringLen)
                                                         : (0);
                                                pdhStatus = PdhiConvertUnicodeToAnsi(
                                                        _getmbcp(),
                                                        szName,
                                                        szNextAnsiString,
                                                        & dwStrLen);
                                                if (pdhStatus == ERROR_SUCCESS) {
                                                    szNextAnsiString += dwStrLen;
                                                }
                                            }
                                            dwInstanceStringLen += dwStrLen;
                                        }
                                    }
                                    apEnumAccess[i]->Release();
                                }
                            }
                        }
                    }
                }
            }

            if (! SUCCEEDED(hResult)) {
                SetLastError(hResult);
                pdhStatus = PDH_WBEM_ERROR;
            }
            else if (dwInstanceStringLen == 0) {
                dwInstanceStringLen = 2;
                if (   szNextWideString != NULL
                    && dwInstanceStringLen <= * pcchInstanceListLength) {
                    * szNextWideString = L'\0';
                    szNextWideString ++;
                }
                if (   szNextAnsiString != NULL
                    && dwInstanceStringLen <= * pcchInstanceListLength) {
                    * szNextAnsiString = '\0';
                    szNextAnsiString ++;
                }
            }
            else {
                dwInstanceStringLen ++;
            }

            if (apEnumAccess != NULL) G_FREE(apEnumAccess);
            if (pEnum        != NULL) pEnum->Release();
            if (pConfig      != NULL) pConfig->Release();
            if (pRefresher   != NULL) pRefresher->Release();
        }

        if (dwInstanceStringLen > * pcchInstanceListLength) {
            pdhStatus = PDH_MORE_DATA;
        }
        if (pdhStatus == ERROR_SUCCESS) {
            if (bUnicode) {
                if (szNextWideString != NULL) {
                    if (szNextWideString != (LPWSTR)mszInstanceList) {
                        *szNextWideString++ = 0;
                    } else {
                        dwInstanceStringLen = 0;
                    }
                } else if (dwInstanceStringLen > 0) {
                    // then this is just a length query so return
                    // include the the MSZ term null char
                    InstanceStatus = PDH_MORE_DATA;
                }
            } else {
                if (szNextAnsiString != NULL) {
                    if (szNextAnsiString != (LPSTR)mszInstanceList) {
                        *szNextAnsiString++ = 0;
                    } else {
                        dwInstanceStringLen = 0;
                    }
                } else if (dwInstanceStringLen > 0) {
                    // then this is just a length query so return
                    // include the the MSZ term null char
                    InstanceStatus = PDH_MORE_DATA;
                }
            }
        }
        else {
            InstanceStatus = pdhStatus;
        }
        *pcchInstanceListLength = dwInstanceStringLen;
    }

    VariantClear (&vName);

    if (bDisconnectServer) {
        if (pdhStatus == ERROR_SUCCESS) {
            pdhStatus = PdhiDisconnectWbemServer (pThisServer);
        } else {
            // keep error code from function body
            PdhiDisconnectWbemServer (pThisServer);
        }
    }

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }

    if (pdhStatus == ERROR_SUCCESS) {
        pdhStatus = (CounterStatus == ERROR_SUCCESS)
                  ? (InstanceStatus) : (CounterStatus);
    }

    return pdhStatus;
}
#pragma warning ( default : 4127 )

PDH_FUNCTION
PdhiGetDefaultWbemProperty (
    IN LPCWSTR      szMachineName,
    IN LPCWSTR      szObjectName,
    IN LPVOID       szDefaultCounterName,
    IN LPDWORD      pcchBufferSize,
    IN BOOL         bUnicode
)
{
    PDH_STATUS          pdhStatus = ERROR_SUCCESS;
    DWORD               dwStrLen;
    PPDHI_WBEM_SERVER_DEF   pThisServer;
    HRESULT                 hResult;
    DWORD               dwCounterStringLen = 0;
    WCHAR               szObjectClassName[MAX_PATH];
    DWORD               bDisconnectServer = FALSE;
    BOOL                bFound = FALSE;

    IWbemClassObject        *pThisClass = NULL;
    IWbemQualifierSet       *pQualSet = NULL;

    assert (szMachineName != NULL);
    assert (szObjectName != NULL);
    assert (pcchBufferSize != NULL);

    // CoInitialize() if we need to
    BOOL    fCoInitialized = PdhiCoInitialize();

    pdhStatus = PdhiConnectWbemServer (
        szMachineName,
        &pThisServer);

    // enumerate the instances
    if (pdhStatus == ERROR_SUCCESS) {
        pdhStatus = PdhiWbemGetObjectClassName (
            pThisServer,
            szObjectName,
            &szObjectClassName[0],
            sizeof(szObjectClassName) / sizeof(szObjectClassName[0]),
            &pThisClass);
        bDisconnectServer = TRUE;
    }

    //enumerate the counter properties

    if (pdhStatus == ERROR_SUCCESS) {
        SAFEARRAY   *psaNames = NULL;
        long        lLower; 
        long        lUpper = 0;
        long        lCount;
        BSTR        bsPropName = NULL;
        BSTR        bsDisplayname = NULL;
        BSTR        bsPerfDefault = NULL;
        VARIANT     vName, vCountertype;

        VariantInit (&vName);
        VariantInit (&vCountertype);

        // get the properties of this class as a Safe Array
        hResult = pThisClass->GetNames (NULL,
            WBEM_FLAG_NONSYSTEM_ONLY, NULL, &psaNames);
        if (hResult == WBEM_NO_ERROR) {
            hResult = SafeArrayGetLBound (psaNames, 1, &lLower);
            if (hResult == S_OK) {
                hResult = SafeArrayGetUBound (psaNames, 1, &lUpper);
            }
            if (hResult == S_OK) {
                bsDisplayname = SysAllocString (cszDisplayname);
                bsPerfDefault = SysAllocString (cszPerfdefault);
                if (bsDisplayname && bsPerfDefault) {
                    for (lCount = lLower; lCount <= lUpper; lCount++) {
                        hResult = SafeArrayGetElement (psaNames, &lCount, &bsPropName);
                        if (hResult == S_OK) {
                            // get the qualifier set for this property
                            hResult = pThisClass->GetPropertyQualifierSet (
                                bsPropName, &pQualSet);
                            if (hResult == WBEM_NO_ERROR) {
                                // make sure this is a perf counter property
                                hResult = pQualSet->Get (bsPerfDefault, 0, &vCountertype, NULL);
                                if (hResult == WBEM_NO_ERROR) {
                                    if ((BOOL)V_BOOL(&vCountertype)) {
                                        // found the default property so load it and return
                                        hResult = pQualSet->Get (bsDisplayname, 0, &vName, NULL);
                                        if (hResult == WBEM_NO_ERROR) {
                                            // display name found
                                            bFound = TRUE;
                                            if (bUnicode) {
                                                dwStrLen = lstrlenW (V_BSTR(&vName)) + 1;
                                                if (   (szDefaultCounterName != NULL)
                                                    && (dwStrLen <= * pcchBufferSize)) {
                                                    lstrcpyW ((LPWSTR)szDefaultCounterName,
                                                              (LPWSTR)V_BSTR(&vName));
                                                }
                                                else {
                                                    pdhStatus = PDH_MORE_DATA;
                                                }
                                            }
                                            else {
                                                dwStrLen = * pcchBufferSize;
                                                pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                                        (LPWSTR) V_BSTR(& vName),
                                                        (LPSTR)  szDefaultCounterName,
                                                        & dwStrLen);
                                            }
                                            // this is either the amount used or the amount needed
                                            dwCounterStringLen = dwStrLen;
                                            // free qualifier set
                                            pQualSet->Release();
                                            // now leave
                                            break;
                                        } else {
                                            // no qualifier so assume FALSE
                                        }
                                    } else {
                                        // value found but is FALSE
                                    }
                                }
                                // free the qualifier set
                                pQualSet->Release();
                                // clear variants
                                VariantClear (&vName);
                                VariantClear (&vCountertype);
                            } else {
                                // no Qualifiers so continue with the next one
                            }
                        } else {
                            // unable to read element in SafeArray
                            pdhStatus = PDH_WBEM_ERROR;
                            SetLastError(hResult);
                        }
                    } // end for each element in SafeArray
                } else {
                    pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
                }
                // no default defined for this object
                if ((pdhStatus == ERROR_SUCCESS) && !bFound) pdhStatus = PDH_CSTATUS_NO_COUNTER;

                PdhiSysFreeString (&bsPerfDefault);
                PdhiSysFreeString (&bsDisplayname);
            } else {
                // unable to get array boundries
                pdhStatus = PDH_WBEM_ERROR;
                SetLastError (hResult);
            }
        } else {
            // unable to get property strings
            pdhStatus = PDH_WBEM_ERROR;
            SetLastError (hResult);
        }

        if ( NULL != psaNames )
        {
            SafeArrayDestroy( psaNames );
        }

        VariantClear (&vName);
        VariantClear (&vCountertype);

        //pThisClass->Release();
    }
    *pcchBufferSize = dwCounterStringLen;

    if (bDisconnectServer) {
        if (pdhStatus == ERROR_SUCCESS) {
            pdhStatus = PdhiDisconnectWbemServer (pThisServer);
        } else {
            // keep error code from function body
            PdhiDisconnectWbemServer (pThisServer);
        }
    }

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }

    return pdhStatus;
}

PDH_FUNCTION
PdhiEncodeWbemPathW (
    IN      PDH_COUNTER_PATH_ELEMENTS_W *pCounterPathElements,
    IN      LPWSTR                      szFullPathBuffer,
    IN      LPDWORD                     pcchBufferSize,
    IN      LANGID                      LangId,
    IN      DWORD                       dwFlags
)
/*++

  converts a set of path elements in either Registry or WBEM format
  to a path in either Registry or WBEM format as defined by the flags.

--*/
{
    PDH_STATUS  pdhStatus = ERROR_SUCCESS;
    DWORD       dwBuffSize;
    LPWSTR      szTempPath = NULL;
    DWORD       dwCurSize = 0;

    LPWSTR      szThisChar;
    IWbemClassObject        *pWbemClass = NULL;
    PPDHI_WBEM_SERVER_DEF   pWbemServer = NULL;
    DWORD                   bDisconnectServer = FALSE;

    DBG_UNREFERENCED_PARAMETER (LangId);

    assert (pCounterPathElements != NULL); // this is not allowed
    assert (dwFlags != 0); // this should be caught by the calling fn.
    assert (pcchBufferSize != NULL); // this is required

    // CoInitialize() if we need to
    BOOL    fCoInitialized = PdhiCoInitialize();

    // create a working buffer the same size as the one passed in

    if (*pcchBufferSize == 0L) {
        dwBuffSize = *pcchBufferSize * sizeof(WCHAR);
    } else {
        dwBuffSize = 1024 * sizeof(WCHAR); // just something to work with
    }

    szTempPath = (LPWSTR) G_ALLOC(dwBuffSize);

    if (szTempPath == NULL) {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    } else if (pdhStatus == ERROR_SUCCESS) {
        szTempPath[0] = L'\0';
        // start by adding the machine name to the path
        if (pCounterPathElements->szMachineName != NULL) {
            lstrcpyW (szTempPath, pCounterPathElements->szMachineName);
            if (dwFlags == (PDH_PATH_WBEM_INPUT)) {
                // if this is a wbem element in to a registry path out,
                // then remove the namespace which occurs starting at the
                // second backslash
                for (szThisChar = &szTempPath[2];
                    (*szThisChar != 0) && (*szThisChar != L'\\');
                    szThisChar++);
                if (*szThisChar != 0) *szThisChar = 0;
            } else if (dwFlags == (PDH_PATH_WBEM_RESULT)) {
                // if this is a registry element in to a WBEM out, then
                // append the default namespace to the machine name
//NAMEFIX                lstrcatW (szTempPath, cszWbemDefaultPerfRoot);
            }
        } else {
            // no machine name specified so add the default machine
            // and default namespace for a wbem output path
            if (dwFlags == (PDH_PATH_WBEM_RESULT)) {
                lstrcpyW (szTempPath, cszDoubleBackSlashDot); // default machine
//NAMEFIX                lstrcatW (szTempPath, cszWbemDefaultPerfRoot);
            } else {
                // no entry required for the registry path
            }
        }
        dwCurSize = lstrlenW(szTempPath);

        // now add the object or class name
        if (pdhStatus == ERROR_SUCCESS) {
            if (pCounterPathElements->szObjectName != NULL) {
                DWORD   dwSize;
                WCHAR   szTempObjectString[1024];
    
                dwSize = 1024;
                ZeroMemory(szTempObjectString, sizeof(WCHAR) * 1024);
                // then the input is different from the output
                // so convert from one to the other
                // and default name space since perf counters won't be
                // found elsewhere
                pdhStatus = PdhiConnectWbemServer (
                    NULL, // use local machine
                    &pWbemServer);
                if (pdhStatus == ERROR_SUCCESS) {
                    bDisconnectServer = TRUE;
                    if (dwFlags & PDH_PATH_WBEM_INPUT) {
                        // convert the WBEM Class to the display name
                        pdhStatus = PdhiWbemGetClassDisplayName (
                            pWbemServer,
                            pCounterPathElements->szObjectName,
                            &szTempObjectString[0],
                            dwSize,
                            &pWbemClass);
                        // add a backslash path separator for registry output
                        if (pdhStatus == ERROR_SUCCESS) {
                            if (dwFlags & PDH_PATH_WBEM_RESULT) {
                                lstrcatW(szTempPath, cszColon);
                                // just copy the string, but save
                                lstrcpyW (szTempObjectString, pCounterPathElements->szObjectName);
                            } else {
                                lstrcatW(szTempPath, cszBackSlash);
                                // copy the retrieved string
                            }
                        }
                    } else {
                        // convert the display name to a Wbem class name
                        pdhStatus = PdhiWbemGetObjectClassName (
                            pWbemServer,
                            pCounterPathElements->szObjectName,
                            &szTempObjectString[0],
                            dwSize,
                            &pWbemClass);
                        // add a colon path separator
                        lstrcatW(szTempPath, cszColon);
                    }
                    if (pdhStatus == ERROR_SUCCESS) {
                        //then add the string
                        lstrcatW(szTempPath, szTempObjectString);
                        dwCurSize += lstrlenW(szTempObjectString) + 1; // includes delimiter
                    }

                    if (bDisconnectServer) {
                        if (pdhStatus == ERROR_SUCCESS) {
                            pdhStatus = PdhiDisconnectWbemServer (pWbemServer);
                        } else {
                            // keep error code from function body
                            PdhiDisconnectWbemServer (pWbemServer);
                        }
                    }
                }
            } else {
                // no object name, so bad structure
                pdhStatus = PDH_CSTATUS_NO_OBJECT;
            }

        }

        // check for instance entries to add before adding the counter.
        if (pdhStatus == ERROR_SUCCESS) {
            if (pCounterPathElements->szInstanceName != NULL) {
                lstrcatW (szTempPath, cszLeftParen);
                dwCurSize += 1;
                if (pCounterPathElements->szParentInstance != NULL) {
                    lstrcatW (szTempPath, pCounterPathElements->szParentInstance);
                    lstrcatW (szTempPath, cszSlash);
                    dwCurSize += lstrlenW( pCounterPathElements->szParentInstance ) + 1;
                }
                lstrcatW (szTempPath, pCounterPathElements->szInstanceName);
                lstrcatW (szTempPath, cszRightParen);
                dwCurSize += lstrlenW( pCounterPathElements->szInstanceName ) + 1;
            } else {
                // this is OK
                assert (pCounterPathElements->szParentInstance == NULL);
                assert (pCounterPathElements->dwInstanceIndex == 0);
            }
        }

        // add counter name
        if (pdhStatus == ERROR_SUCCESS) {
            if (pCounterPathElements->szCounterName != NULL) {
                DWORD   dwSize;
                WCHAR   szTempCounterString[1024];

                dwSize = 1024;
                // then the input is different from the output
                // so convert from one to the other
                // and default name space since perf counters won't be
                // found elsewhere
                assert (pWbemServer != NULL);
                if (pdhStatus == ERROR_SUCCESS) {
                    // add a backslash path separator
                    lstrcatW(szTempPath, cszBackSlash);
                    if (dwFlags & PDH_PATH_WBEM_INPUT) {
                        // convert the WBEM Class to the display name
                        pdhStatus = PdhiWbemGetCounterDisplayName (
                            pWbemClass,
                            pCounterPathElements->szCounterName,
                            &szTempCounterString[0],
                            dwSize);
                        if (dwFlags & PDH_PATH_WBEM_RESULT) {
                            // just copy the string, but save
                            // the class pointer
                            lstrcpyW (szTempCounterString, pCounterPathElements->szCounterName);
                        } else {
                            // copy the retrieved string
                        }
                    } else {
                        // convert the display name to a Wbem class name
                        pdhStatus = PdhiWbemGetCounterPropertyName (
                            pWbemClass,
                            pCounterPathElements->szCounterName,
                            &szTempCounterString[0],
                            dwSize);
                    }
                    if (pdhStatus == ERROR_SUCCESS) {
                        //then add the string
                        lstrcatW(szTempPath, szTempCounterString);
                        dwCurSize += lstrlenW(szTempCounterString) + 1; // includes delimiter
                    }
                }
            } else {
                // no object name, so bad structure
                pdhStatus = PDH_CSTATUS_NO_COUNTER;
            }
        }

        assert (dwCurSize == (DWORD)lstrlenW(szTempPath));
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // copy path to the caller's buffer if it will fit
        assert (dwCurSize == (DWORD)lstrlenW(szTempPath));
        if (dwCurSize < *pcchBufferSize) {
            if (szFullPathBuffer != NULL) {
                lstrcpyW (szFullPathBuffer, szTempPath);
            }
        } else {
            if (szFullPathBuffer != NULL) {
                // the buffer passed in is too small
                pdhStatus = PDH_MORE_DATA;
            }
        }
        *pcchBufferSize = dwCurSize;
    }

    //if (pWbemClass != NULL) pWbemClass->Release();

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }
    if (szTempPath != NULL) G_FREE(szTempPath);

    return pdhStatus;
}

PDH_FUNCTION
PdhiEncodeWbemPathA (
    PDH_COUNTER_PATH_ELEMENTS_A *pCounterPathElements,
    LPSTR                       szFullPathBuffer,
    LPDWORD                     pcchBufferSize,
    LANGID                      LangId,
    DWORD                       dwFlags
)
{
    PDH_STATUS                  pdhStatus = ERROR_SUCCESS;
    LPWSTR                      wszNextString;
    LPWSTR                      wszReturnBuffer;
    PDH_COUNTER_PATH_ELEMENTS_W *pWideCounterPathElements;
    DWORD                       dwcchBufferSize;
    DWORD                       dwBuffSize;
    DWORD                       dwDest;

    // get required buffer size...
    dwBuffSize = sizeof (PDH_COUNTER_PATH_ELEMENTS_W);

    if (pCounterPathElements->szMachineName != NULL) {
        dwBuffSize += (lstrlenA(pCounterPathElements->szMachineName) + 1) * sizeof(WCHAR);
    }

    if (pCounterPathElements->szObjectName != NULL) {
        dwBuffSize += (lstrlenA(pCounterPathElements->szObjectName) + 1) * sizeof(WCHAR);
    }

    if (pCounterPathElements->szInstanceName != NULL) {
        dwBuffSize += (lstrlenA(pCounterPathElements->szInstanceName) + 1) * sizeof(WCHAR);
    }

    if (pCounterPathElements->szParentInstance != NULL) {
        dwBuffSize += (lstrlenA(pCounterPathElements->szParentInstance) + 1) * sizeof(WCHAR);
    }

    if (pCounterPathElements->szCounterName != NULL) {
        dwBuffSize += (lstrlenA(pCounterPathElements->szCounterName) + 1) * sizeof(WCHAR);
    }

    // add in room for the return buffer
    dwcchBufferSize  = * pcchBufferSize;
    dwBuffSize      += dwcchBufferSize * sizeof(WCHAR);

    pWideCounterPathElements = (PDH_COUNTER_PATH_ELEMENTS_W *)G_ALLOC(dwBuffSize);

    if (pWideCounterPathElements != NULL) {
        // populate the fields
        wszNextString = (LPWSTR)&pWideCounterPathElements[1];

        if (pCounterPathElements->szMachineName != NULL) {
            dwDest = MultiByteToWideChar(_getmbcp(),
                        0,
                        pCounterPathElements->szMachineName,
                        lstrlenA(pCounterPathElements->szMachineName),
                        wszNextString,
                        (lstrlenA(pCounterPathElements->szMachineName) + 1));
            if (dwDest > 0) {
                pWideCounterPathElements->szMachineName = wszNextString;
                wszNextString += dwDest + 1;
            }
            else {
                pWideCounterPathElements->szMachineName = NULL;
            }
        } else {
            pWideCounterPathElements->szMachineName = NULL;
        }

        if (pCounterPathElements->szObjectName != NULL) {
            pWideCounterPathElements->szObjectName = wszNextString;
            dwDest = MultiByteToWideChar(_getmbcp(),
                        0,
                        pCounterPathElements->szObjectName,
                        lstrlenA(pCounterPathElements->szObjectName),
                        wszNextString,
                        (lstrlenA(pCounterPathElements->szObjectName) + 1));
            if (dwDest > 0) {
                pWideCounterPathElements->szObjectName = wszNextString;
                wszNextString += dwDest + 1;
            }
            else {
                pWideCounterPathElements->szObjectName = NULL;
            }
        } else {
            pWideCounterPathElements->szObjectName = NULL;
        }

        if (pCounterPathElements->szInstanceName != NULL) {
            dwDest = MultiByteToWideChar(_getmbcp(),
                        0,
                        pCounterPathElements->szInstanceName,
                        lstrlenA(pCounterPathElements->szInstanceName),
                        wszNextString,
                        (lstrlenA(pCounterPathElements->szInstanceName) + 1));
            if (dwDest > 0) {
                pWideCounterPathElements->szInstanceName = wszNextString;
                wszNextString += dwDest + 1;
            }
            else {
                pWideCounterPathElements->szInstanceName = NULL;
            }
        } else {
            pWideCounterPathElements->szInstanceName = NULL;
        }

        if (pCounterPathElements->szParentInstance != NULL) {
            dwDest = MultiByteToWideChar(_getmbcp(),
                        0,
                        pCounterPathElements->szParentInstance,
                        lstrlenA(pCounterPathElements->szParentInstance),
                        wszNextString,
                        (lstrlenA(pCounterPathElements->szParentInstance) + 1));
            if (dwDest > 0) {
                pWideCounterPathElements->szParentInstance = wszNextString;
                wszNextString += dwDest + 1;
            }
            else {
                pWideCounterPathElements->szParentInstance = NULL;
            }
        } else {
            pWideCounterPathElements->szParentInstance = NULL;
        }

        if (pCounterPathElements->szCounterName != NULL) {
            dwDest = MultiByteToWideChar(_getmbcp(),
                        0,
                        pCounterPathElements->szCounterName,
                        lstrlenA(pCounterPathElements->szCounterName),
                        wszNextString,
                        (lstrlenA(pCounterPathElements->szCounterName) + 1));
            if (dwDest > 0) {
                pWideCounterPathElements->szCounterName = wszNextString;
                wszNextString += dwDest + 1;
            }
            else {
                pWideCounterPathElements->szCounterName = NULL;
            }
        } else {
            pWideCounterPathElements->szCounterName = NULL;
        }

        pWideCounterPathElements->dwInstanceIndex =
            pCounterPathElements->dwInstanceIndex;

        if (szFullPathBuffer != NULL) {
            wszReturnBuffer = wszNextString;
        } else {
            wszReturnBuffer = NULL;
        }

        // call wide function
        pdhStatus = PdhiEncodeWbemPathW (
            pWideCounterPathElements,
            wszReturnBuffer,
            & dwcchBufferSize,
            LangId,
            dwFlags);

        if ((pdhStatus == ERROR_SUCCESS) && (szFullPathBuffer != NULL)) {
            // convert the wide path back to ANSI
            pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                        wszReturnBuffer,
                        szFullPathBuffer,
                        pcchBufferSize);
        }

        G_FREE (pWideCounterPathElements);
    } else {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    return pdhStatus;

}

PDH_FUNCTION
PdhiDecodeWbemPathW (
    IN      LPCWSTR                     szFullPathBuffer,
    IN      PDH_COUNTER_PATH_ELEMENTS_W *pCounterPathElements,
    IN      LPDWORD                     pdwBufferSize,
    IN      LANGID                      LangId,
    IN      DWORD                       dwFlags
)
{
    PPDHI_COUNTER_PATH  pLocalCounterPath;
    PDH_STATUS          pdhStatus = ERROR_SUCCESS;
    DWORD               dwSize;
    LPWSTR              szString = NULL;
    WCHAR               wszTempBuffer[MAX_PATH];
    LPWSTR              szSrc = NULL;

    PPDHI_WBEM_SERVER_DEF   pThisServer = NULL;
    IWbemClassObject    *pThisClass = NULL;

    DBG_UNREFERENCED_PARAMETER (LangId);

    // CoInitialize() if we need to
    BOOL    fCoInitialized = PdhiCoInitialize();

     // allocate a temporary work buffer
    pLocalCounterPath = (PPDHI_COUNTER_PATH) G_ALLOC(
            sizeof(PDHI_COUNTER_PATH) + sizeof(WCHAR) * 2 *
                (  lstrlenW(szStaticLocalMachineName)
                 + lstrlenW(szFullPathBuffer) + 3));

    if (pLocalCounterPath != NULL) {
        dwSize = (DWORD)G_SIZE (pLocalCounterPath);
        assert (dwSize != NULL);

        if (pdhStatus == ERROR_SUCCESS) {
            // get WBEM server since we'll probably need it later
            if (ParseFullPathNameW (szFullPathBuffer,
                &dwSize, pLocalCounterPath,
                (dwFlags & PDH_PATH_WBEM_INPUT ? TRUE : FALSE))) {
                // parsed successfully so load into user's buffer
                if (*pdwBufferSize != 0) {
                    if (pCounterPathElements != NULL) {
                        // see if there's enough room
                        if (*pdwBufferSize >= dwSize) {
                            // there's room so copy / translate the data
                            szString = (LPWSTR)&pCounterPathElements[1];
                            if (pLocalCounterPath->szMachineName != NULL) {
                                pCounterPathElements->szMachineName = szString;
                                lstrcpyW (szString, pLocalCounterPath->szMachineName);
                                szString += lstrlenW (szString) + 1;
                                szString = (LPWSTR)ALIGN_ON_DWORD (szString);
                            } else {
                                pCounterPathElements->szMachineName = NULL;
                            }
                            dwSize = (DWORD)((LPBYTE)szString - (LPBYTE)pCounterPathElements);
                        }

                        // Now that we have the proper machine name,
                        // connect to the server if we need to
                        if (dwFlags != (PDH_PATH_WBEM_INPUT | PDH_PATH_WBEM_RESULT)) {
                            pdhStatus = PdhiConnectWbemServer (
                                pCounterPathElements->szMachineName, &pThisServer);
                        } else {
                            // this will just be a copy operation
                            pdhStatus = ERROR_SUCCESS;
                        }

                        if ( pdhStatus == ERROR_SUCCESS ) {

                            if (pLocalCounterPath->szObjectName != NULL) {
                                pCounterPathElements->szObjectName = szString;
                                if (dwFlags & PDH_PATH_WBEM_RESULT) {
                                    if (dwFlags & PDH_PATH_WBEM_INPUT) {
                                        // just copy
                                        szSrc = pLocalCounterPath->szObjectName;
                                    } else {
                                        // interpret the display name to a class name
                                        pdhStatus = PdhiWbemGetObjectClassName (
                                            pThisServer,
                                            pLocalCounterPath->szObjectName,
                                            wszTempBuffer,
                                            sizeof(wszTempBuffer) / sizeof(wszTempBuffer[0]),
                                            &pThisClass);
                                        if (pdhStatus == ERROR_SUCCESS) {
                                            szSrc = wszTempBuffer;
                                        } 
                                    }
                                } else {
                                    if (dwFlags & PDH_PATH_WBEM_INPUT) {
                                        // translate class name to a display name
                                        pdhStatus = PdhiWbemGetClassDisplayName (
                                            pThisServer, pLocalCounterPath->szObjectName,
                                            wszTempBuffer,
                                            sizeof(wszTempBuffer) / sizeof(wszTempBuffer[0]),
                                            &pThisClass);
                                        if (pdhStatus == ERROR_SUCCESS) {
                                            szSrc = wszTempBuffer;
                                        }
                                    } else {
                                        assert (dwFlags != 0); // this should be caught earlier
                                    }
                                }

                                if (pdhStatus == ERROR_SUCCESS) {
                                    dwSize += (lstrlenW(szSrc) +1) * sizeof(WCHAR);
                                    if (*pdwBufferSize >= dwSize) {
                                        lstrcpyW (szString, szSrc);
                                        szString += lstrlenW (szString) + 1;
                                        szString = (LPWSTR)ALIGN_ON_DWORD (szString);
                                        dwSize = (DWORD)((LPBYTE)szString - (LPBYTE)pCounterPathElements);
                                    } else {
                                        // not enough room
                                        pdhStatus = PDH_INSUFFICIENT_BUFFER;
                                    }
                                }
                            } else {
                                pCounterPathElements->szObjectName = NULL;
                            }

                            if (pdhStatus == ERROR_SUCCESS) {
                                if (pLocalCounterPath->szInstanceName != NULL) {
                                    pCounterPathElements->szInstanceName = szString;
                                    szSrc = pLocalCounterPath->szInstanceName;
                                    dwSize += (lstrlenW(szSrc) +1) * sizeof(WCHAR);
                                    if (*pdwBufferSize >= dwSize) {
                                        lstrcpyW (szString, szSrc);
                                        szString += lstrlenW (szString) + 1;
                                        szString = (LPWSTR)ALIGN_ON_DWORD (szString);
                                        dwSize = (DWORD)((LPBYTE)szString - (LPBYTE)pCounterPathElements);
                                    } else {
                                        // not enough room
                                        pdhStatus = PDH_INSUFFICIENT_BUFFER;
                                    }

                                    if (pLocalCounterPath->szParentName != NULL) {
                                        pCounterPathElements->szParentInstance = szString;
                                        szSrc = pLocalCounterPath->szParentName;
                                        dwSize += (lstrlenW(szSrc) +1) * sizeof(WCHAR);
                                        if (*pdwBufferSize >= dwSize) {
                                            lstrcpyW (szString, szSrc);
                                            szString += lstrlenW (szString) + 1;
                                            szString = (LPWSTR)ALIGN_ON_DWORD (szString);
                                            dwSize = (DWORD)((LPBYTE)szString - (LPBYTE)pCounterPathElements);
                                        } else {
                                            // not enough room
                                            pdhStatus = PDH_INSUFFICIENT_BUFFER;
                                        }
                                    } else {
                                        pCounterPathElements->szParentInstance = NULL;
                                    }

                                    pCounterPathElements->dwInstanceIndex =
                                        pLocalCounterPath->dwIndex;

                                } else {
                                    pCounterPathElements->szInstanceName = NULL;
                                    pCounterPathElements->szParentInstance = NULL;
                                    pCounterPathElements->dwInstanceIndex = (DWORD)-1;
                                }
                            }

                            if (pdhStatus == ERROR_SUCCESS) {
                                if (pLocalCounterPath->szCounterName != NULL) {
                                    pCounterPathElements->szCounterName = szString;
                                    if (dwFlags & PDH_PATH_WBEM_RESULT) {
                                        if (dwFlags & PDH_PATH_WBEM_INPUT) {
                                            // just copy
                                            szSrc = pLocalCounterPath->szCounterName;
                                        } else {
                                            // interpret the display name to a property name
                                            pdhStatus = PdhiWbemGetCounterPropertyName (
                                                pThisClass,
                                                pLocalCounterPath->szCounterName,
                                                wszTempBuffer,
                                                sizeof(wszTempBuffer) / sizeof(wszTempBuffer[0]));
                                            if (pdhStatus == ERROR_SUCCESS) {
                                                szSrc = wszTempBuffer;
                                            }
                                        }
                                    } else {
                                        if (dwFlags & PDH_PATH_WBEM_INPUT) {
                                            // translate class name to a display name
                                            pdhStatus = PdhiWbemGetCounterDisplayName (
                                                pThisClass, pLocalCounterPath->szCounterName,
                                                wszTempBuffer,
                                                sizeof(wszTempBuffer) / sizeof(wszTempBuffer[0]));
                                            if (pdhStatus == ERROR_SUCCESS) {
                                                szSrc = wszTempBuffer;
                                            }
                                        } else {
                                            assert (dwFlags != 0); // this should be caught earlier
                                        }
                                    }
                                    dwSize += (lstrlenW(szSrc) +1) * sizeof(WCHAR);
                                    if (*pdwBufferSize >= dwSize) {
                                        lstrcpyW (szString, szSrc);
                                        szString += lstrlenW (szString) + 1;
                                        szString = (LPWSTR)ALIGN_ON_DWORD (szString);
                                        dwSize = (DWORD)((LPBYTE)szString - (LPBYTE)pCounterPathElements);
                                    } else {
                                        // not enough room
                                        pdhStatus = PDH_INSUFFICIENT_BUFFER;
                                    }
                                } else {
                                    pCounterPathElements->szCounterName = NULL;
                                }
                            }
                        }   // If pdhStatus == ERROR_SUCCESS

                        if (pdhStatus == ERROR_SUCCESS) {
                            dwSize = (DWORD)((LPBYTE)szString - (LPBYTE)pCounterPathElements);

                            *pdwBufferSize = dwSize;
                        }
                    } else {
                        // a null buffer pointer was passed int
                        pdhStatus = PDH_INVALID_ARGUMENT;
                    }
                } else {
                    // this is just a size check so return size required
                    *pdwBufferSize = dwSize * 2; // doubled to insure room for path expansions
                    pdhStatus = ERROR_SUCCESS;
                }
            } else {
                // unable to read path
                pdhStatus = PDH_INVALID_PATH;
            }
            // release class object if used
            //if (pThisClass != NULL) pThisClass->Release();

            // Cleanup pThisServer if used
            if ( NULL != pThisServer )
            {
                if (pdhStatus == ERROR_SUCCESS) {
                    pdhStatus = PdhiDisconnectWbemServer (pThisServer);
                } else {
                    // don't trash the return status
                    PdhiDisconnectWbemServer (pThisServer);
                }
            }

        }
        G_FREE (pLocalCounterPath);
    } else {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }

    return pdhStatus;
}

PDH_FUNCTION
PdhiDecodeWbemPathA (
    IN      LPCSTR                      szFullPathBuffer,
    IN      PDH_COUNTER_PATH_ELEMENTS_A *pCounterPathElements,
    IN      LPDWORD                     pdwBufferSize,
    IN      LANGID                      LangId,
    IN      DWORD                       dwFlags
)
{
    PDH_STATUS  pdhStatus = ERROR_SUCCESS;
    LPWSTR      wszWidePath = NULL;
    PDH_COUNTER_PATH_ELEMENTS_W     *pWideElements = NULL;
    DWORD       dwSize;
    DWORD       dwDest = 0;
    LONG        lSizeRemaining;
    LPSTR       szNextString;

    wszWidePath = (LPWSTR)G_ALLOC((lstrlenA(szFullPathBuffer) + 1) * sizeof(WCHAR));

    if (wszWidePath == NULL) {
        pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // compute size of temp element buffer
        lSizeRemaining = * pdwBufferSize - sizeof(PDH_COUNTER_PATH_ELEMENTS_A);
        dwSize = * pdwBufferSize - sizeof(PDH_COUNTER_PATH_ELEMENTS_A);
        // dwSize now has the size of the buffer AFTER the structure so
        // adjust this for the longer char length to make it a fair comparison
        dwSize *= sizeof(WCHAR)/sizeof(CHAR);
        // and add back in the structure
        dwSize += sizeof(PDH_COUNTER_PATH_ELEMENTS_W);

        if (pCounterPathElements != NULL) {
            pWideElements = (PDH_COUNTER_PATH_ELEMENTS_W *) G_ALLOC(dwSize);
            if (pWideElements == NULL) {
                pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
            }
        } else {
            pWideElements = NULL;
            pdhStatus = ERROR_SUCCESS;
        }
    }

    if (pdhStatus == ERROR_SUCCESS) {
        // convert path to Wide
        MultiByteToWideChar(_getmbcp(),
                    0,
                    szFullPathBuffer,
                    lstrlenA(szFullPathBuffer),
                    wszWidePath,
                    lstrlenA(szFullPathBuffer) + 1);
        pdhStatus = PdhiDecodeWbemPathW (
                    wszWidePath,
                    pWideElements,
                    & dwSize,
                    LangId,
                    dwFlags);

        if (pdhStatus == ERROR_SUCCESS) {
            if (pCounterPathElements != NULL) {
                // populate the fields of the caller's buffer
                szNextString = (LPSTR)&pCounterPathElements[1];

                if (   pWideElements->szMachineName != NULL
                    && lSizeRemaining > 0) {
                    dwDest    = lSizeRemaining;
                    pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                pWideElements->szMachineName,
                                szNextString,
                                & dwDest);
                    if (pdhStatus == ERROR_SUCCESS) {
                        pCounterPathElements->szMachineName = szNextString;
                        szNextString += dwDest + 1;
                    }
                    else {
                        pCounterPathElements->szMachineName = NULL;
                    }
                    lSizeRemaining -= dwDest + 1;
                } else {
                    pCounterPathElements->szMachineName = NULL;
                }

                if (   pWideElements->szObjectName != NULL
                    && lSizeRemaining > 0) {
                    dwDest    = lSizeRemaining;
                    pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                pWideElements->szObjectName,
                                szNextString,
                                & dwDest);
                    if (pdhStatus == ERROR_SUCCESS) {
                        pCounterPathElements->szObjectName = szNextString;
                        szNextString += dwDest + 1;
                    }
                    else {
                        pCounterPathElements->szObjectName = NULL;
                    }
                    lSizeRemaining -= dwDest + 1;
                } else {
                    pCounterPathElements->szObjectName = NULL;
                }

                if (   pWideElements->szInstanceName != NULL
                    && lSizeRemaining > 0) {
                    dwDest    = lSizeRemaining;
                    pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                pWideElements->szInstanceName,
                                szNextString,
                                & dwDest);
                    if (pdhStatus == ERROR_SUCCESS) {
                        pCounterPathElements->szInstanceName = szNextString;
                        szNextString += dwDest + 1;
                    }
                    else {
                        pCounterPathElements->szInstanceName = NULL;
                    }
                    lSizeRemaining -= dwDest + 1;
                } else {
                    pCounterPathElements->szInstanceName = NULL;
                }

                if (   pWideElements->szParentInstance != NULL
                    && lSizeRemaining > 0) {
                    dwDest    = lSizeRemaining;
                    pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                pWideElements->szParentInstance,
                                szNextString,
                                & dwDest);
                    if (pdhStatus == ERROR_SUCCESS) {
                        pCounterPathElements->szParentInstance = szNextString;
                        szNextString += dwDest + 1;
                    }
                    else {
                        pCounterPathElements->szParentInstance = NULL;
                    }
                    lSizeRemaining -= dwDest + 1;
                } else {
                    pCounterPathElements->szParentInstance = NULL;
                }

                if (   pWideElements->szCounterName != NULL
                    && lSizeRemaining > 0) {
                    dwDest    = lSizeRemaining;
                    pdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
                                pWideElements->szObjectName,
                                szNextString,
                                & dwDest);
                    if (pdhStatus == ERROR_SUCCESS) {
                        pCounterPathElements->szCounterName = szNextString;
                        szNextString   += dwDest + 1;
                    }
                    else {
                        pCounterPathElements->szCounterName = NULL;
                    }
                    lSizeRemaining -= dwDest + 1;
                } else {
                    pCounterPathElements->szCounterName = NULL;
                }

                pCounterPathElements->dwInstanceIndex =
                    pWideElements->dwInstanceIndex;

                *pdwBufferSize = (DWORD)((LPBYTE)szNextString - (LPBYTE)pCounterPathElements);
            } else {
                // just return the size required adjusted for wide/ansi characters
                *pdwBufferSize = sizeof(PDH_COUNTER_PATH_ELEMENTS_A);
                dwSize -= sizeof(PDH_COUNTER_PATH_ELEMENTS_W);
                dwSize /= sizeof(WCHAR)/sizeof(CHAR);
                *pdwBufferSize += dwSize;
            }
        } else {
            // call to wide function failed so just return error
        }
    } else {
        // memory allocation failed so return error
    }

    if (pWideElements != NULL) G_FREE(pWideElements);
    if (wszWidePath != NULL) G_FREE(wszWidePath);

    return pdhStatus;
}

BOOL
WbemInitCounter (
    IN      PPDHI_COUNTER pCounter
)
/*++

Routine Description:

    Initialized the counter data structure by:
        Allocating the memory block to contain the counter structure
            and all the associated data fields. If this allocation
            is successful, then the fields are initialized by
            verifying the counter is valid.

Arguments:

    IN      PPDHI_COUNTER pCounter
        pointer of the counter to initialize using the system data

Return Value:

    TRUE if the counter was successfully initialized
    FALSE if a problem was encountered

    In either case, the CStatus field of the structure is updated to
    indicate the status of the operation.

--*/
{
    DWORD               dwResult;
    PDH_STATUS          pdhStatus = ERROR_SUCCESS;
    PPDHI_WBEM_SERVER_DEF   pWbemServer = NULL;
    DWORD               dwLastError = ERROR_SUCCESS;
    HRESULT             hRes = S_OK;
    VARIANT             vCountertype;
    WCHAR               szBasePropertyName[MAX_PATH];
    WCHAR               szFreqPropertyName[MAX_PATH];
    WCHAR               szWbemItemPath[MAX_PATH];
    ULONGLONG           llValue;
    LONG                lOffset;

    PPDH_COUNTER_PATH_ELEMENTS_W    pPathElem = NULL;
    BOOL                            bReturn = TRUE;
    DWORD                           dwBufferSize = 0;
    BSTR                            bsPropName = NULL;
    BSTR                            bsCountertype = NULL;
    IWbemQualifierSet               *pQualSet = NULL;
    PPDHI_COUNTER                   pCounterInList = NULL;
    PPDHI_COUNTER_PATH              pPdhiCtrPath = NULL;
    BOOL                bMatchFound;
    DWORD               bDisconnectServer = FALSE;

    // CoInitialize() if we need to
    BOOL    fCoInitialized = PdhiCoInitialize();

    VariantInit (&vCountertype);

    pCounter->dwFlags |= PDHIC_WBEM_COUNTER; // make sure WBEM flag is set

    // make sure the query has a refresher started already
    if (pCounter->pOwner->pRefresher == NULL) {
        // it hasn't been started so start now
        dwResult = CoCreateRefresher( &pCounter->pOwner->pRefresher );
        if ((dwResult != S_OK) || (pCounter->pOwner->pRefresher ==  NULL)) {
            pCounter->pOwner->pRefresher = NULL;
            dwLastError = PDH_WBEM_ERROR;
            bReturn = FALSE;
        } else {
            // open config interface
            dwResult = pCounter->pOwner->pRefresher->QueryInterface (
                IID_IWbemConfigureRefresher,
                (LPVOID *)&pCounter->pOwner->pRefresherCfg);
            if (dwResult != S_OK) {
                pCounter->pOwner->pRefresherCfg = NULL;
                pCounter->pOwner->pRefresher->Release();
                pCounter->pOwner->pRefresher = NULL;
                dwLastError = PDH_WBEM_ERROR;
                bReturn = FALSE;
            }
        }
    }

    if (bReturn) {
        // so far so good, now figure out the WBEM path to add it to the
        // refresher
        dwBufferSize = lstrlenW(pCounter->szFullName) * sizeof(WCHAR) * 10;
        dwBufferSize += sizeof (PDH_COUNTER_PATH_ELEMENTS_W);

        pPathElem = (PPDH_COUNTER_PATH_ELEMENTS_W) G_ALLOC (dwBufferSize);
        // the path is display names, so convert to WBEM class names first

        if (pPathElem == NULL) {
            dwLastError = PDH_MEMORY_ALLOCATION_FAILURE;
            bReturn = FALSE;
        } else {
            pdhStatus = PdhiDecodeWbemPathW (
                pCounter->szFullName,
                pPathElem,
                &dwBufferSize,
                pCounter->pOwner->LangID,
                PDH_PATH_WBEM_RESULT);
            if (pdhStatus == ERROR_SUCCESS) {
                // continue
            } else {
                dwLastError = PDH_INVALID_PATH;
                bReturn = FALSE;
            }
        }
    }

    if (bReturn) {
        dwBufferSize *= 8; // just to be safe
        pPdhiCtrPath = (PPDHI_COUNTER_PATH) G_ALLOC (dwBufferSize);
        if (pPdhiCtrPath == NULL) {
            dwLastError = PDH_MEMORY_ALLOCATION_FAILURE;
            bReturn = FALSE;
        } else {
            // break path into display elements
            bReturn = ParseFullPathNameW (
                pCounter->szFullName,
                &dwBufferSize,
                pPdhiCtrPath,
                FALSE);
            if (bReturn) {
                // realloc to use only the memory needed
                pCounter->pCounterPath = (PPDHI_COUNTER_PATH)
                    G_REALLOC (pPdhiCtrPath, dwBufferSize);
                if ((pPdhiCtrPath != pCounter->pCounterPath) &&
                    (pCounter->pCounterPath != NULL)){
                    // the memory block moved so
                    // correct addresses inside structure
                    lOffset = (LONG)((ULONG_PTR)pCounter->pCounterPath -
                                     (ULONG_PTR)pPdhiCtrPath);
                    if (pCounter->pCounterPath->szMachineName) {
                        pCounter->pCounterPath->szMachineName = (LPWSTR)(
                            (LPBYTE)pCounter->pCounterPath->szMachineName + lOffset);
                    }
                    if (pCounter->pCounterPath->szObjectName) {
                        pCounter->pCounterPath->szObjectName = (LPWSTR)(
                            (LPBYTE)pCounter->pCounterPath->szObjectName + lOffset);
                    }
                    if (pCounter->pCounterPath->szInstanceName) {
                        pCounter->pCounterPath->szInstanceName = (LPWSTR)(
                            (LPBYTE)pCounter->pCounterPath->szInstanceName + lOffset);
                    }
                    if (pCounter->pCounterPath->szParentName) {
                        pCounter->pCounterPath->szParentName = (LPWSTR)(
                            (LPBYTE)pCounter->pCounterPath->szParentName + lOffset);
                    }
                    if (pCounter->pCounterPath->szCounterName) {
                        pCounter->pCounterPath->szCounterName = (LPWSTR)(
                            (LPBYTE)pCounter->pCounterPath->szCounterName + lOffset);
                    }
                }
            } else {
                // free the buffer
                G_FREE (pPdhiCtrPath);
                dwLastError = PDH_WBEM_ERROR;
            }
        }
    }

    // connect to the WBEM Server on that machine
    if (bReturn) {
        pdhStatus = PdhiConnectWbemServer (
            pCounter->pCounterPath->szMachineName,
            &pWbemServer);
        if (pdhStatus != ERROR_SUCCESS) {
            dwLastError = pdhStatus;
            bReturn = FALSE;
        } else {
            bDisconnectServer = TRUE;
        }
    }

    if (bReturn) {
        // make WBEM Instance path out of path elements
        pdhStatus = PdhiMakeWbemInstancePath (
            pPathElem,
            szWbemItemPath,
            TRUE);

        // check for an object/class of this type that has already been added
        // walk down counter list to find a matching:
        //  machine\namespace
        //  object
        //  instance name
        if (pdhStatus != ERROR_SUCCESS) {
            dwLastError = pdhStatus;
            bReturn = FALSE;
        }
    }

    if (bReturn) {
        assert (pCounter->pWbemObject == NULL);
        assert (pCounter->lWbemRefreshId == 0);

        pCounterInList = pCounter->pOwner->pCounterListHead;
        if (pCounterInList == NULL) {
            // then there are no entries to search so continue
        } else {
            do {
                // check for matching machine name
                bMatchFound = FALSE;
                if (lstrcmpiW(pCounterInList->pCounterPath->szMachineName,
                    pCounter->pCounterPath->szMachineName) == 0) {
                    // then the machine name matches
                    if (lstrcmpiW (pCounterInList->pCounterPath->szObjectName,
                        pCounter->pCounterPath->szObjectName) == 0) {
                        // then the object name matches
                        // see if the instance matches
                        if (lstrcmpiW (pCounterInList->pCounterPath->szInstanceName,
                            pCounter->pCounterPath->szInstanceName) == 0) {
                            if (pCounter->pCounterPath->szParentName != 0) {
                                if (lstrcmpiW (pCounterInList->pCounterPath->szParentName,
                                    pCounter->pCounterPath->szParentName) == 0) {
                                    // then this is a match
                                    bMatchFound = TRUE;
                                } else {
                                    // not a match
                                }
                            } else {
                                // this is a match
                                bMatchFound = TRUE;
                            }

                            if (bMatchFound) {
                                if ((pCounter->pCounterPath->szInstanceName != NULL) &&
                                    (*pCounter->pCounterPath->szInstanceName == SPLAT_L)) {
                                    // then this is a Wild Card or multiple instance path
                                    // see if an enumerator for this object has already been created
                                    // if so, then AddRef it
                                    if (pCounterInList->pWbemEnum != NULL) {
                                        pCounter->pWbemObject = pCounterInList->pWbemObject;
                                        pCounter->pWbemEnum = pCounterInList->pWbemEnum;
                                        // bump the ref counts on this object so it
                                        //  doesn't disapper from us
                                        pCounter->pWbemObject->AddRef();
                                        pCounter->pWbemEnum->AddRef();
                                        pCounter->lWbemEnumId = pCounterInList->lWbemEnumId;
                                        pCounter->dwFlags |= PDHIC_MULTI_INSTANCE;
                                    }
                                    // and exit loop
                                    hRes = S_OK;
                                    break;
                                } else {
                                    // then it's a regular instance the instance name matches
                                    // so get the Object pointer
                                    pCounter->pWbemObject = pCounterInList->pWbemObject;
                                    pCounter->pWbemAccess = pCounterInList->pWbemAccess;
                                    // bump the ref counts on this object so it
                                    //  doesn't disapper from us
                                    pCounter->pWbemObject->AddRef();
                                    pCounter->pWbemAccess->AddRef();
                                    pCounter->lWbemRefreshId = pCounterInList->lWbemRefreshId;
                                    // and exit loop
                                    hRes = S_OK;
                                    break;
                                }
                            } else {
                                // no match so go to next one
                            }
                        } else {
                            // no match so go to next one
                        }
                    } else {
                        // no match so go to next one
                    }
                } else {
                    // no match so go to next counter
                }
                pCounterInList = pCounterInList->next.flink;
            } while (pCounterInList != pCounter->pOwner->pCounterListHead);
        }

        bDontRefresh = TRUE;

        // determine if we should and an object or an enumerator
        if ((pCounter->pCounterPath->szInstanceName != NULL) &&
            (*pCounter->pCounterPath->szInstanceName == SPLAT_L)) {
            // then this is an enum type so see if there's already one assigned
            // if not, then create one
            if (pCounter->pWbemEnum == NULL) {
                if (pCounter->pOwner->pRefresherCfg != NULL) {
                    hRes = pCounter->pOwner->pRefresherCfg->AddEnum(
                        pWbemServer->pSvc,
                        pPathElem->szObjectName,
                        WBEM_FLAG_USE_AMENDED_QUALIFIERS, 0,
                        &pCounter->pWbemEnum,
                        &pCounter->lWbemEnumId);
                } else {
                    hRes = WBEM_E_INITIALIZATION_FAILURE;
                }

                if (hRes != S_OK) {
                    bReturn = FALSE;
                    dwLastError = PDH_WBEM_ERROR;
                } else {
                    pdhStatus = PdhiWbemGetClassObjectByName (
                        pWbemServer,
                        pPathElem->szObjectName,
                        &pCounter->pWbemObject);
                }
                // set multi instance flag
                pCounter->dwFlags |= PDHIC_MULTI_INSTANCE;
            } else {
                // we must have copied another one so continue
            }

        } else {
            // this is a single counter
            if (pCounter->pWbemObject == NULL) {
                // and it hasn't been added yet, so just add one object
                if (pCounter->pOwner->pRefresherCfg != NULL) {
                    hRes = pCounter->pOwner->pRefresherCfg->AddObjectByPath (
                        pWbemServer->pSvc,
                        szWbemItemPath,
                        WBEM_FLAG_USE_AMENDED_QUALIFIERS, 0,
                        &pCounter->pWbemObject,
                        &pCounter->lWbemRefreshId);
                } else {
                    hRes = WBEM_E_INITIALIZATION_FAILURE;
                }

                if (hRes != S_OK) {
                    bReturn = FALSE;
                    dwLastError = PDH_WBEM_ERROR;
                }
            } else {
                // it must have been copied from another
            }
        }

        if (hRes == S_OK) {
            // get handles for subsequent data collection from this object
            hRes = pCounter->pWbemObject->QueryInterface (IID_IWbemObjectAccess,
                (LPVOID *)&pCounter->pWbemAccess);
            if (hRes == S_OK) {
                if (!PdhiIsSingletonClass (pCounter->pWbemObject)) {
                    CIMTYPE cimType = 0;
                    bsPropName = SysAllocString(cszName);
                    if (bsPropName) {
                        // get handle to the name property for this counter
                        hRes = pCounter->pWbemAccess->GetPropertyHandle (
                            bsPropName, &cimType,
                            &pCounter->lNameHandle);
                        if (hRes != S_OK) {
                            dwLastError = PDH_WBEM_ERROR;
                        }
                        assert (cimType == CIM_STRING);
                    } else {
                        dwLastError = PDH_MEMORY_ALLOCATION_FAILURE;
                        hRes = WBEM_E_OUT_OF_MEMORY;
                    }
                } else {
                    pCounter->lNameHandle = -1;
                }
                if (hRes == S_OK) {
                    // get handle to the data property for this counter
                    hRes = pCounter->pWbemAccess->GetPropertyHandle (
                        pPathElem->szCounterName, &pCounter->lNumItemType,
                        &pCounter->lNumItemHandle);
                    assert (hRes == S_OK);

                    // get counter type field
                    // first get the property qualifiers
                    PdhiSysFreeString (&bsPropName);
                    bsPropName = SysAllocString (pPathElem->szCounterName);
                    if (bsPropName) {
                        hRes = pCounter->pWbemObject->GetPropertyQualifierSet (
                            bsPropName, &pQualSet);
                    } else {
                        hRes = WBEM_E_OUT_OF_MEMORY;
                    }

                    if (hRes == WBEM_NO_ERROR) {
                        // now get the specific value
                        VariantClear (&vCountertype);
                        bsCountertype = SysAllocString (cszCountertype);
                        if (bsCountertype) {
                            hRes = pQualSet->Get (bsCountertype, 0, &vCountertype, NULL);
                            if (hRes == WBEM_NO_ERROR) {
                                pCounter->plCounterInfo.dwCounterType = (DWORD)V_I4(&vCountertype);
                            } else {
                                pCounter->plCounterInfo.dwCounterType = 0;
                            }
                            PdhiSysFreeString (&bsCountertype);
                        } else {
                            hRes = WBEM_E_OUT_OF_MEMORY;
                        }


                        if (hRes == WBEM_NO_ERROR) {
 
                            // if this is a fraction counter that has a "base" value
                            // then look it up by appending the "base" string to the
                            // property name

                            if ((pCounter->plCounterInfo.dwCounterType == PERF_SAMPLE_FRACTION) ||
                                (pCounter->plCounterInfo.dwCounterType == PERF_AVERAGE_TIMER)   ||
                                (pCounter->plCounterInfo.dwCounterType == PERF_AVERAGE_BULK)    ||
                                (pCounter->plCounterInfo.dwCounterType == PERF_LARGE_RAW_FRACTION) ||
                                (pCounter->plCounterInfo.dwCounterType == PERF_RAW_FRACTION)) {

                                // make sure we have room for the "_Base" string
                                assert (lstrlenW(pPathElem->szCounterName) < (MAX_PATH - 6));
                                lstrcpyW (szBasePropertyName, pPathElem->szCounterName);
                                lstrcatW (szBasePropertyName, cszBaseSuffix);

                                // get the handle to the denominator
                                hRes = pCounter->pWbemAccess->GetPropertyHandle (
                                    szBasePropertyName, &pCounter->lDenItemType,
                                    &pCounter->lDenItemHandle);
                                assert (hRes == S_OK);

                            } else {
                                // the denominator is a time field
                                if ((pCounter->plCounterInfo.dwCounterType & PERF_TIMER_FIELD) == PERF_TIMER_TICK) {
                                    // use the system perf time timestamp as the denominator
                                    lstrcpyW (szBasePropertyName, cszTimestampPerfTime);
                                    lstrcpyW (szFreqPropertyName, cszFrequencyPerfTime);
                                } else if ((pCounter->plCounterInfo.dwCounterType & PERF_TIMER_FIELD) == PERF_TIMER_100NS) {
                                    lstrcpyW (szBasePropertyName, cszTimestampSys100Ns);
                                    lstrcpyW (szFreqPropertyName, cszFrequencySys100Ns);
                                } else if ((pCounter->plCounterInfo.dwCounterType & PERF_TIMER_FIELD) == PERF_OBJECT_TIMER) {
                                    lstrcpyW (szBasePropertyName, cszTimestampObject);
                                    lstrcpyW (szFreqPropertyName, cszFrequencyObject);
                                } else {
                                    assert (FALSE); // this should never happen
                                }

                                // get the handle to the denominator
                                hRes = pCounter->pWbemAccess->GetPropertyHandle (
                                    szBasePropertyName, &pCounter->lDenItemType,
                                    &pCounter->lDenItemHandle);
                                assert (hRes == S_OK);

                                // get the handle to the frequency
                                hRes = pCounter->pWbemAccess->GetPropertyHandle (
                                    szFreqPropertyName, &pCounter->lFreqItemType,
                                    &pCounter->lFreqItemHandle);
                                assert (hRes == S_OK);
                            }

                            // get the default scale value of this counter
                            VariantClear (&vCountertype);
                            PdhiSysFreeString (&bsCountertype);
                            bsCountertype = SysAllocString (cszDefaultscale);
                            if (bsCountertype) {
                                hRes = pQualSet->Get (bsCountertype, 0, &vCountertype, NULL);
                                if (hRes == WBEM_NO_ERROR) {
                                    pCounter->lScale = 0;
                                    pCounter->plCounterInfo.lDefaultScale = (DWORD)V_I4(&vCountertype);
                                } else {
                                    pCounter->plCounterInfo.lDefaultScale = 0;
                                    pCounter->lScale = 0;
                                }

                                // this may not be initialized but we try anyway
                                if ((pCounter->lFreqItemType == VT_I8) ||
                                    (pCounter->lFreqItemType == VT_UI8)) {
                                    pCounter->pWbemAccess->ReadQWORD (
                                        pCounter->lFreqItemHandle, &llValue);
                                } else {
                                    llValue = 0;
                                }
                                // the timebase is a 64 bit integer
                                pCounter->TimeBase = llValue;
                            } else {
                                hRes = WBEM_E_OUT_OF_MEMORY;
                            }
                        }
                        PdhiSysFreeString (&bsCountertype);
                        pQualSet->Release();
                    } else {
                        if (hRes == WBEM_E_OUT_OF_MEMORY) {
                            dwLastError = PDH_MEMORY_ALLOCATION_FAILURE;
                        } else {
                            dwLastError = PDH_WBEM_ERROR;
                        }
                        bReturn = FALSE;
                    }
                } // else an error has ocurred
                PdhiSysFreeString (&bsPropName);
            } else {
                dwLastError = PDH_WBEM_ERROR;
                bReturn = FALSE;
            }
        } else {
            dwLastError = PDH_WBEM_ERROR;
            bReturn = FALSE;
        }

        if (bReturn) {
            // clear the not init'd flag to say it's ok to use now
            pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
        }

        bDontRefresh = FALSE;
    }

    if (bReturn) {
        if (!AssignCalcFunction (
            pCounter->plCounterInfo.dwCounterType,
            &pCounter->CalcFunc,
            &pCounter->StatFunc)) {
            dwLastError = PDH_FUNCTION_NOT_FOUND;
            bReturn = FALSE;
        }
    }

    if (pPathElem != NULL) G_FREE(pPathElem);
    VariantClear (&vCountertype);

    if (bDisconnectServer) {
        if (pdhStatus == ERROR_SUCCESS) {
            pdhStatus = PdhiDisconnectWbemServer (pWbemServer);
        } else {
            // keep error code from function body
            PdhiDisconnectWbemServer (pWbemServer);
        }
    }

    if (!bReturn) SetLastError (dwLastError);

    // CoUninitialize if necessary
    if ( fCoInitialized )
    {
        PdhiCoUninitialize();
    }

    return bReturn;
}

BOOL
UpdateWbemCounterValue (
    IN      PPDHI_COUNTER   pCounter,
    IN      FILETIME        *pTimeStamp
)
{
    DWORD   LocalCStatus = 0;
    DWORD   LocalCType  = 0;
    ULONGLONG   llValue;
    DWORD       dwValue;

    BOOL    bReturn  = FALSE;

    // move current value to last value buffer
    pCounter->LastValue = pCounter->ThisValue;

    // and clear the old value
    pCounter->ThisValue.MultiCount = 1;
    pCounter->ThisValue.FirstValue =
        pCounter->ThisValue.SecondValue = 0;
    pCounter->ThisValue.TimeStamp = *pTimeStamp;

    // get the counter's machine status first. There's no point in
    // contuning if the machine is offline

    // UpdateWbemCounterValue() will be called only if WBEM refresher succeeds
    // in GetQueryWbemData(); that is, all remote machines should be on-line

    LocalCStatus = ERROR_SUCCESS;

    if (IsSuccessSeverity(LocalCStatus)) {
        // get the pointer to the counter data
        LocalCType = pCounter->plCounterInfo.dwCounterType;
        switch (LocalCType) {
            //
            // these counter types are loaded as:
            //      Numerator = Counter data from perf data block
            //      Denominator = Perf Time from perf data block
            //      (the time base is the PerfFreq)
            //
            case PERF_COUNTER_COUNTER:
            case PERF_COUNTER_QUEUELEN_TYPE:
            case PERF_SAMPLE_COUNTER:
                // this should be a DWORD counter
                assert ((pCounter->lNumItemType == VT_I4) ||
                        (pCounter->lNumItemType == VT_UI4));
                pCounter->pWbemAccess->ReadDWORD (
                    pCounter->lNumItemHandle, &dwValue);
                pCounter->ThisValue.FirstValue = (LONGLONG)(dwValue);

                assert ((pCounter->lDenItemType == VT_I8) ||
                        (pCounter->lDenItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lDenItemHandle, &llValue);
                // the denominator should be a 64-bit timestamp
                pCounter->ThisValue.SecondValue = llValue;

                // look up the timebase freq if necessary
                if (pCounter->TimeBase == 0) {
                    assert ((pCounter->lFreqItemType == VT_I8) ||
                            (pCounter->lFreqItemType == VT_UI8));
                    pCounter->pWbemAccess->ReadQWORD (
                        pCounter->lFreqItemHandle, &llValue);
                    // the timebase is a 64 bit integer
                    pCounter->TimeBase = llValue;
                }

                break;

            case PERF_ELAPSED_TIME:
            case PERF_100NSEC_TIMER:
            case PERF_100NSEC_TIMER_INV:
            case PERF_COUNTER_TIMER:
            case PERF_COUNTER_TIMER_INV:
            case PERF_COUNTER_BULK_COUNT:
            case PERF_COUNTER_MULTI_TIMER:
            case PERF_COUNTER_MULTI_TIMER_INV:
            case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
            case PERF_OBJ_TIME_TIMER:
            case PERF_COUNTER_100NS_QUEUELEN_TYPE:
            case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
            case PERF_PRECISION_SYSTEM_TIMER:
            case PERF_PRECISION_100NS_TIMER:
            case PERF_PRECISION_OBJECT_TIMER:
                // this should be a QWORD counter
                assert ((pCounter->lNumItemType == VT_I8) ||
                        (pCounter->lNumItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lNumItemHandle, &llValue);
                pCounter->ThisValue.FirstValue = (LONGLONG)(llValue);

                assert ((pCounter->lDenItemType == VT_I8) ||
                        (pCounter->lDenItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lDenItemHandle, &llValue);
                // the denominator should be a 64-bit timestamp
                pCounter->ThisValue.SecondValue = llValue;

                // look up the timebase freq if necessary
                if (pCounter->TimeBase == 0) {
                    assert ((pCounter->lFreqItemType == VT_I8) ||
                            (pCounter->lFreqItemType == VT_UI8));
                    pCounter->pWbemAccess->ReadQWORD (
                        pCounter->lFreqItemHandle, &llValue);
                    // the timebase is a 64 bit integer
                    pCounter->TimeBase = llValue;
                }

                break;
            //
            //  These counters do not use any time reference
            //
            case PERF_COUNTER_RAWCOUNT:
            case PERF_COUNTER_RAWCOUNT_HEX:
            case PERF_COUNTER_DELTA:
                // this should be a DWORD counter
                assert ((pCounter->lNumItemType == VT_I4) ||
                        (pCounter->lNumItemType == VT_UI4));
                pCounter->pWbemAccess->ReadDWORD (
                    pCounter->lNumItemHandle, &dwValue);
                pCounter->ThisValue.FirstValue = (LONGLONG)(dwValue);
                pCounter->ThisValue.SecondValue = 0;
                break;

            case PERF_COUNTER_LARGE_RAWCOUNT:
            case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
            case PERF_COUNTER_LARGE_DELTA:
                // this should be a DWORD counter
                assert ((pCounter->lNumItemType == VT_I8) ||
                        (pCounter->lNumItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lNumItemHandle, &llValue);
                pCounter->ThisValue.FirstValue = (LONGLONG)(llValue);
                pCounter->ThisValue.SecondValue = 0;
                break;

            //
            //  These counters use two data points, the one pointed to by
            //  pData and the one immediately after
            //
            case PERF_SAMPLE_FRACTION:
            case PERF_RAW_FRACTION:
                // this should be a DWORD counter
                assert ((pCounter->lNumItemType == VT_I4) ||
                        (pCounter->lNumItemType == VT_UI4));
                pCounter->pWbemAccess->ReadDWORD (
                    pCounter->lNumItemHandle, &dwValue);
                pCounter->ThisValue.FirstValue = (LONGLONG)dwValue;

                assert ((pCounter->lDenItemType == VT_I4) ||
                        (pCounter->lDenItemType == VT_UI4));
                pCounter->pWbemAccess->ReadDWORD (
                    pCounter->lDenItemHandle, &dwValue);
                // the denominator should be a 32-bit value
                pCounter->ThisValue.SecondValue = (LONGLONG)dwValue;
                break;

            case PERF_LARGE_RAW_FRACTION:
                // this should be a DWORD counter
                assert ((pCounter->lNumItemType == VT_I8) ||
                        (pCounter->lNumItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lNumItemHandle, & llValue);
                pCounter->ThisValue.FirstValue = (LONGLONG) llValue;

                assert ((pCounter->lDenItemType == VT_I8) ||
                        (pCounter->lDenItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lDenItemHandle, & llValue);
                // the denominator should be a 32-bit value
                pCounter->ThisValue.SecondValue = (LONGLONG) llValue;
            break;

            case PERF_AVERAGE_TIMER:
            case PERF_AVERAGE_BULK:
                // counter (numerator) is a LONGLONG, while the
                // denominator is just a DWORD
                // this should be a DWORD counter
                assert ((pCounter->lNumItemType == VT_I8) ||
                        (pCounter->lNumItemType == VT_UI8));
                pCounter->pWbemAccess->ReadQWORD (
                    pCounter->lNumItemHandle, &llValue);
                pCounter->ThisValue.FirstValue = (LONGLONG)llValue;

                assert ((pCounter->lDenItemType == VT_I4) ||
                        (pCounter->lDenItemType == VT_UI4));
                pCounter->pWbemAccess->ReadDWORD (
                    pCounter->lDenItemHandle, &dwValue);
                // the denominator should be a 32-bit value
                pCounter->ThisValue.SecondValue = (LONGLONG)dwValue;

                // look up the timebase freq if necessary
                if (pCounter->TimeBase == 0) {
                    assert ((pCounter->lFreqItemType == VT_I8) ||
                            (pCounter->lFreqItemType == VT_UI8));
                    pCounter->pWbemAccess->ReadQWORD (
                        pCounter->lFreqItemHandle, &llValue);
                    // the timebase is a 64 bit integer
                    pCounter->TimeBase = llValue;
                }
                break;
            //
            //  These counters are used as the part of another counter
            //  and as such should not be used, but in case they are
            //  they'll be handled here.
            //
            case PERF_SAMPLE_BASE:
            case PERF_AVERAGE_BASE:
            case PERF_COUNTER_MULTI_BASE:
            case PERF_RAW_BASE:
            case PERF_LARGE_RAW_BASE:
                pCounter->ThisValue.FirstValue = 0;
                pCounter->ThisValue.SecondValue = 0;
                break;

            //
            //  These counters are not supported by this function (yet)
            //
            case PERF_COUNTER_TEXT:
            case PERF_COUNTER_NODATA:
            case PERF_COUNTER_HISTOGRAM_TYPE:
                pCounter->ThisValue.FirstValue = 0;
                pCounter->ThisValue.SecondValue = 0;
                break;

            case PERF_100NSEC_MULTI_TIMER:
            case PERF_100NSEC_MULTI_TIMER_INV:
            default:
                // an unidentified  or unsupported
                // counter was returned so
                pCounter->ThisValue.FirstValue = 0;
                pCounter->ThisValue.SecondValue = 0;
                bReturn = FALSE;
                break;
        }
    } else {
        // else this counter is not valid so this value == 0
        pCounter->ThisValue.CStatus     = LocalCStatus;
        pCounter->ThisValue.FirstValue  = 0;
        pCounter->ThisValue.SecondValue = 0;
        bReturn = FALSE;
    }

    return bReturn;
}

BOOL
UpdateWbemMultiInstanceCounterValue (
    IN      PPDHI_COUNTER   pCounter,
    IN      FILETIME        *pTimestamp
)
{
    IWbemObjectAccess   *pWbemAccess;
    HRESULT     hRes;

    DWORD       LocalCStatus = 0;
    DWORD       LocalCType  = 0;
    DWORD       dwValue;
    ULONGLONG   llValue;
    DWORD       dwSize;
    DWORD       dwFinalSize;
    LONG        lAvailableSize;
    LONG        lReturnSize;
    LONG        lThisInstanceIndex;
    LONG        lNumInstances;

    LPWSTR  szNextNameString;
    PPDHI_RAW_COUNTER_ITEM   pThisItem;

    BOOL    bReturn  = FALSE;

    if (pCounter->pThisRawItemList != NULL) {
        // free old counter buffer list
        G_FREE(pCounter->pLastRawItemList);
        pCounter->pLastRawItemList =
            pCounter->pThisRawItemList;
        pCounter->pThisRawItemList = NULL;
    }

    // get the counter's machine status first. There's no point in
    // contuning if the machine is offline

    // UpdateWbemCounterValue() will be called only if WBEM refresher succeeds
    // in GetQueryWbemData(); that is, all remote machines should be on-line

    LocalCStatus = ERROR_SUCCESS;

    if (IsSuccessSeverity(LocalCStatus)) {
        IWbemObjectAccess   **pWbemInstances = NULL;
        // get count of instances in enumerator
        assert (pCounter->pWbemEnum != NULL);
        hRes = pCounter->pWbemEnum->GetObjects(0, 0, NULL, (LPDWORD)&lNumInstances);
        if (hRes == WBEM_E_BUFFER_TOO_SMALL) {
            // then we should know how many have been returned so allocate an
            // array of pointers
            pWbemInstances = new IWbemObjectAccess * [lNumInstances];
            assert (pWbemInstances != NULL);
            if (pWbemInstances == NULL) {
                SetLastError(ERROR_OUTOFMEMORY);
                hRes    = ERROR_OUTOFMEMORY;
                bReturn = FALSE;
            }
            else {
                hRes = pCounter->pWbemEnum->GetObjects(0,
                    lNumInstances, pWbemInstances, (LPDWORD)&lNumInstances);
            }

            if (hRes == S_OK && lNumInstances > 0) {
                // then we have a table of instances
                // estimate the size required for the new data block
                dwSize = sizeof (PDHI_RAW_COUNTER_ITEM_BLOCK) - sizeof (PDHI_RAW_COUNTER_ITEM);
                dwSize += lNumInstances * (sizeof(PDH_RAW_COUNTER_ITEM_W) + (MAX_PATH * 2 * sizeof(WCHAR)));

                pCounter->pThisRawItemList = (PPDHI_RAW_COUNTER_ITEM_BLOCK)G_ALLOC (dwSize);

                if (pCounter->pThisRawItemList != NULL) {
                    dwFinalSize = lNumInstances * sizeof(PDH_RAW_COUNTER_ITEM_W);
                    szNextNameString = (LPWSTR)((PBYTE)pCounter->pThisRawItemList + dwFinalSize);

                    for (lThisInstanceIndex = 0;
                        lThisInstanceIndex < lNumInstances;
                        lThisInstanceIndex++) {
                        // get pointer to this raw data block in the array
                        pThisItem = &pCounter->pThisRawItemList->pItemArray[lThisInstanceIndex];
                        // get pointer to this IWbemObjectAccess pointer
                        pWbemAccess = pWbemInstances[lThisInstanceIndex];
                        // compute the remaining size of the buffer
                        lAvailableSize = (long)(dwSize - dwFinalSize);

                        assert (lAvailableSize > 0);

                        if (pCounter->lNameHandle != -1) {
                            hRes = pWbemAccess->ReadPropertyValue(
                                    pCounter->lNameHandle,
                                    lAvailableSize,
                                    &lReturnSize,
                                    (LPBYTE)szNextNameString);
                            assert(hRes == S_OK);
                        } else {
                            szNextNameString[0] = ATSIGN_L;
                            szNextNameString[1] = 0;
                            lReturnSize = 2;
                        }
                        pThisItem->szName = (DWORD)
                                (  ((LPBYTE) szNextNameString)
                                 - ((LPBYTE) pCounter->pThisRawItemList));
                        szNextNameString = (LPWSTR)((LPBYTE)szNextNameString + lReturnSize);
                        dwFinalSize += lReturnSize;
                        dwFinalSize = DWORD_MULTIPLE(dwFinalSize);

                        LocalCType = pCounter->plCounterInfo.dwCounterType;
                        switch (LocalCType) {
                            //
                            // these counter types are loaded as:
                            //      Numerator = Counter data from perf data block
                            //      Denominator = Perf Time from perf data block
                            //      (the time base is the PerfFreq)
                            //
                            case PERF_COUNTER_COUNTER:
                            case PERF_COUNTER_QUEUELEN_TYPE:
                            case PERF_SAMPLE_COUNTER:
                                // this should be a DWORD counter
                                assert ((pCounter->lNumItemType == VT_I4) ||
                                        (pCounter->lNumItemType == VT_UI4));
                                pWbemAccess->ReadDWORD (
                                        pCounter->lNumItemHandle, &dwValue);
                                pThisItem->FirstValue = (LONGLONG)(dwValue);

                                assert ((pCounter->lDenItemType == VT_I8) ||
                                        (pCounter->lDenItemType == VT_UI8));
                                pWbemAccess->ReadQWORD (
                                        pCounter->lDenItemHandle, &llValue);
                                // the denominator should be a 64-bit timestamp
                                pThisItem->SecondValue = llValue;

                                // look up the timebase freq if necessary
                                if (pCounter->TimeBase == 0) {
                                    assert ((pCounter->lFreqItemType == VT_I8) ||
                                            (pCounter->lFreqItemType == VT_UI8));
                                    pWbemAccess->ReadQWORD (
                                            pCounter->lFreqItemHandle, &llValue);
                                    // the timebase is a 64 bit integer
                                    pCounter->TimeBase = llValue;
                                }
                                break;

                            case PERF_ELAPSED_TIME:
                            case PERF_100NSEC_TIMER:
                            case PERF_100NSEC_TIMER_INV:
                            case PERF_COUNTER_TIMER:
                            case PERF_COUNTER_TIMER_INV:
                            case PERF_COUNTER_BULK_COUNT:
                            case PERF_COUNTER_MULTI_TIMER:
                            case PERF_COUNTER_MULTI_TIMER_INV:
                            case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
                            case PERF_OBJ_TIME_TIMER:
                            case PERF_COUNTER_100NS_QUEUELEN_TYPE:
                            case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
                            case PERF_PRECISION_SYSTEM_TIMER:
                            case PERF_PRECISION_100NS_TIMER:
                            case PERF_PRECISION_OBJECT_TIMER:
                                // this should be a QWORD counter
                                assert ((pCounter->lNumItemType == VT_I8) ||
                                        (pCounter->lNumItemType == VT_UI8));
                                pWbemAccess->ReadQWORD (
                                        pCounter->lNumItemHandle, &llValue);
                                pThisItem->FirstValue = (LONGLONG)(llValue);

                                assert ((pCounter->lDenItemType == VT_I8) ||
                                        (pCounter->lDenItemType == VT_UI8));
                                pWbemAccess->ReadQWORD (
                                        pCounter->lDenItemHandle, &llValue);
                                // the denominator should be a 64-bit timestamp
                                pThisItem->SecondValue = llValue;

                                // look up the timebase freq if necessary
                                if (pCounter->TimeBase == 0) {
                                    assert ((pCounter->lFreqItemType == VT_I8) ||
                                            (pCounter->lFreqItemType == VT_UI8));
                                    pWbemAccess->ReadQWORD (
                                            pCounter->lFreqItemHandle, &llValue);
                                    // the timebase is a 64 bit integer
                                    pCounter->TimeBase = llValue;
                                }
                                break;
                            //
                            //  These counters do not use any time reference
                            //
                            case PERF_COUNTER_RAWCOUNT:
                            case PERF_COUNTER_RAWCOUNT_HEX:
                            case PERF_COUNTER_DELTA:
                                // this should be a DWORD counter
                                assert ((pCounter->lNumItemType == VT_I4) ||
                                        (pCounter->lNumItemType == VT_UI4));
                                pWbemAccess->ReadDWORD (
                                        pCounter->lNumItemHandle, &dwValue);
                                pThisItem->FirstValue = (LONGLONG)(dwValue);
                                pThisItem->SecondValue = 0;
                                break;

                            case PERF_COUNTER_LARGE_RAWCOUNT:
                            case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
                            case PERF_COUNTER_LARGE_DELTA:
                                // this should be a DWORD counter
                                assert ((pCounter->lNumItemType == VT_I8) ||
                                        (pCounter->lNumItemType == VT_UI8));
                                pWbemAccess->ReadQWORD (
                                        pCounter->lNumItemHandle, &llValue);
                                pThisItem->FirstValue = (LONGLONG)(llValue);
                                pThisItem->SecondValue = 0;
                                break;

                            //
                            //  These counters use two data points, the one pointed to by
                            //  pData and the one immediately after
                            //
                            case PERF_SAMPLE_FRACTION:
                            case PERF_RAW_FRACTION:
                                // this should be a DWORD counter
                                assert ((pCounter->lNumItemType == VT_I4) ||
                                        (pCounter->lNumItemType == VT_UI4));
                                pWbemAccess->ReadDWORD (
                                        pCounter->lNumItemHandle, &dwValue);
                                pThisItem->FirstValue = (LONGLONG)dwValue;

                                assert ((pCounter->lDenItemType == VT_I4) ||
                                        (pCounter->lDenItemType == VT_UI4));
                                pWbemAccess->ReadDWORD (
                                        pCounter->lDenItemHandle, &dwValue);
                                // the denominator should be a 32-bit value
                                pThisItem->SecondValue = (LONGLONG)dwValue;
                                break;

                            case PERF_LARGE_RAW_FRACTION:
                                // this should be a DWORD counter
                                assert ((pCounter->lNumItemType == VT_I8) ||
                                        (pCounter->lNumItemType == VT_UI8));
                                pCounter->pWbemAccess->ReadQWORD (
                                    pCounter->lNumItemHandle, & llValue);
                                pCounter->ThisValue.FirstValue = (LONGLONG) llValue;

                                assert ((pCounter->lDenItemType == VT_I8) ||
                                        (pCounter->lDenItemType == VT_UI8));
                                pCounter->pWbemAccess->ReadQWORD (
                                    pCounter->lDenItemHandle, & llValue);
                                // the denominator should be a 32-bit value
                                pCounter->ThisValue.SecondValue = (LONGLONG) llValue;
                            break;

                            case PERF_AVERAGE_TIMER:
                            case PERF_AVERAGE_BULK:
                                // counter (numerator) is a LONGLONG, while the
                                // denominator is just a DWORD
                                // this should be a DWORD counter
                                assert ((pCounter->lNumItemType == VT_I8) ||
                                        (pCounter->lNumItemType == VT_UI8));
                                pWbemAccess->ReadQWORD (
                                        pCounter->lNumItemHandle, &llValue);
                                pThisItem->FirstValue = (LONGLONG)llValue;

                                assert ((pCounter->lDenItemType == VT_I4) ||
                                        (pCounter->lDenItemType == VT_UI4));
                                pWbemAccess->ReadDWORD (
                                        pCounter->lDenItemHandle, &dwValue);
                                // the denominator should be a 32-bit value
                                pThisItem->SecondValue = (LONGLONG)dwValue;

                                // look up the timebase freq if necessary
                                if (pCounter->TimeBase == 0) {
                                    assert ((pCounter->lFreqItemType == VT_I8) ||
                                            (pCounter->lFreqItemType == VT_UI8));
                                    pWbemAccess->ReadQWORD (
                                            pCounter->lFreqItemHandle, &llValue);
                                    // the timebase is a 64 bit integer
                                    pCounter->TimeBase = llValue;
                                }
                                break;
                            //
                            //  These counters are used as the part of another counter
                            //  and as such should not be used, but in case they are
                            //  they'll be handled here.
                            //
                            case PERF_SAMPLE_BASE:
                            case PERF_AVERAGE_BASE:
                            case PERF_COUNTER_MULTI_BASE:
                            case PERF_RAW_BASE:
                            case PERF_LARGE_RAW_BASE:
                                pThisItem->FirstValue = 0;
                                pThisItem->SecondValue = 0;
                                break;

                            //
                            //  These counters are not supported by this function (yet)
                            //
                            case PERF_COUNTER_TEXT:
                            case PERF_COUNTER_NODATA:
                            case PERF_COUNTER_HISTOGRAM_TYPE:
                                pThisItem->FirstValue = 0;
                                pThisItem->SecondValue = 0;
                                break;

                            case PERF_100NSEC_MULTI_TIMER:
                            case PERF_100NSEC_MULTI_TIMER_INV:
                            default:
                                // an unidentified  or unsupported
                                // counter was returned so
                                pThisItem->FirstValue = 0;
                                pThisItem->SecondValue = 0;
                                bReturn = FALSE;
                                break;
                        }
                        // we're done with this one so release it
                        pWbemAccess->Release();
                    }
                    // measure the memory block used
                    assert (dwFinalSize == (DWORD)((LPBYTE)szNextNameString -
                            (LPBYTE)(pCounter->pThisRawItemList)));

                    pCounter->pThisRawItemList->dwLength = dwFinalSize;
                    pCounter->pThisRawItemList->dwItemCount = lNumInstances;
                    pCounter->pThisRawItemList->dwReserved = 0;
                    pCounter->pThisRawItemList->CStatus = ERROR_SUCCESS;

                    pCounter->pThisRawItemList->TimeStamp = *pTimestamp;

                } else {
                    // unable to allocate a new buffer so return error
                    SetLastError (ERROR_OUTOFMEMORY);
                    bReturn = FALSE;
                }
            }
        }
    }
    return bReturn;
}

LONG
GetQueryWbemData (
    IN  PPDHI_QUERY         pQuery,
    IN  LONGLONG            *pllTimeStamp
)
{
    FILETIME            GmtFileTime;
    FILETIME            LocFileTime;
    LONGLONG            llTimeStamp = 0;
    HRESULT             hRes;
    LONG                lRetStatus = ERROR_SUCCESS;\

    PPDHI_COUNTER       pCounter;
    PDH_STATUS          pdhStatus;

    // refresh Wbem Refresher

    if (bDontRefresh) return ERROR_BUSY;

    if (pQuery->pRefresher != NULL) {
        hRes = pQuery->pRefresher->Refresh(0);
    } else {
        hRes = WBEM_E_INITIALIZATION_FAILURE;
    }

    // If multiple objects are being refreshed, some objects may succeed and
    // others may fail, in which case WBEM_S_PARTIAL_RESULTS is returned.

    if ( FAILED( hRes ) ) {
        SetLastError (hRes);
        lRetStatus = PDH_WBEM_ERROR;
    }

    if (lRetStatus == ERROR_SUCCESS) {
        // get timestamp for this counter
        GetSystemTimeAsFileTime(& GmtFileTime);
        FileTimeToLocalFileTime(& GmtFileTime, & LocFileTime);
        llTimeStamp = MAKELONGLONG(LocFileTime.dwLowDateTime,
                                   LocFileTime.dwHighDateTime);

        // now update the counters using this new data
        if ((pCounter = pQuery->pCounterListHead) != NULL) {
            do {
                if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
                    pdhStatus = UpdateWbemMultiInstanceCounterValue (
                        pCounter, (FILETIME *)&llTimeStamp);
                } else {
                    // update single instance counter values
                    pdhStatus = UpdateWbemCounterValue (pCounter,
                        (FILETIME *)&llTimeStamp);
                }
                pCounter = pCounter->next.flink;
            } while (pCounter != pQuery->pCounterListHead);
            pdhStatus = ERROR_SUCCESS;
        } else {
            // no counters in the query  (?!)
            pdhStatus = PDH_NO_DATA;
        }
        lRetStatus = pdhStatus;
    }
    
    *pllTimeStamp = llTimeStamp;

    return lRetStatus;
}

HRESULT WbemSetProxyBlanket(
    IUnknown                 *pInterface,
    DWORD                     dwAuthnSvc,
    DWORD                     dwAuthzSvc,
    OLECHAR                  *pServerPrincName,
    DWORD                     dwAuthLevel,
    DWORD                     dwImpLevel,
    RPC_AUTH_IDENTITY_HANDLE  pAuthInfo,
    DWORD                     dwCapabilities )
{
    // Security MUST be set on both the Proxy and it's IUnknown!

    IUnknown * pUnk = NULL;
    IClientSecurity * pCliSec = NULL;
    HRESULT sc = pInterface->QueryInterface(IID_IUnknown, (void **) &pUnk);
    if(sc != S_OK)
        return sc;
    sc = pInterface->QueryInterface(IID_IClientSecurity, (void **) &pCliSec);
    if(sc != S_OK)
    {
        pUnk->Release();
        return sc;
    }
    sc = pCliSec->SetBlanket(pInterface, dwAuthnSvc, dwAuthzSvc, pServerPrincName,
        dwAuthLevel, dwImpLevel, pAuthInfo, dwCapabilities);
    pCliSec->Release();
    pCliSec = NULL;
    sc = pUnk->QueryInterface(IID_IClientSecurity, (void **) &pCliSec);
    if(sc == S_OK)
    {
        sc = pCliSec->SetBlanket(pUnk, dwAuthnSvc, dwAuthzSvc, pServerPrincName,
            dwAuthLevel, dwImpLevel, pAuthInfo, dwCapabilities);
        pCliSec->Release();
    }
    else if (sc == 0x80004002)
        sc = S_OK;
    pUnk->Release();
    return sc;
}