Figure 4   PerfSrvObject

PerfSrvObject.h


// PerfSrvObject.h : Declaration of the CPerfSrvObject

#ifndef __PERFSRVOBJECT_H_
#define __PERFSRVOBJECT_H_

#include "resource.h"       // main symbols
#include "allincludes.h"

/////////////////////////////////////////////////////////////////////////////
// CPerfSrvObject
class ATL_NO_VTABLE CPerfSrvObject :
    public CComObjectRootEx<CComMultiThreadModel>,
    public CComCoClass<CPerfSrvObject, &CLSID_PerfSrvObject>,
    public ISupportErrorInfo,
    public IPersistStreamInitImpl<CPerfSrvObject>,
    public IDispatchImpl<IPerfSrvObject, &IID_IPerfSrvObject,  	                         &LIBID_PERFSRVEXELib>
{
public:
    static POTYPE    s_POMap;
    POTYPE& m_POMap;

    POTYPE::iterator    m_curPO;
    CPerfSrvObject() : m_POMap(s_POMap), m_bof(false),
                       m_eof(false),m_bRequiresLoad(TRUE)
    {
    }

    HRESULT FinalConstruct();
    void FinalRelease();

DECLARE_REGISTRY_RESOURCEID(IDR_PERFSRVOBJECT)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CPerfSrvObject)
    COM_INTERFACE_ENTRY(IPerfSrvObject)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(ISupportErrorInfo)
    COM_INTERFACE_ENTRY_IMPL(IPersistStreamInit)
    COM_INTERFACE_ENTRY_IMPL_IID(IID_IPersistStream,IPersistStreamInit)
END_COM_MAP()

BEGIN_PROP_MAP(CPerfSrvObject)
END_PROP_MAP();
// ISupportsErrorInfo
    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

    STDMETHOD(Load) (LPSTREAM pStream);
    STDMETHOD(Save) (LPSTREAM pStream, BOOL bClearDirty);
private:
    bool m_bof;
    bool m_eof;

public:
    STDMETHOD(Save)(/*[in]*/BSTR path,/*[in]*/BSTR name);
    STDMETHOD(AddPO)(/*[in]*/BSTR name, /*[in]*/BSTR helpString);
    STDMETHOD(GetNumCounters)(/*[out,retval]*/long* pNumCounters);
    STDMETHOD(MoveFirst)();
    STDMETHOD(MoveLast)();
    STDMETHOD(MoveNext)();
    STDMETHOD(MovePrevious)();
    STDMETHOD(GetNumPOs)(/*[out,retval]*/long* pNumCounters);
    STDMETHOD(GetCurrentPO)(/*[out,retval]*/IPerfPerformanceObject** pPO);
public:
    STDMETHOD(Clear)();
    STDMETHOD(FindFirst)(/*[in]*/ BSTR poName);
    STDMETHOD(Load)(/*[in]*/BSTR path,/*[in]*/BSTR name);
    bool m_bRequiresLoad;
    bool m_bRequiresSave;
};
#endif //__PERFSRVOBJECT_H_
PerfSrvObject.cpp

// PerfSrvObject.cpp : Implementation of CPerfSrvObject
#include "stdafx.h"
#include <algorithm>
#include "PerfSrvExe.h"
#include "PerfSrvObject.h"

/////////////////////////////////////////////////////////////////////////////
// CPerfSrvObject
POTYPE CPerfSrvObject::s_POMap;

STDMETHODIMP CPerfSrvObject::InterfaceSupportsErrorInfo(REFIID riid)
{
    static const IID* arr[] =
    {
        &IID_IPerfSrvObject
    };
    for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
        if (InlineIsEqualGUID(*arr[i],riid))
            return S_OK;
    }
    return S_FALSE;
}
HRESULT CPerfSrvObject::FinalConstruct()
{
    HRESULT hr = S_OK;
    m_bRequiresLoad = TRUE;
    if(m_POMap.size() > 0)
    {
        m_bRequiresLoad = FALSE;
    }
    return hr;
}
void CPerfSrvObject::FinalRelease()
{
/*    POTYPE::iterator    iter;

    for(iter = m_POMap.begin();iter != m_POMap.end();iter++)
    {
        ((*iter).second)->Release();
    }
    m_curPO = m_POMap.end();*/
    Clear();
}

/***************************************************************************
    Informational Methods
***************************************************************************/
STDMETHODIMP CPerfSrvObject::GetNumCounters(long *pNumCounters)
{
    IPerfPerformanceObject *pTemp = (*m_curPO).second;
    pTemp->get_m_numCounters(pNumCounters);
    return S_OK;
}
STDMETHODIMP CPerfSrvObject::GetNumPOs(long *pNumCounters)
{
    *pNumCounters = m_POMap.size();
    return S_OK;
}
STDMETHODIMP CPerfSrvObject::GetCurrentPO(IPerfPerformanceObject** pPO)
{
    *pPO = (IPerfPerformanceObject*)(*m_curPO).second;
    ((*m_curPO).second)->AddRef();

    return S_OK;
}

