|
|
#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_
|