#ifndef __UTILS__H
#define __UTILS__H
/*++

Copyright (C) 1997-1999  Microsoft Corporation

Module Name:

    utils.h

Abstract:

    This module declares utilities classes

Author:

    William Hsieh (williamh) created

Revision History:


--*/

//
// Memory allocation exception class
//
class CMemoryException
{
public:
    CMemoryException(BOOL Global)
    {
        m_Global = Global;
        m_Message[0] = _T('\0');
        m_Caption[0] = _T('\0');
        m_Options = MB_OK | MB_ICONHAND;
    }
    BOOL SetMessage(LPCTSTR Message)
    {
        if (!Message || lstrlen(Message) >= ARRAYLEN(m_Message))
        {
            return FALSE;
        }

        lstrcpy(m_Message, Message);
        return TRUE;

    }
    BOOL SetCaption(LPCTSTR Caption)
    {
        if (!Caption || lstrlen(Caption) >= ARRAYLEN(m_Caption))
        {
            return FALSE;
        }

        lstrcpy(m_Caption, Caption);
        return TRUE;
    }
    BOOL SetOptions(DWORD Options)
    {
        m_Options = Options;
        return TRUE;
    }
    void ReportError(HWND hwndParent = NULL)
    {
        MessageBox(hwndParent, m_Message, m_Caption, m_Options);
    }
    void Delete()
    {
        if (!m_Global)
        {
            delete this;
        }
    }

private:
    TCHAR m_Message[128];
    TCHAR m_Caption[128];
    DWORD m_Options;
    BOOL  m_Global;
};

inline int MAX(int Value1, int Value2)
{
    return (Value1 >= Value2) ? Value1 : Value2;
}

//
// data buffer control class for String class
//
class StringData
{
public:
    StringData() : Ref(1), ptsz(NULL), Len(0)
    {}
    ~StringData()
    {
        delete [] ptsz;
    }
    long AddRef()
    {
        Ref++;
        return Ref;
    }
    long Release()
    {
        ASSERT(Ref);
        if (!(--Ref))
        {
        delete this;
        return 0;
        }
        return Ref;
    }
    TCHAR*  ptsz;
    long    Len;

private:
    long    Ref;
};

class CBlock
{
public:
    CBlock(CBlock* BlockHead, UINT unitCount, UINT unitSize)
    {
        data = new BYTE[unitCount * unitSize];
        if (data)
        {
            if (BlockHead)
            {
                m_Next = BlockHead->m_Next;
                BlockHead->m_Next = this;
            }
            else
            {
                m_Next = NULL;
            }
        }
        else
        {
            throw &g_MemoryException;
        }
    }
    ~CBlock()
    {
        if (data)
        delete [] data;
        if (m_Next)
        delete m_Next;
    }
    void*   data;

private:
    CBlock* m_Next;
};


//
// Text string class
//
class String
{
public:
// constructors
    String();
    String(LPCTSTR lptsz);
    String(const String& strSrc);
    ~String()
    {
        m_pData->Release();
    }
//operators

    TCHAR& operator[](int Index);
    operator LPTSTR();

    const TCHAR& operator[](int Index) const
    {
        ASSERT(Index < m_pData->Len && m_pData->ptsz);
        return m_pData->ptsz[Index];
    }

    operator LPCTSTR () const
    {
        return m_pData->ptsz;
    }
    String& operator=(const String& strSrc);
    String& operator=(LPCTSTR ptsz);
    String& operator+=(const String& strSrc);
    String& operator+=(LPCTSTR prsz);
    friend String operator+(const String& str1, const String& str2);

    int GetLength() const
    {
        return m_pData->Len;
    }
    BOOL IsEmpty() const
    {
        return (0 == m_pData->Len);
    }
    int Compare(const String& strSrc) const
    {
        return lstrcmp(m_pData->ptsz, strSrc.m_pData->ptsz);
    }
    int CompareNoCase(const String& strSrc) const
    {
        return lstrcmpi(m_pData->ptsz, strSrc.m_pData->ptsz);
    }
    void Empty();
    BOOL LoadString(HINSTANCE hInstance, int ResourceId);
    BOOL GetComputerName();
    BOOL GetSystemWindowsDirectory();
    void Format(LPCTSTR FormatString, ...);
    StringData* m_pData;

protected:
    String(int Len);

};

//
// Command line parsing class
//
class CCommandLine
{
public:
    void ParseCommandLine(LPCTSTR cmdline);
    virtual void ParseParam(LPCTSTR Param, BOOL bFlag, BOOL bLast) = 0;
};