/***************************************************************************
    Positioning Methods

        Things to be done:

            - Add error handling
***************************************************************************/
STDMETHODIMP CPerfSrvObject::MoveFirst()
{
    HRESULT hr = S_OK;
    if(m_POMap.size() > 0)
    {
        m_bof = false;
        m_eof = false;
        m_curPO = m_POMap.begin();
    }
    else
    {
        ReportError repErr;
        return repErr.WriteCOMError(IDS_MAPNOTINITIALIZED,"");
    }
    return hr;
}
STDMETHODIMP CPerfSrvObject::MoveLast()
{
    if(m_POMap.size() > 0)
    {
        m_bof = false;
        m_eof = false;
        m_curPO = m_POMap.end();
        m_curPO--;
    }
    else
    {
        ReportError repErr;
        return repErr.WriteCOMError(IDS_MAPNOTINITIALIZED,"");
    }

    return S_OK;
}
STDMETHODIMP CPerfSrvObject::MoveNext()
{
    HRESULT hr = S_OK;
    ReportError repErr;

    if(m_eof)
    {
        return repErr.WriteCOMError(IDS_ENDOFMAP,"");
    }
    else
    {
        if(m_bof)
        {
            MoveFirst();
            m_bof = false;
        }
        else
        {
            m_curPO++;
        }

        if(m_curPO == m_POMap.end())
        {
            m_eof = true;
            return repErr.WriteCOMError(IDS_ENDOFMAP,"");
        }

    }

    return hr;
}
STDMETHODIMP CPerfSrvObject::MovePrevious()
{
    HRESULT hr = S_OK;
    ReportError repErr;

    if(m_bof)
    {
        //Insert proper error handling later
        return repErr.WriteCOMError(IDS_BEGINOFMAP,"");
    }
    else
    {
        if(m_curPO == m_POMap.begin() )
        {
            m_curPO = m_POMap.begin();
            m_bof = true;
        }
        else
        {
            m_curPO--;
            m_eof = false;
        }
    }

    return hr;
}

/***************************************************************************
    New Item Methods
***************************************************************************/
STDMETHODIMP CPerfSrvObject::AddPO(BSTR name, BSTR helpString)
{
    HRESULT hr = S_OK;

    CComObject<IPerfPerformanceObjectImpl> *pNew = NULL;

    hr = CComObject<IPerfPerformanceObjectImpl>::CreateInstance(&pNew);

    pNew->AddRef();

    pNew->SetInfo(name,helpString,0);

    _bstr_t poName(name);
    m_POMap[poName] = pNew;

    m_curPO = m_POMap.begin();
    return hr;
}

