1134 lines
24 KiB
C++
1134 lines
24 KiB
C++
#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_
|