//
// Safe registry class
//
class CSafeRegistry
{
public:
    CSafeRegistry(HKEY hKey = NULL) : m_hKey(hKey)
    {}
    ~CSafeRegistry()
    {
        if (m_hKey)
        {
            RegCloseKey(m_hKey);
        }
    }
    operator HKEY()
    {
        return m_hKey;
    }
    BOOL Open(HKEY hKeyAncestor, LPCTSTR KeyName, REGSAM Access = KEY_ALL_ACCESS);
    void Close()
    {
        if (m_hKey)
        {
            RegCloseKey(m_hKey);
        }

        m_hKey = NULL;
    }
    BOOL Create(HKEY hKeyAncestor, LPCTSTR KeyName,
             REGSAM Access = KEY_ALL_ACCESS,
             DWORD * pDisposition = NULL, DWORD  Options = 0,
             LPSECURITY_ATTRIBUTES pSecurity = NULL);
    BOOL SetValue(LPCTSTR ValueName, DWORD Type, PBYTE pData, DWORD DataLen);
    BOOL SetValue(LPCTSTR ValueName, LPCTSTR Value);
    BOOL GetValue(LPCTSTR ValueName, DWORD* pType, PBYTE Buffer, DWORD* BufferLen);
    BOOL GetValue(LPCTSTR ValueName, String& str);
    BOOL DeleteValue(LPCTSTR ValueName);
    BOOL DeleteSubkey(LPCTSTR SubkeyName);
    BOOL EnumerateSubkey(DWORD Index, LPTSTR Buffer, DWORD* BufferSize);

private:
    HKEY    m_hKey;
};

// define iteration context. To be used by CLIST
struct tagPosition{ };
typedef tagPosition* POSITION;

template<class TYPE>
inline void ConstructElements(TYPE* pElements, int Count)
{
    memset((void*)&pElements, 0, Count * sizeof(TYPE));
    
    for (; Count; Count--, pElements++)
    {
        // call the contructor -- note the placement
        ::new((void*)pElements) TYPE;
    }
}

template<class TYPE>
inline void DestructElements(TYPE* pElements, int Count)
{
    for (; Count; Count--, pElements++)
    {
        pElements->~TYPE();
    }
}
//
// TEMPLATEs
//


//
// CList template, adapted from MFC
//
template<class TYPE, class ARG_TYPE>
class CList
{
protected:
    struct CNode
    {
        CNode* pNext;
        CNode* pPrev;
        TYPE data;
    };

public:
// Construction
    CList(int nBlockSize = 10);

// Attributes (head and tail)
    // count of elements
    int GetCount() const;
    BOOL IsEmpty() const;

    // peek at head or tail
    TYPE& GetHead();
    TYPE GetHead() const;
    TYPE& GetTail();
    TYPE GetTail() const;

// Operations
    // get head or tail (and remove it) - don't call on empty list !
    TYPE RemoveHead();
    TYPE RemoveTail();

    // add before head or after tail
    POSITION AddHead(ARG_TYPE newElement);
    POSITION AddTail(ARG_TYPE newElement);

    // add another list of elements before head or after tail
    void AddHead(CList* pNewList);
    void AddTail(CList* pNewList);

    // remove all elements
    void RemoveAll();

    // iteration
    POSITION GetHeadPosition() const;
    POSITION GetTailPosition() const;
    TYPE& GetNext(POSITION& rPosition); // return *Position++
    TYPE GetNext(POSITION& rPosition) const; // return *Position++
    TYPE& GetPrev(POSITION& rPosition); // return *Position--
    TYPE GetPrev(POSITION& rPosition) const; // return *Position--

    // getting/modifying an element at a given position
    TYPE& GetAt(POSITION position);
    TYPE GetAt(POSITION position) const;
    void SetAt(POSITION pos, ARG_TYPE newElement);
    void RemoveAt(POSITION position);

    // inserting before or after a given position
    POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
    POSITION InsertAfter(POSITION position, ARG_TYPE newElement);

    POSITION FindIndex(int nIndex) const;
        // get the 'nIndex'th element (may return NULL)

// Implementation
protected:
    CNode* m_pNodeHead;
    CNode* m_pNodeTail;
    int m_nCount;
    CNode* m_pNodeFree;
    CBlock* m_pBlocks;
    int m_nBlockSize;