STDMETHODIMP CPerfSrvObject::Save(BSTR path, BSTR name)
{
    HRESULT hr = S_OK;
    IStreamPtr    pStream;

    try
    {
        HGLOBAL    hGlobal;
        void *pData = NULL;
        UCHAR *pDataCopy = NULL;
        CComVariant    varTemp;

        CreateStreamOnHGlobal(NULL,TRUE,&pStream);

        this->Save(pStream,TRUE);

        GetHGlobalFromStream(pStream,&hGlobal);

        pData = GlobalLock(hGlobal);
        DWORD dwSize = GlobalSize(hGlobal);

        USES_CONVERSION;
        _bstr_t localPath(path);
        _bstr_t localName(name);
        char dataPath[MAX_PATH];

        if(localName.length() > 0)
        {
            sprintf(dataPath,"%s\\%s",OLE2A(localPath),OLE2A(localName));
        }
        else if(localPath.length() > 0)
        {
            sprintf(dataPath,"%s",OLE2A(localPath));
        }
        else
        {
            ReportError repErr;
            return repErr.WriteCOMError(IDS_NOFILEFOUND,"No Valid File Name");
        }

        HANDLE hFile =
            CreateFile(dataPath,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
        long retVal;
        DWORD numWrite;
        retVal = WriteFile(hFile,pData,dwSize, &numWrite, NULL);

        CloseHandle(hFile);

        GlobalUnlock(hGlobal);
        GlobalFree(hGlobal);

    }
    catch(HRESULT hr)
    {
        hr = E_FAIL;
    }


    return S_OK;
}
STDMETHODIMP CPerfSrvObject::Load(LPSTREAM pStream)
{
    HRESULT hr = S_OK;
    long numPO;
    ULONG cb;

    IStreamPtr pIStream(pStream);
    pStream->Read(&numPO,sizeof(long),&cb);

    for(int x=0;x<numPO;x++)
    {
        HRESULT hr = S_OK;

        CComObject<IPerfPerformanceObjectImpl> *pNew = NULL;

        hr = CComObject<IPerfPerformanceObjectImpl>::CreateInstance(&pNew);

        pNew->AddRef();

        pNew->Read(pStream);

        BSTR poName;
        IPerfParentObject* pParent;

        pNew->GetParent(&pParent);
        pParent->get_m_name(&poName);

        pParent->Release();

        _bstr_t poBstrName(poName);

        m_POMap[poBstrName] = pNew;

    }

    m_curPO = m_POMap.begin();

    return hr;
}
STDMETHODIMP CPerfSrvObject::Save(LPSTREAM pStream, BOOL bClearDirty)
{
    HRESULT hr = S_OK;
    POTYPE::iterator    iter;
    long numCounters = 0;
    long numPO = 0;

    GetNumPOs(&numPO);

    //write number of Performance Objects
    ULONG cb;
    pStream->Write(&numPO,sizeof(long),&cb);

    for(iter = m_POMap.begin();iter != m_POMap.end();iter++)
    {
        IPerfPerformanceObject *pTemp = (*iter).second;

        pTemp->Write(pStream);

        //write something to stream saying no counter
        if(pTemp->MoveFirst() == E_FAIL)
            continue;

        do
        {
            IPerfCounterObject* pCO = NULL;
            hr = pTemp->GetCurrentCO(&pCO);

            pCO->Write(pStream);

            pCO->Release();

        }while(pTemp->MoveNext() != E_FAIL)    ;
    }

    return hr;
}

STDMETHODIMP CPerfSrvObject::Load(BSTR path, BSTR name)
{
    HGLOBAL    hGlobal;
    IStreamPtr    pStream;
    void *pData = NULL;
    UCHAR *pDataCopy = NULL;
    CComVariant    varTemp;

    USES_CONVERSION;

    HRESULT hr = S_OK;

    if(!m_bRequiresLoad)
    {
        //make proper return after
        //should return S_ALREADYLOADED
        return hr;
    }

    _bstr_t localPath(path);
    _bstr_t localName(name);
    char dataPath[MAX_PATH];

    if(localName.length() > 0)
    {
        sprintf(dataPath,"%s\\%s",OLE2A(localPath),OLE2A(localName));
    }
    else if(localPath.length() > 0)
    {
        sprintf(dataPath,"%s",OLE2A(localPath));
    }
    else
    {
        ReportError repErr;
        return repErr.WriteCOMError(IDS_NOFILEFOUND,"No Valid File Name");
    }

    HANDLE hFile =
        CreateFile(dataPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);

    if(hFile == INVALID_HANDLE_VALUE)
    {
        ReportError repErr;
        return repErr.WriteCOMError(IDS_NOFILEFOUND,dataPath);
    }

    DWORD dwSizeHigh,dwSizeLow;
    dwSizeLow = GetFileSize (hFile, &dwSizeHigh);

    hGlobal = GlobalAlloc(GMEM_MOVEABLE,dwSizeLow);

    DWORD nBytesRead;
    void *pGlobalVoid = GlobalLock(hGlobal);
    hr = ReadFile(hFile, pGlobalVoid, dwSizeLow, &nBytesRead,NULL);

    GlobalUnlock(hGlobal);

    hr = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);

    this->Load(pStream);

    CloseHandle(hFile);
    GlobalFree(hGlobal);

    m_bRequiresLoad = FALSE;

    return S_OK;
}

STDMETHODIMP CPerfSrvObject::FindFirst(BSTR poName)
{
    HRESULT hr = S_OK;

    _bstr_t    nameToFind(poName);

    m_curPO = m_POMap.find(nameToFind);

    if(m_curPO == m_POMap.end())
    {
        USES_CONVERSION;
        ReportError repErr;
        return repErr.WriteCOMError(IDS_NORECORDFOUND,OLE2A(poName));
    }

    return hr;
}

STDMETHODIMP CPerfSrvObject::Clear()
{
    POTYPE::iterator    iter;

    for(iter = m_POMap.begin();iter != m_POMap.end();iter++)
    {
        ((*iter).second)->Release();
    }
    m_curPO = m_POMap.end();
    m_bRequiresLoad = TRUE;
    return S_OK;
}

Figure 6   IPerfPerformanceObject Methods

Method Name
Description
AddCounter
Adds a counter object to the current PO
GetCurrentCO
Retrieves the CO that the current PO is responsible for
GetParent
Gets the parent interface that implements some common methods
MoveFirst
Moves to the first CO
MoveLast
Moves to the last CO
MoveNext
Moves to the next CO
MovePrevious
Moves to the previous CO
FindFirst
Finds the first CO based on its name
Read
Reads in a persisted PO/CO schema
SetInfo
A general method for setting the PO's name, help string, and index value
Write
Persists the current PO's information to a data stream