    CNode* NewNode(CNode*, CNode*);
    void FreeNode(CNode*);

public:
    ~CList();
};


/////////////////////////////////////////////////////////////////////////////
// CList<TYPE, ARG_TYPE> inline functions

template<class TYPE, class ARG_TYPE>
inline int CList<TYPE, ARG_TYPE>::GetCount() const
    { return m_nCount; }
template<class TYPE, class ARG_TYPE>
inline BOOL CList<TYPE, ARG_TYPE>::IsEmpty() const
    { return m_nCount == 0; }
template<class TYPE, class ARG_TYPE>
inline TYPE& CList<TYPE, ARG_TYPE>::GetHead()
    { ASSERT(m_pNodeHead != NULL);
        return m_pNodeHead->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE CList<TYPE, ARG_TYPE>::GetHead() const
    { ASSERT(m_pNodeHead != NULL);
        return m_pNodeHead->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE& CList<TYPE, ARG_TYPE>::GetTail()
    { ASSERT(m_pNodeTail != NULL);
        return m_pNodeTail->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE CList<TYPE, ARG_TYPE>::GetTail() const
    { ASSERT(m_pNodeTail != NULL);
        return m_pNodeTail->data; }
template<class TYPE, class ARG_TYPE>
inline POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition() const
    { return (POSITION) m_pNodeHead; }
template<class TYPE, class ARG_TYPE>
inline POSITION CList<TYPE, ARG_TYPE>::GetTailPosition() const
    { return (POSITION) m_pNodeTail; }
template<class TYPE, class ARG_TYPE>
inline TYPE& CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) // return *Position++
    { CNode* pNode = (CNode*) rPosition;
        rPosition = (POSITION) pNode->pNext;
        return pNode->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) const // return *Position++
    { CNode* pNode = (CNode*) rPosition;
        rPosition = (POSITION) pNode->pNext;
        return pNode->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE& CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) // return *Position--
    { CNode* pNode = (CNode*) rPosition;
        rPosition = (POSITION) pNode->pPrev;
        return pNode->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) const // return *Position--
    { CNode* pNode = (CNode*) rPosition;
        rPosition = (POSITION) pNode->pPrev;
        return pNode->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE& CList<TYPE, ARG_TYPE>::GetAt(POSITION position)
    { CNode* pNode = (CNode*) position;
        return pNode->data; }
template<class TYPE, class ARG_TYPE>
inline TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION position) const
    { CNode* pNode = (CNode*) position;
        return pNode->data; }
template<class TYPE, class ARG_TYPE>
inline void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
    { CNode* pNode = (CNode*) pos;
        pNode->data = newElement; }

template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::CList(int nBlockSize)
{
    ASSERT(nBlockSize > 0);

    m_nCount = 0;
    m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
    m_pBlocks = NULL;
    m_nBlockSize = nBlockSize;
}

template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::RemoveAll()
{
    // destroy elements
    CNode* pNode;
    for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
    {
        DestructElements<TYPE>(&pNode->data, 1);
    }

    m_nCount = 0;
    m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
    delete m_pBlocks;
    m_pBlocks = NULL;
}

template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::~CList()
{
    RemoveAll();
    ASSERT(m_nCount == 0);
}

/////////////////////////////////////////////////////////////////////////////
// Node helpers
//

template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::CNode*
CList<TYPE, ARG_TYPE>::NewNode(CList::CNode* pPrev, CList::CNode* pNext)
{
    if (m_pNodeFree == NULL)
    {
        // add another block
        CBlock* pNewBlock = new CBlock(m_pBlocks, m_nBlockSize, sizeof(CNode));
        
        if (!pNewBlock) {

            throw &g_MemoryException;
        }

        if (m_pBlocks == NULL)
        {
            m_pBlocks = pNewBlock;
        }

        // chain them into free list
        CNode* pNode = (CNode*) pNewBlock->data;
        
        // free in reverse order to make it easier to debug
        pNode += m_nBlockSize - 1;
        
        for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
        {
            pNode->pNext = m_pNodeFree;
            m_pNodeFree = pNode;
        }
    }
    
    ASSERT(m_pNodeFree != NULL);  // we must have something

    CList::CNode* pNode = m_pNodeFree;
    m_pNodeFree = m_pNodeFree->pNext;
    pNode->pPrev = pPrev;
    pNode->pNext = pNext;
    m_nCount++;
    ASSERT(m_nCount > 0);  // make sure we don't overflow

    ConstructElements<TYPE>(&pNode->data, 1);
    
    return pNode;
}

template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::FreeNode(CList::CNode* pNode)
{
    DestructElements<TYPE>(&pNode->data, 1);
    pNode->pNext = m_pNodeFree;
    m_pNodeFree = pNode;
    m_nCount--;
    ASSERT(m_nCount >= 0);  // make sure we don't underflow

    // if no more elements, cleanup completely
    if (m_nCount == 0)
        RemoveAll();
}

template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
{
    CNode* pNewNode = NewNode(NULL, m_pNodeHead);
    pNewNode->data = newElement;
    
    if (m_pNodeHead != NULL)
    {
        m_pNodeHead->pPrev = pNewNode;
    }
    else
    {
        m_pNodeTail = pNewNode;
    }

    m_pNodeHead = pNewNode;
    
    return (POSITION) pNewNode;
}

template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
{
    CNode* pNewNode = NewNode(m_pNodeTail, NULL);
    pNewNode->data = newElement;
    if (m_pNodeTail != NULL)
    {
        m_pNodeTail->pNext = pNewNode;
    }
    else
    {
        m_pNodeHead = pNewNode;
    }

    m_pNodeTail = pNewNode;
    
    return (POSITION) pNewNode;
}

template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::AddHead(CList* pNewList)
{
    ASSERT(pNewList != NULL);

    // add a list of same elements to head (maintain order)
    POSITION pos = pNewList->GetTailPosition();
    
    while (pos != NULL)
    {
        AddHead(pNewList->GetPrev(pos));
    }
}

template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::AddTail(CList* pNewList)
{
    ASSERT(pNewList != NULL);

    // add a list of same elements
    POSITION pos = pNewList->GetHeadPosition();
    
    while (pos != NULL)
    {
        AddTail(pNewList->GetNext(pos));
    }
}

template<class TYPE, class ARG_TYPE>
TYPE CList<TYPE, ARG_TYPE>::RemoveHead()
{
    ASSERT(m_pNodeHead != NULL);  // don't call on empty list !!!

    CNode* pOldNode = m_pNodeHead;
    TYPE returnValue = pOldNode->data;

    m_pNodeHead = pOldNode->pNext;
    
    if (m_pNodeHead != NULL)
    {
        m_pNodeHead->pPrev = NULL;
    }
    else
    {
        m_pNodeTail = NULL;
    }
    
    FreeNode(pOldNode);
    
    return returnValue;
}

template<class TYPE, class ARG_TYPE>
TYPE CList<TYPE, ARG_TYPE>::RemoveTail()
{
    ASSERT(m_pNodeTail != NULL);  // don't call on empty list !!!

    CNode* pOldNode = m_pNodeTail;
    TYPE returnValue = pOldNode->data;

    m_pNodeTail = pOldNode->pPrev;
    
    if (m_pNodeTail != NULL)
    {
        m_pNodeTail->pNext = NULL;
    }
    else
    {
        m_pNodeHead = NULL;
    }
    
    FreeNode(pOldNode);
    
    return returnValue;
}

template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::InsertBefore(POSITION position, ARG_TYPE newElement)
{

    if (position == NULL)
    {
        return AddHead(newElement); // insert before nothing -> head of the list
    }

    // Insert it before position
    CNode* pOldNode = (CNode*) position;
    CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
    pNewNode->data = newElement;

    if (pOldNode->pPrev != NULL)
    {
        pOldNode->pPrev->pNext = pNewNode;
    }
    else
    {
        ASSERT(pOldNode == m_pNodeHead);
        m_pNodeHead = pNewNode;
    }
    
    pOldNode->pPrev = pNewNode;
    
    return (POSITION) pNewNode;
}

template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::InsertAfter(POSITION position, ARG_TYPE newElement)
{

    if (position == NULL)
    {
        return AddTail(newElement); // insert after nothing -> tail of the list
    }

    // Insert it before position
    CNode* pOldNode = (CNode*) position;
    CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
    pNewNode->data = newElement;

    if (pOldNode->pNext != NULL)
    {
        pOldNode->pNext->pPrev = pNewNode;
    }
    else
    {
        ASSERT(pOldNode == m_pNodeTail);
        m_pNodeTail = pNewNode;
    }
    
    pOldNode->pNext = pNewNode;
    
    return (POSITION) pNewNode;
}

template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::RemoveAt(POSITION position)
{

    CNode* pOldNode = (CNode*) position;

    // remove pOldNode from list
    if (pOldNode == m_pNodeHead)
    {
        m_pNodeHead = pOldNode->pNext;
    }
    else
    {
        pOldNode->pPrev->pNext = pOldNode->pNext;
    }
    
    if (pOldNode == m_pNodeTail)
    {
        m_pNodeTail = pOldNode->pPrev;
    }
    else
    {
        pOldNode->pNext->pPrev = pOldNode->pPrev;
    }
    
    FreeNode(pOldNode);
}


template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::FindIndex(int nIndex) const
{
    ASSERT(nIndex >= 0);

    if (nIndex >= m_nCount)
    {
        return NULL;  // went too far
    }

    CNode* pNode = m_pNodeHead;
    
    while (nIndex--)
    {
        pNode = pNode->pNext;
    }
    
    return (POSITION) pNode;
}



// NOTE:
// dereferencing operator -> is not supported in this template
// because this is designed to allocate intrinsic data types only
//
template<class T>
class BufferPtr
{
public:
    BufferPtr(UINT Size) : m_pBase(NULL), m_Size(Size)
    {
        ASSERT(Size);
        m_pBase = new T[Size];
        m_pCur = m_pBase;
        
        if (!m_pBase)
        {
            throw &g_MemoryException;
        }
    }
    BufferPtr()
    {
        m_pBase = NULL;
        m_pCur = NULL;
        m_Size = 0;
    }
    ~BufferPtr()
    {
        if (m_pBase)
        {
            delete [] m_pBase;
        }
    }
    // casting operator
    operator T*()
    {
        return m_pCur;
    }
    operator T&()
    {
        ASSERT(m_pCur < m_pBase + m_Size);
        return *m_pCur;
    }
    operator void*()
    {
        return m_pCur;
    }
    T& operator*()
    {
        ASSERT(m_pCur < m_pBase + m_Size);
        return *m_pCur;
    }
    // increment/decrement
    T* operator+(UINT Inc)
    {
        ASSERT(m_pBase + m_Size > m_pCur + Inc);
        return (m_pBase + Inc);
    }
    T* operator-(UINT Dec)
    {
        ASSERT(m_pBase >= m_pCur - Dec);
        m_pCur -= Dec;
        return m_pCur;
    }
    //prefix
    T* operator++()
    {
        ASSERT(m_pBase + m_Size > m_pCur - 1);
        return ++m_pCur;
    }
    //postfix
    T* operator++(int inc)
    {
        pCur
        ASSERT(m_pBase + m_Size > m_pCur);
        return m_pCur++;
    }
    //prefix
    T* operator--()
    {
        ASSERT(m_pCur > m_pBase);
        return --m_pCur;
    }
    //postfix
    T* operator--(int inc)
    {
        ASSERT(m_pCur > m_pBase);
        return m_pCur--;
    }
    T** operator&()
    {
        return &m_pBase;
    }
    // subscripting
    T& operator[](UINT Index)
    {
        ASSERT(Index < m_Size);
        return m_pBase[Index];
    }
    void Attach(T* pT, UINT Size = 1)
    {
        ASSERT(!m_pBase);
        m_pBase = pT;
        m_pCur = m_pBase;
        m_Size = Size;
    }
    void Detach()
    {
        m_pBase = NULL;
    }
    UINT GetSize()
    {
        return m_Size;
    }

private:
    T*   m_pBase;
    T*   m_pCur;
    UINT    m_Size;
};

template<class T>
class SafePtr
{
public:
    SafePtr(T* p)
    {
        __p = p;
    }
    SafePtr()
    {
        __p = NULL;
    }
    ~SafePtr()
    {
        if (__p)
        {
            delete __p;
        }
    }
    void Attach(T* p)
    {
        ASSERT(NULL == __p);
        __p = p;
    }
    void Detach()
    {
        __p = NULL;
    }
    T* operator->()
    {
        ASSERT(__p);

        return __p;
    }
    T& operator*()
    {
        ASSERT(__p);

        return *__p;
    }
    operator T*()
    {
        return __p;
    }
    operator T&()
    {
        ASSERT(__p);
        return *__p;
    }

private:
    T*  __p;

};



class CPropPageProvider;

class CPropSheetData
{
public:
    CPropSheetData();
    ~CPropSheetData();
    virtual BOOL Create(HINSTANCE hInst, HWND hwndParent, UINT MaxPages, LONG_PTR lConsoleHandle = 0);
    BOOL InsertPage(HPROPSHEETPAGE hPage, int Index = -1);
    INT_PTR DoSheet()
    {
        return ::PropertySheet(&m_psh);
    }
    HWND GetWindowHandle()
    {
        return m_hWnd;
    }
    void PageCreateNotify(HWND hWnd);
    void PageDestroyNotify(HWND hWnd);
    PROPSHEETHEADER m_psh;
    BOOL PropertyChangeNotify(long lParam);
    void AddProvider(CPropPageProvider* pProvider)
    {
        m_listProvider.AddTail(pProvider);
    }

protected:
    UINT    m_MaxPages;
    LONG_PTR m_lConsoleHandle;
    HWND    m_hWnd;

private:
    CList<CPropPageProvider*, CPropPageProvider*> m_listProvider;
};


class CDialog
{
public:
    CDialog(int TemplateId) : m_hDlg(NULL), m_TemplateId(TemplateId)
    {}
    virtual ~CDialog()
    {}
    static INT_PTR CALLBACK DialogWndProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    INT_PTR DoModal(HWND hwndParent, LPARAM lParam )
    {
        return DialogBoxParam(g_hInstance, MAKEINTRESOURCE(m_TemplateId), hwndParent, DialogWndProc, lParam);
    }
    void DoModaless(HWND hwndParent, LPARAM lParam)
    {
        m_hDlg = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(m_TemplateId), hwndParent, DialogWndProc, lParam);
    }
    virtual BOOL OnInitDialog()
    {
        return TRUE;
    }
    virtual void OnCommand(WPARAM wParam, LPARAM lParam)
    {}
    virtual BOOL OnNotify(LPNMHDR pnmhdr)
    {
        return FALSE;
    }
    virtual BOOL OnDestroy()
    {
        return FALSE;
    }
    virtual BOOL OnHelp(LPHELPINFO pHelpInfo)
    {
        return FALSE;
    }
    virtual BOOL OnContextMenu(HWND hWnd, WORD xPos, WORD yPos)
    {
        return FALSE;
    }

    HWND GetControl(int idControl)
    {
        return GetDlgItem(m_hDlg, idControl);
    }
    operator HWND()
    {
        return m_hDlg;
    }
    HWND    m_hDlg;

private:
    int     m_TemplateId;
};


class CFileHandle
{
public:
    CFileHandle(HANDLE hFile = INVALID_HANDLE_VALUE) : m_hFile(hFile)
    {}
    ~CFileHandle()
    {
        if (INVALID_HANDLE_VALUE != m_hFile)
        CloseHandle(m_hFile);
    }
    void Open(HANDLE hFile)
    {
        ASSERT(INVALID_HANDLE_VALUE == m_hFile);
        m_hFile = hFile;
    }
    void Close()
    {
        if (INVALID_HANDLE_VALUE != m_hFile)
        CloseHandle(m_hFile);
    }
    HANDLE hFile()
    {
        return m_hFile;
    }

private:
    HANDLE  m_hFile;
};

class CLogFile
{
public:
    CLogFile() : m_hFile(INVALID_HANDLE_VALUE)
    {}
    ~CLogFile()
    {
        Close();
    }
    BOOL Create(LPCTSTR LogFileName)
    {
        if (!LogFileName)
        {
            return FALSE;
        }

        m_strLogFileName = LogFileName;
        m_hFile = CreateFile(LogFileName,
                GENERIC_READ | GENERIC_WRITE,
                0,
                NULL,
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
        return INVALID_HANDLE_VALUE != m_hFile;
    }
    void Close()
    {
        if (m_hFile)
        {
            CloseHandle(m_hFile);
            m_hFile = INVALID_HANDLE_VALUE;
        }
    }
    LPCTSTR LogFileName()
    {
        return m_strLogFileName.IsEmpty() ? NULL : (LPCTSTR)m_strLogFileName;
    }
    void Delete()
    {
        Close();
        if (m_strLogFileName)
        DeleteFile(m_strLogFileName);
    }
    BOOL LogLastError(LPCTSTR FunctionName);
    BOOL Logf(LPCTSTR Format, ...);
    BOOL Log(LPCTSTR Text);

private:
    HANDLE  m_hFile;
    String  m_strLogFileName;
};

STDAPI_(CONFIGRET) GetLocationInformation(
    DEVNODE dn,
    LPTSTR Location,
    ULONG LocationLen,  // In characters
    HMACHINE hMachine
    );

#endif  // __UTILS_H_
