//////////////////////////////////////////
// ToolBox - Useful Code                //
//////////////////////////////////////////


#if !defined(TOOL_BOX_HEADER)
#define TOOL_BOX_HEADER

// Do not use "new" or "delete" in any of the inlined code below (excluding templates)
// so that we can avoid having those allocations tracked by ToolBoxDebug

#include "ToolBoxW4Settings.h"
#include "Windows_W3.h"
#include <TCHAR.h>
// Some environments do not have an assert.h file, but do have an ASSERT(...)
// macro defined

#if defined assert
#undef assert
#endif  // defined(assert)

#if defined(ASSERT)
#define assert(e) ASSERT(e)
#else  // defined(ASSERT)
#include <assert.h>
#define ASSERT(e) assert(e)
#endif  // defined(ASSERT)

// C_ASSERT() can be used to perform many compile-time assertions: type sizes,
// field offsets, etc.  (From VC++'s WinNT.h)
#if !defined(C_ASSERT)
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
// An assertion failure results in error C2118: negative subscript.
#endif // !defined(C_ASSERT)

// Provide a verify macro for all environments
#if !defined(VERIFY)
#if defined(DEBUG) || defined(_DEBUG)
#define VERIFY(e) ASSERT(e)
#else  // defined(DEBUG) || defined(_DEBUG)
#define VERIFY(e) ((void)(e))
#endif  // defined(DEBUG) || defined(_DEBUG)
#endif  // !defined(VERIFY)


#if !defined(MAX_RC_STRING_LENGTH_TOOLBOX)
#define MAX_RC_STRING_LENGTH_TOOLBOX 512
#endif

// Macro to simplify determining the number of elements in an array (do *not*
// use this macro for pointers)
#define ARRAY_LENGTH(x) (sizeof(x)/sizeof((x)[0]))

// Macro to divide an integer by another integer, rounding any fractional remainder up
// Example: DIVIDE_ROUNDING_UP(5, 7) == 1
//          DIVIDE_ROUNDING_UP(10, 7) == 2
//          DIVIDE_ROUNDING_UP(14, 7) == 2
#define DIVIDE_ROUNDING_UP(x, Divisor) (((x)+((Divisor)-1))/(Divisor))

// Macro to round an integer up to the next multiple of another number
// Example: ROUND_UP_TO_NEXT_MULTIPLE(5, 7) == 7
//          ROUND_UP_TO_NEXT_MULTIPLE(10, 7) == 14
//          ROUND_UP_TO_NEXT_MULTIPLE(14, 7) == 14
#define ROUND_UP_TO_NEXT_MULTIPLE(x, Multiple) ((x)+(((Multiple)-((x)%(Multiple)))%(Multiple)))
// Alternative method that computes DIVIDE_ROUNDING_UP(x, Multiple)*Multiple
// #define ROUND_UP_TO_NEXT_MULTIPLE(x, Multiple) ((((x)+((Multiple)-1))/(Multiple))*(Multiple))

// Safe string-copying and string-concatenation routines that take length-
// limiting parameters and *always* 0-terminate the destination string
TCHAR* _tcsncpyz(TCHAR* const psDestination, const TCHAR* const psSource, const unsigned int uiDestinationLength);
//seems this function is bugged....use OS supplied _tscncat() instead
//TCHAR* _tcsncatz(TCHAR* const psDestination, const TCHAR* const psSource, const unsigned int uiDestinationLength);
char* strncpyz(char* const psDestination, const char* const psSource, const unsigned int uiDestinationLength);
char* strncatz(char* const psDestination, const char* const psSource, const unsigned int uiDestinationLength);
WCHAR* wcsncpyz(WCHAR* const psDestination, const WCHAR* const psSource, const unsigned int uiDestinationLength);
WCHAR* wcsncatz(WCHAR* const psDestination, const WCHAR* const psSource, const unsigned int uiDestinationLength);
int _sntprintfz(TCHAR* const psDestination, const unsigned int uiDestinationLength, const TCHAR* const psFormat, ...);
int _snprintfz(char* const psDestination, const unsigned int uiDestinationLength, const char* const psFormat, ...);
int _snwprintfz(WCHAR* const psDestination, const unsigned int uiDestinationLength, const WCHAR* const psFormat, ...);

// Registry get and set helper-functions
bool GetRegistryDWORD(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, DWORD* const pdwValue);
bool SetRegistryDWORD(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, const DWORD dwValue);
bool GetRegistryBoolean(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, bool* const pbValue);
bool SetRegistryBoolean(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, const bool bValue);
bool GetRegistryBINARY(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, BYTE *const pbValue, const DWORD dwValueSize);
bool SetRegistryBINARY(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, const BYTE* const pbValue, const DWORD dwValueSize);
bool GetRegistrySZ(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, TCHAR *const psValue, const DWORD dwValueChars);
bool SetRegistrySZ(const HKEY hRoot, const TCHAR* const psKeyName, const TCHAR* const psValueName, const TCHAR *const psValue);

// Function to return a random number r such that ((iLow <= r) && (r <= iHigh)).  It is the caller's duty to call srand if desired.
int BoundedRandom(const int iLow, const int iHigh);

// Class for creating blocks of code that are wrapped in a critical section
class SYNCBLOCK_Implementation
	{
	public:
	SYNCBLOCK_Implementation(CRITICAL_SECTION& rcs, BOOL bTry = FALSE) : m_bBlocked(TRUE)
		{
		m_pcs = &rcs;
		if (bTry)
			m_bBlocked = TryEnterCriticalSection(m_pcs);
		else
			EnterCriticalSection(m_pcs);
		};
	~SYNCBLOCK_Implementation()
		{
		if (m_bBlocked)
			LeaveCriticalSection(m_pcs);
		}
	BOOL IsBlocked() { return m_bBlocked; }

	private:
	SYNCBLOCK_Implementation(const SYNCBLOCK_Implementation&);  // Not supported
	SYNCBLOCK_Implementation& operator=(const SYNCBLOCK_Implementation&);  // Not supported
	CRITICAL_SECTION* m_pcs;
	BOOL m_bBlocked;
	};
// Class for creating blocks of code inside a SYNCBLOCK that are NOT wrapped in a critical section
class UNSYNCBLOCK_Implementation
	{
	public:
	UNSYNCBLOCK_Implementation(CRITICAL_SECTION& rcs)
		{
		m_pcs = &rcs;
		LeaveCriticalSection(m_pcs);
		}
	~UNSYNCBLOCK_Implementation()
		{
		EnterCriticalSection(m_pcs);
		}
	private:
	UNSYNCBLOCK_Implementation(const UNSYNCBLOCK_Implementation&);  // Not supported
	UNSYNCBLOCK_Implementation& operator=(const UNSYNCBLOCK_Implementation&);  // Not supported
	CRITICAL_SECTION* m_pcs;
	};
// Macros to make SYNCBLOCK and UNSYNCBLOCK easier to use
#define SYNCBLOCK(cs) SYNCBLOCK_Implementation SYNCBLOCK_Object(cs)
#define SYNCTRYBLOCK(cs) SYNCBLOCK_Implementation SYNCBLOCK_Object(cs, TRUE)
#define ISBLOCKED SYNCBLOCK_Object.IsBlocked()
#define UNSYNCBLOCK(cs) UNSYNCBLOCK_Implementation UNSYNCBLOCK_Object(cs)
// SYNCBLOCK2 is necessary in the case where you need to have code wrapped
// in two SYNCBLOCKs at once.  (Ideally, there would be a way to name the
// variables uniquely (i.e., by using the "__LINE__" preprocessor directive),
// but the "##" operator doesn't handle "XX##__LINE__" correctly (by
// design).)
#define SYNCBLOCK2(cs) SYNCBLOCK_Implementation SYNCBLOCK2_Object(cs)
#define UNSYNCBLOCK2(cs) UNSYNCBLOCK_Implementation UNSYNCBLOCK2_Object(cs)

// Class for creating blocks of code that are wrapped in a mutex
class GLOBAL_SYNCBLOCK_Implementation
	{
	public:
	GLOBAL_SYNCBLOCK_Implementation(HANDLE hMutex)
		{
		m_hMutex = hMutex;
		if(0 != m_hMutex)
			{
			WaitForSingleObject(m_hMutex, INFINITE);
			}
		}
	~GLOBAL_SYNCBLOCK_Implementation()
		{
		if(0 != m_hMutex)
			{
			ReleaseMutex(m_hMutex);
			}
		}
	private:
	GLOBAL_SYNCBLOCK_Implementation(const GLOBAL_SYNCBLOCK_Implementation&);  // Not supported
	GLOBAL_SYNCBLOCK_Implementation& operator=(const GLOBAL_SYNCBLOCK_Implementation&);  // Not supported
	HANDLE m_hMutex;
	};
// Macro to make GLOBAL_SYNCBLOCK easier to use
#define GLOBAL_SYNCBLOCK(cs) GLOBAL_SYNCBLOCK_Implementation GSB_##__LINE__(cs)

// Class to encapsulate loading a string from a module's resource section
#if defined(UNDER_CE) && !defined(RC_STRINGS_0_TERMINATED_TOOLBOX)
#pragma message("Define RC_STRINGS_0_TERMINATED_TOOLBOX if applicable.")
#endif  // defined(UNDER_CE) && !defined(RC_STRINGS_0_TERMINATED_TOOLBOX)
class ResourceString
	{
	public:
	ResourceString();
	ResourceString(HINSTANCE hInstance, UINT uID);
	const TCHAR* LoadResourceString(HINSTANCE hInstance, UINT uID);
	operator const TCHAR*();
	~ResourceString();
	private:
	ResourceString(const ResourceString&);  // Not supported
	ResourceString& operator=(const ResourceString&);  // Not supported
	TCHAR* m_psResource;
	};

// Class to tokenize an application's command-line (such as that returned by
// GetCommandLine())
class CommandLineTokenizer
	{
	public:
	CommandLineTokenizer();
	CommandLineTokenizer(const TCHAR* ptsCommandLine);
	~CommandLineTokenizer();
	bool SetCommandLine(const TCHAR* ptsCommandLine);
	TCHAR* NextParameter();
	private:
	CommandLineTokenizer(const CommandLineTokenizer&);  // Not supported
	CommandLineTokenizer& operator=(const CommandLineTokenizer&);  // Not supported
	TCHAR* m_ptsCommandLineCopy;
	TCHAR* m_ptsRemainingCommandLine;
	};

// Class to process command-line parameters and call appropriate functions
typedef bool (COMMAND_LINE_PARAMETER_HANDLER)(const TCHAR* const psParameterOptions);
class CommandLineParameterHandler
	{
	public:
	CommandLineParameterHandler(const TCHAR* const psCommandLine, const TCHAR** const psParameterStrings, COMMAND_LINE_PARAMETER_HANDLER** const pclphParameterHandlers, COMMAND_LINE_PARAMETER_HANDLER* const pclphUnknownParameterHandler);
	bool ProcessParameters();
	private:
	CommandLineParameterHandler(const CommandLineParameterHandler&);  // Not supported
	CommandLineParameterHandler& operator=(const CommandLineParameterHandler&);  // Not supported
	CommandLineTokenizer m_cltParameters;
	const TCHAR** m_psParameterStrings;
	COMMAND_LINE_PARAMETER_HANDLER** m_pclphParameterHandlers;
	COMMAND_LINE_PARAMETER_HANDLER* m_pclphUnknownParameterHandler;
	};

// Class to allow access to a string as an ANSI string
class AnsiString
	{
	public:
	AnsiString(const wchar_t* const psWide, const wchar_t pcEndOfString = L'\0');
	AnsiString(const char* const psAnsi, const char pcEndOfString = '\0');
	~AnsiString();
	operator char*()
		{
		if(0 != m_psAnsi)
			{
			return m_psAnsi;
			}
		else
			{
			return "";
			}
		}
	private:
	AnsiString(const AnsiString&);  // Not supported
	AnsiString& operator=(const AnsiString&);  // Not supported
	char* m_psAnsi;
	};

// Class to allow access to a string as a WIDE string
class WideString
	{
	public:
	WideString(const char* const psAnsi, const char pcEndOfString = '\0');
	WideString(const wchar_t* const psWide, const wchar_t pcEndOfString = L'\0');
	~WideString();
	operator wchar_t*()
		{
		if(0 != m_psWide)
			{
			return m_psWide;
			}
		else
			{
			return L"";
			}
		}
	private:
	WideString(const WideString&);  // Not supported
	WideString& operator=(const WideString&);  // Not supported
	wchar_t* m_psWide;
	};

#if defined(UNICODE) || defined(_UNICODE)
#define TString WideString
#else  // defined(UNICODE) || defined(_UNICODE)
#define TString AnsiString
#endif  // defined(UNICODE) || defined(_UNICODE)

// Class to allow access to a string as US ASCII chars
class USAsciiString
	{
	public:
	USAsciiString(const wchar_t* psWide);
	USAsciiString(const char* const psAnsi);
	~USAsciiString();
	operator char*()
		{
		if(0 != m_psUSAscii)
			{
			return m_psUSAscii;
			}
		else
			{
			return "";
			}
		}
	private:
	USAsciiString(const USAsciiString&);  // Not supported
	USAsciiString& operator=(const USAsciiString&);  // Not supported
	char* m_psUSAscii;
	};

// Class to provide a string that displays special characters (like '\r' and '\n')
class VerboseString
	{
	public:
	VerboseString(const TCHAR* const psString, const TCHAR cCR=TEXT('\r'), const TCHAR cLF=TEXT('\n'));
	~VerboseString();
	operator TCHAR*()
		{
		if(0 != m_psVerboseString)
			{
			return m_psVerboseString;
			}
		else
			{
			return TEXT("");
			}
		}
	private:
	VerboseString(const VerboseString&);  // Not supported
	VerboseString& operator=(const VerboseString&);  // Not supported
	TCHAR* m_psVerboseString;
	};

// Class to provide a string in printable format (with special characters displayed)
class PrintableString
	{
	public:
	PrintableString(const char* const psString, const unsigned int uiLength, const bool bVerbose=true, const char cCR='\r', const char cLF='\n');
	~PrintableString();
	operator char*()
		{
		if(0 != m_psPrintableString)
			{
			return m_psPrintableString;
			}
		else
			{
			return "";
			}
		}
	private:
	PrintableString(const PrintableString&);  // Not supported
	PrintableString& operator=(const PrintableString&);  // Not supported
	char* m_psPrintableString;
	};

// Class to provide a string in printable format (with special characters displayed)
class HexString
	{
	public:
	HexString(const char* const pcsString, const unsigned int uiLength);
	~HexString();
	operator char*()
		{
		if(0 != m_pcsHexString)
			{
			return m_pcsHexString;
			}
		else
			{
			return "";
			}
		}
	private:
	HexString(const HexString&);  // Not supported
	HexString& operator=(const HexString&);  // Not supported
	char* m_pcsHexString;
	};

// Class to safely handle interactions with a DLL
class LibraryLoader
	{
	public:
	LibraryLoader(const TCHAR* const psLibraryFileName)
		{
		m_hInstLibrary = 0;
		Load(psLibraryFileName);
		}
	~LibraryLoader()
		{
		Unload();
		}
	bool Load(const TCHAR* const psLibraryFileName)
		{
		Unload();
		m_hInstLibrary = (0 != psLibraryFileName) ? LoadLibrary(psLibraryFileName) : 0;
		return LoadSucceeded();
		}
	bool LoadSucceeded() const
		{
		return (m_hInstLibrary != 0);
		}
	void Unload()
		{
		if(0 != m_hInstLibrary)
			{
			FreeLibrary(m_hInstLibrary);
			m_hInstLibrary = 0;
			}
		}
	FARPROC GetProcedureAddress(const TCHAR* const psProcedureName) const
		{
		FARPROC fpReturn = 0;
		if(0 != m_hInstLibrary)
			{
#ifdef UNDER_CE
			fpReturn = GetProcAddress(m_hInstLibrary, psProcedureName);
#else // UNDER_CE
			fpReturn = GetProcAddress(m_hInstLibrary, AnsiString(psProcedureName));
#endif // UNDER_CE
			}
		return fpReturn;
		}
	private:
	LibraryLoader(const LibraryLoader&);  // Not supported
	LibraryLoader& operator=(const LibraryLoader&);  // Not supported
	HINSTANCE m_hInstLibrary;
	};

#ifdef IDC_WAIT
// Class to handle displaying and removing the wait-cursor
#if 0
class WaitCursor
	{
	public:
	WaitCursor(const HINSTANCE hInst = 0, const TCHAR* const psCursorNameOrNumber = IDC_WAIT)
		{
		m_hcOld = 0;
		m_bSetCursor = false;
		HCURSOR hcWait = LoadCursor(hInst, psCursorNameOrNumber);
		if(0 != hcWait)
			{
			m_hcOld = SetCursor(hcWait);
			m_bSetCursor = true;
			}
		}
	~WaitCursor()
		{
		Dismiss();
		}
	void Dismiss()
		{
		if(m_bSetCursor)
			{
			SetCursor(m_hcOld);
			m_bSetCursor = false;
			}
		}

	private:
	WaitCursor(const WaitCursor&);  // Not supported
	WaitCursor& operator=(const WaitCursor&);  // Not supported
	HCURSOR m_hcOld;
	bool m_bSetCursor;
	};
#endif
#endif // IDC_WAIT

// Class to manage an indeterminate number of things
// NOTE: NOT safe for classes that overload operator= or use copy-
// constructors (because of this class's use of memcpy)
template <class T> class GrowableThingCollection
	{
	public:
	// Constructor/destructor/operator overloads
	GrowableThingCollection(int iGrowSize = 10)
		{
		InitializeCriticalSection(&m_csData);
		InitializeCriticalSection(&m_csModify);
		m_ptArray = 0;
		m_iSlotsUsed = 0;
		m_iSlotsAllocated = 0;
		ASSERT(0 < iGrowSize);
		m_iGrowSize = (0 < iGrowSize) ? iGrowSize : 1;
		m_uiLockCount = 0;
		}
	GrowableThingCollection(const GrowableThingCollection& rgtc)
		{
		InitializeCriticalSection(&m_csData);
		InitializeCriticalSection(&m_csModify);
		CopyAnotherGrowableThingCollection(rgtc);
		}
	virtual ~GrowableThingCollection()
		{
		ASSERT(0 == m_uiLockCount);
		if(0 != m_ptArray)
			{
			LocalFree(m_ptArray);
			}
		/*
		m_ptArray = 0;
		m_iSlotsUsed = 0;
		m_iSlotsAllocated = 0;
		m_iGrowSize = 0;
		m_uiLockCount = 0;
		*/
		DeleteCriticalSection(&m_csModify);
		DeleteCriticalSection(&m_csData);
		}
	GrowableThingCollection& operator=(const GrowableThingCollection& rgtc)
		{
		if(0 != m_ptArray)
			{
			LocalFree(m_ptArray);
			}
		CopyAnotherGrowableThingCollection(rgtc);
		return *this;
		}
	// Methods that modify the collection
	virtual bool AddThing(const T t)
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csModify);
		EnterCriticalSection(&m_csData);
		if(0 == m_uiLockCount)
			{
			bSuccess = MakeRoomForAnotherThing();
			if(bSuccess)
				{
				m_ptArray[m_iSlotsUsed] = (T)t;
				m_iSlotsUsed++;
				}
			}
		LeaveCriticalSection(&m_csData);
		LeaveCriticalSection(&m_csModify);
		return bSuccess;
		}
	virtual bool InsertThing(const T t, const int i)
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csModify);
		EnterCriticalSection(&m_csData);
		if(0 == m_uiLockCount)
			{
			ASSERT((0 <= i) && (i <= m_iSlotsUsed));
			if((0 <= i) && (i <= m_iSlotsUsed))
				{
				bSuccess = MakeRoomForAnotherThing();
				if(bSuccess)
					{
					memmove(&(m_ptArray[i+1]), &(m_ptArray[i]), (m_iSlotsUsed-i)*sizeof(T));
					m_iSlotsUsed++;
					m_ptArray[i] = (T)t;
					}
				}
			}
		LeaveCriticalSection(&m_csData);
		LeaveCriticalSection(&m_csModify);
		return bSuccess;
		}
	virtual bool RemoveThingAtIndex(const int i)
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csModify);
		EnterCriticalSection(&m_csData);
		if(0 == m_uiLockCount)
			{
			ASSERT((0 <= i) && (i < m_iSlotsUsed));
			if((0 <= i) && (i < m_iSlotsUsed))
				{
				// Preserve ordering
				memmove(&(m_ptArray[i]), &(m_ptArray[i+1]), (m_iSlotsUsed-i-1)*sizeof(T));
				m_iSlotsUsed--;
				bSuccess = true;
				}
			}
		LeaveCriticalSection(&m_csData);
		LeaveCriticalSection(&m_csModify);
		return bSuccess;
		}
	virtual bool RemoveThing(const T t)
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csModify);
		EnterCriticalSection(&m_csData);
		if(0 == m_uiLockCount)
			{
			const int i = GetThingIndex(t);
			if(-1 != i)
				{
				// Preserve relative ordering of elements
				memmove(&(m_ptArray[i]), &(m_ptArray[i+1]), (m_iSlotsUsed-i-1)*sizeof(T));
				m_iSlotsUsed--;
				bSuccess = true;
				}
			}
		LeaveCriticalSection(&m_csData);
		LeaveCriticalSection(&m_csModify);
		return bSuccess;
		}
	virtual bool RemoveAllThings()
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csModify);
		EnterCriticalSection(&m_csData);
		if(0 == m_uiLockCount)
			{
			m_iSlotsUsed = 0;
			bSuccess = true;
			}
		LeaveCriticalSection(&m_csData);
		LeaveCriticalSection(&m_csModify);
		return bSuccess;
		}
	virtual bool SwapThingsAtIndices(const int i, const int j)
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csModify);
		EnterCriticalSection(&m_csData);
		if(0 == m_uiLockCount)
			{
			ASSERT((0 <= i) && (i < m_iSlotsUsed) && (0 <= j) && (j < m_iSlotsUsed));
			if((0 <= i) && (i < m_iSlotsUsed) && (0 <= j) && (j < m_iSlotsUsed))
				{
				T tTemp = m_ptArray[i];
				m_ptArray[i] = m_ptArray[j];
				m_ptArray[j] = tTemp;
				bSuccess = true;
				}
			}
		LeaveCriticalSection(&m_csData);
		LeaveCriticalSection(&m_csModify);
		return bSuccess;
		}
	// Methods that do not modify the collection
	virtual int GetSize()
		{
		EnterCriticalSection(&m_csData);
		const int iReturn = m_iSlotsUsed;
		LeaveCriticalSection(&m_csData);
		return iReturn;
		}
	virtual bool Lock()
		{
		EnterCriticalSection(&m_csData);
		m_uiLockCount++;
		ASSERT(0 < m_uiLockCount);  // Detect overflow
		LeaveCriticalSection(&m_csData);
		return true;  // Always locks
		}
	virtual bool Unlock()
		{
		EnterCriticalSection(&m_csData);
		ASSERT(0 != m_uiLockCount);
		if(0 != m_uiLockCount)
			{
			m_uiLockCount--;
			}
		LeaveCriticalSection(&m_csData);
		return (0 == m_uiLockCount);  // Return value answers "Unlocked?"
		}
	virtual bool BlockModificationByOtherThreads()
		{
		EnterCriticalSection(&m_csModify);
		return true;  // Always grabs the m_csModify CRITICAL_SECTION
		}
	virtual bool AllowModificationByOtherThreads()
		{
		LeaveCriticalSection(&m_csModify);
		return true;  // Always frees the m_csModify CRITICAL_SECTION
		}
	virtual T GetThingAtIndex(const int i)
		{
		T tReturn;
		memset(&tReturn, 0, sizeof(T));
		EnterCriticalSection(&m_csData);
		ASSERT((0 <= i) && (i < m_iSlotsUsed));
		if((0 <= i) && (i < m_iSlotsUsed))
			{
			tReturn = m_ptArray[i];
			}
		LeaveCriticalSection(&m_csData);
		return tReturn;
		}
	virtual bool SetThingAtIndex(const T t, const int i)
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csData);
		ASSERT((0 <= i) && (i < m_iSlotsUsed));
		if((0 <= i) && (i < m_iSlotsUsed))
			{
			m_ptArray[i] = t;
			bSuccess = true;
			}
		LeaveCriticalSection(&m_csData);
		return bSuccess;
		}
	virtual int GetThingIndex(const T t)
		{
		int iReturn = -1;
		EnterCriticalSection(&m_csData);
		// Count up to preserve relative ordering of elements
		for(int i = 0 ; i < m_iSlotsUsed ; i++)
			{
			if(0 == memcmp(&t, &(m_ptArray[i]), sizeof(T)))
				{
				iReturn = i;
				break;
				}
			}
		LeaveCriticalSection(&m_csData);
		return iReturn;
		}
	typedef bool (*GROWABLE_THING_COLLECTION_FILTER)(const T& rt, void* pvFilterData);
	virtual int GetFilteredThingIndex(GROWABLE_THING_COLLECTION_FILTER gtcfFilter, void* const pvFilterData)
		{
		ASSERT(0 != gtcfFilter);
		int iReturn = -1;
		EnterCriticalSection(&m_csData);
		// Count up to preserve relative ordering of elements
		for(int i = 0 ; (-1 == iReturn) && (i < m_iSlotsUsed) ; i++)
			{
			if(gtcfFilter(m_ptArray[i], pvFilterData))
				{
				iReturn = i;
				}
			}
		LeaveCriticalSection(&m_csData);
		return iReturn;
		}
	// Methods that do not modify the collection and work only when it is locked
	virtual T* GetPointerToThingAtIndex(const int i)
		{
		T* ptReturn = 0;
		EnterCriticalSection(&m_csData);
		ASSERT(0 < m_uiLockCount);
		if(0 < m_uiLockCount)
			{
			ASSERT((0 <= i) && (i < m_iSlotsUsed));
			if((0 <= i) && (i < m_iSlotsUsed))
				{
				ptReturn = &(m_ptArray[i]);
				}
			}
		LeaveCriticalSection(&m_csData);
		return ptReturn;
		}
	virtual T* GetPointerToThing(const T t)
		{
		T* ptReturn = 0;
		EnterCriticalSection(&m_csData);
		ASSERT(0 < m_uiLockCount);
		if(0 < m_uiLockCount)
			{
			for(int i = m_iSlotsUsed-1 ; (0 == ptReturn) && (0 <= i) ; i--)
				{
				if(0 == memcmp(&t, &(m_ptArray[i]), sizeof(T)))
					{
					ptReturn = &(m_ptArray[i]);
					}
				}
			}
		LeaveCriticalSection(&m_csData);
		return ptReturn;
		}

	protected:
	// Method to grow the storage when necessary
	virtual bool MakeRoomForAnotherThing()
		{
		bool bSuccess = true;
		ASSERT(0 == m_uiLockCount);
		if(m_iSlotsUsed == m_iSlotsAllocated)
			{
			T* const Oldm_ptArray = m_ptArray;
			const int iSlotsDesired = m_iSlotsAllocated+m_iGrowSize;
			if(0 == m_ptArray)
				{
				m_ptArray = (T*)LocalAlloc(LMEM_FIXED, iSlotsDesired*sizeof(T));
				}
			else
				{
				m_ptArray = (T*)LocalReAlloc(m_ptArray, iSlotsDesired*sizeof(T), LMEM_MOVEABLE);
				}
			if(0 == m_ptArray)
				{
				// Unable to allocate memory - keep old memory
				m_ptArray = Oldm_ptArray;
				bSuccess = false;
				}
			else
				{
				m_iSlotsAllocated = iSlotsDesired;
				}
			}
		return bSuccess;
		}
	void CopyAnotherGrowableThingCollection(const GrowableThingCollection& rgtc)
		{
		m_ptArray = (T*)LocalAlloc(LMEM_FIXED, rgtc.m_iSlotsAllocated*sizeof(T));
		if(0 != m_ptArray)
			{
			m_iSlotsUsed = rgtc.m_iSlotsUsed;
			m_iSlotsAllocated = rgtc.m_iSlotsAllocated;
			memcpy(m_ptArray, rgtc.m_ptArray, m_iSlotsUsed*sizeof(T));
			}
		else
			{
			m_iSlotsUsed = 0;
			m_iSlotsAllocated = 0;
			}
		m_iGrowSize = rgtc.m_iGrowSize;
		m_uiLockCount = 0;
		}

	CRITICAL_SECTION m_csData;
	CRITICAL_SECTION m_csModify;
	T* m_ptArray;
	int m_iSlotsUsed;
	int m_iSlotsAllocated;
	int m_iGrowSize;
	unsigned int m_uiLockCount;
	};

// Class to manage an indeterminate number of pointers
// Users should NOT call GrowableThingCollection methods for which there is a GrowablePointerCollection counterpart
template <class T> class GrowablePointerCollection : public GrowableThingCollection<T*>
	{
	public:
	// Constructor/destructor/operator overloads
	GrowablePointerCollection(int iGrowSize = 10) : GrowableThingCollection<T*>(iGrowSize)
		{
		m_uiBlockRemovesCount = 0;
		m_hRemoveAllowed = CreateEvent(0, FALSE, TRUE, 0);
		}
	GrowablePointerCollection(const GrowablePointerCollection& rgpc)
		{
		GrowableThingCollection<T*>::operator=(rgpc);
		m_uiBlockRemovesCount = 0;
		m_hRemoveAllowed = CreateEvent(0, FALSE, TRUE, 0);
		}
	~GrowablePointerCollection()
		{
		ASSERT(0 == m_uiBlockRemovesCount);
		if(0 != m_hRemoveAllowed)
			{
			CloseHandle(m_hRemoveAllowed);
			}
		/*
		m_uiBlockRemovesCount = 0;
		m_hRemoveAllowed = 0;
		*/
		}
	GrowablePointerCollection& operator=(const GrowablePointerCollection& rgpc)
		{
		GrowableThingCollection<T*>::operator=(rgpc);
		// Calling operator= for this class is dangerous if either of
		// BlockRemovalOfPointers or AllowRemovalOfPointers are used (due to
		// difficulties related with handling m_uiBlockRemovesCount and
		// m_hRemoveAllowed in all states)
		ASSERT((0 == m_uiBlockRemovesCount) && (0 == rgpc.m_uiBlockRemovesCount));
		return *this;
		}
	// Methods that modify the collection
	bool AddPointer(const T* const t)
		{
		ASSERT(0 != t);
		return GrowableThingCollection<T*>::AddThing((T*)t);
		}
	bool AddThing(const T /*t*/) { ASSERT(false); return false; }
	bool InsertPointer(const T* const t, const int i)
		{
		ASSERT(0 != t);
		return GrowableThingCollection<T*>::InsertThing((T*)t, i);
		}
	bool InsertThing(const T /*t*/, const int /*i*/) { ASSERT(false); return false; }
	bool RemovePointerAtIndex(const int i)
		{
		bool bSuccess = false;
		if((0 != m_hRemoveAllowed) && (WAIT_OBJECT_0 == WaitForSingleObject(m_hRemoveAllowed, INFINITE)))
			{
			bSuccess = GrowableThingCollection<T*>::RemoveThingAtIndex(i);
			SetEvent(m_hRemoveAllowed);
			}
		return bSuccess;
		}
	bool RemoveThingAtIndex(const int /*i*/) { ASSERT(false); return false; }
	bool RemovePointer(const T* const t)
		{
		bool bSuccess = false;
		if((0 != m_hRemoveAllowed) && (WAIT_OBJECT_0 == WaitForSingleObject(m_hRemoveAllowed, INFINITE)))
			{
			bSuccess = GrowableThingCollection<T*>::RemoveThing((T*)t);
			SetEvent(m_hRemoveAllowed);
			}
		return bSuccess;
		}
	bool RemoveThing(const T /*t*/) { ASSERT(false); return false; }
	bool RemoveAllPointers()
		{
		bool bSuccess = false;
		if((0 != m_hRemoveAllowed) && (WAIT_OBJECT_0 == WaitForSingleObject(m_hRemoveAllowed, INFINITE)))
			{
			bSuccess = GrowableThingCollection<T*>::RemoveAllThings();
			SetEvent(m_hRemoveAllowed);
			}
		return bSuccess;
		}
	bool RemoveAllThings() { ASSERT(false); return false; }
	bool SwapPointersAtIndices(const int i, const int j)
		{
		return GrowableThingCollection<T*>::SwapThingsIndices(i, j);
		}
	bool SwapThingsAtIndices(const int /*i*/, const int /*j*/) { ASSERT(false); return false; }
	// Methods that do not modify the collection
	bool BlockRemovalOfPointers()
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csData);
		m_uiBlockRemovesCount++;
		ASSERT(0 < m_uiBlockRemovesCount);  // Detect overflow
		// The first call to BlockRemovalOfPointers must force future calls to Remove* to block
		const bool bFirstCallToBlock = (1 == m_uiBlockRemovesCount);  // Must be protected by m_csData
		LeaveCriticalSection(&m_csData);  // Must leave m_csData so that calls to AllowRemovalOfPointers can proceed - see the declaration of m_hRemoveAllowed for an explanation of why it is not protected
		bSuccess = (!bFirstCallToBlock ||
		            ((0 != m_hRemoveAllowed) && (WAIT_OBJECT_0 == WaitForSingleObject(m_hRemoveAllowed, INFINITE))));
		return bSuccess;
		}
	bool AllowRemovalOfPointers()
		{
		bool bSuccess = false;
		EnterCriticalSection(&m_csData);
		ASSERT(0 != m_uiBlockRemovesCount);
		if(0 != m_uiBlockRemovesCount)
			{
			m_uiBlockRemovesCount--;
			// The last call to AllowRemovalOfPointers should permit calls to Remove* to execute
			bSuccess = ((0 == m_uiBlockRemovesCount) && (0 != m_hRemoveAllowed) && SetEvent(m_hRemoveAllowed));
			}
		LeaveCriticalSection(&m_csData);
		return bSuccess;  // Return value answers "Removal permitted?"
		}
	T* GetPointerAtIndex(const int i)
		{
		// For performance reasons (avoiding a call to memset),
		// provide a custom implementation of this method
		T* ptReturn = 0;
		EnterCriticalSection(&m_csData);
		ASSERT((0 <= i) && (i < m_iSlotsUsed));
		if((0 <= i) && (i < m_iSlotsUsed))
			{
			ptReturn = m_ptArray[i];
			}
		LeaveCriticalSection(&m_csData);
		return ptReturn;
		}
	T* GetThingAtIndex(const int /*i*/) { ASSERT(false); return 0; }
	bool SetPointerAtIndex(const T* const t, const int i)
		{
		return GrowableThingCollection<T*>::SetThingAtIndex((T*)t, i);
		}
	bool SetThingAtIndex(const T /*t*/, const int /*i*/) { ASSERT(false); return false; }
	int GetPointerIndex(const T* t)
		{
		// For performance reasons (avoiding multiple calls to memcmp),
		// provide a custom implementation of this method
		int iReturn = -1;
		EnterCriticalSection(&m_csData);
		// Count up to preserve relative ordering of elements
		for(int i = 0 ; i < m_iSlotsUsed ; i++)
			{
			if(t == m_ptArray[i])
				{
				iReturn = i;
				break;
				}
			}
		LeaveCriticalSection(&m_csData);
		return iReturn;
		}
	int GetThingIndex(const T /*t*/) { ASSERT(false); return -1; }
	int GetFilteredThingIndex(GROWABLE_THING_COLLECTION_FILTER /*gtcfFilter*/, void* const /*pvFilterData*/) { ASSERT(false); return -1; }
	// Methods that do not modify the collection and work only when it is locked
	T** GetPointerToThingAtIndex(const int /*i*/) { ASSERT(false); return 0; }
	T** GetPointerToThing(const T /*t*/) { ASSERT(false); return 0; }
	private:
	int m_uiBlockRemovesCount;
	HANDLE m_hRemoveAllowed;  // Does NOT need to be protected by a CRITICAL_SECTION because it does not change during the life of the object
	};


// Class to manage an indeterminate number of strings
class StringCollection
	{
	public:
	StringCollection();
	virtual ~StringCollection();
	virtual bool AddString(const TCHAR* const psNew, int *const piStringIndex = 0);
	virtual TCHAR* GetString(int i);
	virtual int GetSize();
	protected:
	GrowablePointerCollection<TCHAR> m_gpaStrings;
	private:
	StringCollection(const StringCollection&);  // Not supported
	StringCollection& operator=(const StringCollection&);  // Not supported
	};

// Class to manage an indeterminate number of strings which will be sorted
class SortedStringCollection : public StringCollection
	{
	typedef int (*CompareFunction)(const TCHAR*, const TCHAR*);
	public:
	SortedStringCollection(bool bCaseSensitive);
	virtual ~SortedStringCollection();
	virtual bool AddString(const TCHAR* const psNew, bool bAllowDuplicates = true);
	int FindStringIndex(const TCHAR* const psSearchString);
	private:
	SortedStringCollection(const SortedStringCollection&);  // Not supported
	SortedStringCollection& operator=(const SortedStringCollection&);  // Not supported
	CompareFunction m_sCompare;
	};

// Class to implement a checkpoint for thread synchronization
class CCheckPoint
	{
	public:
	CCheckPoint();
	~CCheckPoint();
	bool Init(const UINT nThreads);
	void Reached();  // Called by a thread to indicate that it reached the checkpoint
	bool Wait(const DWORD dwTimeout);  // Called by a thread to wait for other threads to reach the checkpoint
	private:
	CCheckPoint(const CCheckPoint&);  // Not supported
	CCheckPoint& operator=(const CCheckPoint&);  // Not supported
	UINT m_nCheck;
	CRITICAL_SECTION m_cs;
	HANDLE m_hEvent;
	UINT m_nThreads;
	bool m_fInitialized;
	};

// Binary search (from the C runtime)
#if IM_DBG
// Iulian Mocanu
// ifdefed as cause compiling warnings
void * __cdecl bsearch (const void *key, const void *base, size_t num, size_t width, int (__cdecl *compare)(const void *, const void *));
#endif

// Functions to check the validity of pointers
bool MemoryReadable(const void* pvMemory, const UINT uiMemorySize);
bool MemoryWriteable(void* pvMemory, const UINT uiMemorySize);
bool _tcsReadable(const TCHAR* ptsString);
bool _tcsWriteable(TCHAR* ptsString);
bool strReadable(const char* pcsString);
bool strWriteable(char* pcsString);
bool wcsReadable(const WCHAR* pwsString);
bool wcsWriteable(WCHAR* pwsString);

// Macro to make translating a bool to a string easy
#define BOOL_VALUE_TO_STRING(b) ((b) ? TEXT("true") : TEXT("false"))

// Macros to make translating a DWORD value to a string easy
#define DWORD_VALUE_TO_STRING_CONVERTER_PROLOG(n) \
	TCHAR* n(const DWORD dwDWORD, TCHAR* const psBuffer, const size_t stBufferSize) \
	{ \
	ASSERT(0 != psBuffer); \
	switch(dwDWORD) \
		{
#define HANDLE_DWORD_VALUE(v) case v: _tcsncpyz(psBuffer, TEXT(#v), stBufferSize); break;
#define DWORD_VALUE_TO_STRING_CONVERTER_EPILOG(n) \
		default: \
			psBuffer[0] = TEXT('\0'); \
			break; \
		} \
	return psBuffer; \
	}
#define EXTERN_DWORD_VALUE_TO_STRING_CONVERTER(n) \
	extern TCHAR* n(const DWORD dwDWORD, TCHAR* const psBuffer, const size_t stBufferSize);

// Macros to make translating a DWORD mask (potentially multiple values) to a string easy
#define DWORD_MASK_TO_STRING_CONVERTER_PROLOG(n) \
	TCHAR* n(const DWORD dwDWORD, TCHAR* const psBuffer, const size_t stBufferSize) \
	{ \
	ASSERT(0 != psBuffer); \
	bool bOutputAlready = false; \
	_tcsncpyz(psBuffer, TEXT("("), stBufferSize);
#define HANDLE_DWORD_MASK(m) \
	if(0 != (m & dwDWORD)) \
		{ \
		if(bOutputAlready) \
			{ \
			_tcsncatz(psBuffer, TEXT(" | "), stBufferSize); \
			} \
		_tcsncatz(psBuffer, TEXT(#m), stBufferSize); \
		bOutputAlready = true; \
		}
#define DWORD_MASK_TO_STRING_CONVERTER_EPILOG(n) \
	_tcsncatz(psBuffer, TEXT(")"), stBufferSize); \
	return psBuffer; \
	}
#define EXTERN_DWORD_MASK_TO_STRING_CONVERTER(n) \
	extern TCHAR* n(const DWORD dwDWORD, TCHAR* const psBuffer, const size_t stBufferSize);

// Class to make handling multiple tasks/threads easier
class TaskList
	{
	public:
	typedef bool (*TaskListTask)(void* pvTaskInformation);
	typedef unsigned int TASK_ID;
	enum TaskListUrgency { URGENCY_LOW, URGENCY_NORMAL, URGENCY_HIGH };
	TaskList(const unsigned int uiMaxNumberWorkerThreads = 0);
	~TaskList();
	bool AddTask(TASK_ID* ptidTaskID, TaskListTask tltTask, void* pvTaskInformation, const TaskListUrgency tluUrgency = URGENCY_NORMAL);
	bool RemoveTask(const TASK_ID tidTaskID);
	unsigned int TasksRemaining();
	private:
	TaskList(const TaskList&);  // Not supported
	TaskList& operator=(const TaskList&);  // Not supported
	bool AddWorkerThread();
	friend DWORD WINAPI TaskListThreadProc(LPVOID lpParameter);
	bool m_bInitialized;
	const unsigned int m_uiMaxNumberWorkerThreads;
	GrowableThingCollection<HANDLE> m_hWorkerThreads;
	HANDLE m_hTaskEvent;
	HANDLE m_hExitEvent;
	LONG m_lThreadsWorking;
	TASK_ID m_tidNextTaskID;
	struct TaskListTaskData
		{
		TASK_ID tidTaskID;
		TaskListTask tltTask;
		void* pvTaskInformation;
		};
	GrowableThingCollection<TaskListTaskData> m_gtcHighUrgencyTasks;
	GrowableThingCollection<TaskListTaskData> m_gtcNormalUrgencyTasks;
	GrowableThingCollection<TaskListTaskData> m_gtcLowUrgencyTasks;
	CRITICAL_SECTION m_cs;
	};

// Class to avoid doing unnecessary and repetitive allocations of the same data type
template <class T> class ObjectCache
	{
	public:
	ObjectCache()
		{
		InitializeCriticalSection(&m_cs);
		}
	~ObjectCache()
		{
		ASSERT(0 == m_gpcObjectsUsed.GetSize());
		for(int i = m_gpcObjectsUsed.GetSize()-1 ; 0 <= i ; i--)
			{
			LocalFree(m_gpcObjectsUsed.GetPointerAtIndex(i));
			}
		for(i = m_gpcObjectsFree.GetSize()-1 ; 0 <= i ; i--)
			{
			LocalFree(m_gpcObjectsFree.GetPointerAtIndex(i));
			}
		DeleteCriticalSection(&m_cs);
		}
	T* AllocateObject()
		{
		SYNCBLOCK(m_cs);
		T* pReturn = 0;
		const int iFreeObjects = m_gpcObjectsFree.GetSize();
		if(0 < iFreeObjects)
			{
			pReturn = m_gpcObjectsFree.GetPointerAtIndex(iFreeObjects-1);
			if(m_gpcObjectsUsed.AddPointer(pReturn))
				{
				m_gpcObjectsFree.RemovePointerAtIndex(iFreeObjects-1);
				}
			else
				{
				pReturn = 0;
				}
			}
		else
			{
			pReturn = (T*)LocalAlloc(0, sizeof(T));
			if(!m_gpcObjectsUsed.AddPointer(pReturn))
				{
				LocalFree(pReturn);
				pReturn = 0;
				}
			}
		return pReturn;
		}
	void FreeObject(const T* pT)
		{
		if(0 != pT)
			{
			SYNCBLOCK(m_cs);
			const int iPointerIndex = m_gpcObjectsUsed.GetPointerIndex(pT);
			ASSERT(-1 != iPointerIndex);
			if(-1 != iPointerIndex)
				{
				if(m_gpcObjectsFree.AddPointer(pT))
					{
					m_gpcObjectsUsed.RemovePointerAtIndex(iPointerIndex);
					}
				}
			}
		}
	private:
	ObjectCache(const ObjectCache&);  // Not supported
	ObjectCache& operator=(const ObjectCache&);  // Not supported
	GrowablePointerCollection<T> m_gpcObjectsFree;
	GrowablePointerCollection<T> m_gpcObjectsUsed;
	CRITICAL_SECTION m_cs;
	};

// Class to avoid doing unnecessary and repetitive allocations of events
class EventCache
	{
	public:
	EventCache(const LPSECURITY_ATTRIBUTES lpEventAttributes, const BOOL bManualReset, const BOOL bInitialState, const LPCTSTR lpName) :
		m_lpEventAttributes(lpEventAttributes), m_bManualReset(bManualReset), m_bInitialState(bInitialState), m_lpName(lpName)
		{
		InitializeCriticalSection(&m_cs);
		}
	~EventCache()
		{
		ASSERT(0 == m_gtcEventsUsed.GetSize());
		int i;
		for(i = m_gtcEventsUsed.GetSize()-1 ; 0 <= i ; i--)
			{
			CloseHandle(m_gtcEventsUsed.GetThingAtIndex(i));
			}
		for(i = m_gtcEventsFree.GetSize()-1 ; 0 <= i ; i--)
			{
			CloseHandle(m_gtcEventsFree.GetThingAtIndex(i));
			}
		DeleteCriticalSection(&m_cs);
		}
	HANDLE AllocateEvent()
		{
		SYNCBLOCK(m_cs);
		HANDLE hReturn = 0;
		const int iFreeEvents = m_gtcEventsFree.GetSize();
		if(0 < iFreeEvents)
			{
			hReturn = m_gtcEventsFree.GetThingAtIndex(iFreeEvents-1);
			if(m_gtcEventsUsed.AddThing(hReturn))
				{
				m_gtcEventsFree.RemoveThingAtIndex(iFreeEvents-1);
				}
			else
				{
				hReturn = 0;
				}
			}
		else
			{
			hReturn = CreateEvent(m_lpEventAttributes, m_bManualReset, m_bInitialState, m_lpName);
			if(0 != hReturn)
				{
				if(!m_gtcEventsUsed.AddThing(hReturn))
					{
					CloseHandle(hReturn);
					hReturn = 0;
					}
				}
			}
		return hReturn;
		}
	void FreeEvent(const HANDLE h)
		{
		if(0 != h)
			{
			SYNCBLOCK(m_cs);
			const int iThingIndex = m_gtcEventsUsed.GetThingIndex(h);
			ASSERT(-1 != iThingIndex);
			if(-1 != iThingIndex)
				{
				if(m_gtcEventsFree.AddThing(h))
					{
					m_gtcEventsUsed.RemoveThingAtIndex(iThingIndex);
					}
				}
			}
		}
	private:
	EventCache(const EventCache&);  // Not supported
	EventCache& operator=(const EventCache&);  // Not supported
	GrowableThingCollection<HANDLE> m_gtcEventsFree;
	GrowableThingCollection<HANDLE> m_gtcEventsUsed;
	CRITICAL_SECTION m_cs;
	const LPSECURITY_ATTRIBUTES m_lpEventAttributes;
	const BOOL m_bManualReset;
	const BOOL m_bInitialState;
	const LPCTSTR m_lpName;
	};

// Class to simplify the task of starting and stopping a worker thread
class WorkerThread
	{
	public:
	typedef DWORD (*WORKER_THREAD_PROC)(LPVOID pParameter, HANDLE hThreadShouldExitEvent);
	WorkerThread(WORKER_THREAD_PROC const wtpWorkerThreadProc, LPVOID const lpParameter, const DWORD dwWaitTimeout);
	~WorkerThread();
	bool StartWorkerThread();
	bool StopWorkerThread();
	private:
	WorkerThread(const WorkerThread&);  // Not supported
	WorkerThread& operator=(const WorkerThread&);  // Not supported
	struct WorkerThreadProcData
		{
		WORKER_THREAD_PROC wtpWorkerThreadProc;
		LPVOID lpParameter;
		HANDLE hThreadShouldExitEvent;
		};
	static DWORD WINAPI RunWorkerThreadProc(LPVOID lpParameter);
	WORKER_THREAD_PROC m_wtpWorkerThreadProc;
	LPVOID m_lpParameter;
	DWORD m_dwWaitTimeout;
	HANDLE m_hThread;
	HANDLE m_hThreadShouldExitEvent;
	};

// Class to simplify task of memory-mapping a file for reading
class MemoryMappedFileData
	{
	public:
	MemoryMappedFileData();
	~MemoryMappedFileData();
	bool Initialize(const TCHAR* const ptsFileName);
	DWORD GetMappedFileSize() const
		{
		return m_dwFileSize;
		}
	LPCVOID GetMappedFileData() const
		{
		return m_pvViewOfFile;
		}
	private:
	MemoryMappedFileData(const MemoryMappedFileData&);  // Not supported
	MemoryMappedFileData& operator=(const MemoryMappedFileData&);  // Not supported
	bool bInitialized;
	HANDLE m_hFile;
	HANDLE m_hFileMapping;
	LPCVOID m_pvViewOfFile;
	DWORD m_dwFileSize;
	};

// Class to simplify the task of building a string up from other strings
class StringBuffer
	{
	public:
	StringBuffer(const size_t stExtraAllocationLength = 100);
	~StringBuffer();
	bool Set(const TCHAR* const ptsString);
	bool Append(const TCHAR* const ptsString);
	bool Append(const TCHAR* const ptsString, const size_t stNumberCharacters);
	void Empty();
	void FreeMemory();
	const TCHAR* GetString() const
		{
		return ((0 == m_ptsString) ? TEXT("") : m_ptsString);
		}
	operator const TCHAR*() const
		{
		return ((0 == m_ptsString) ? TEXT("") : m_ptsString);
		}
	private:
	StringBuffer(const StringBuffer&);  // Not supported
	StringBuffer& operator=(const StringBuffer&);  // Not supported
	bool EnsureSpaceToAddStringLength(const size_t stStringLength);
	const size_t m_stExtraAllocationLength;
	TCHAR* m_ptsString;
	size_t m_stStringLength;
	size_t m_stUsedLength;
	};



//
// Wrapper classes for events.
//

/*
class CEvent
{
protected:
    HANDLE  m_hEvent;

public:
    CEvent()
    {
        m_hEvent = NULL;
    }

    virtual ~CEvent()
    {
        if (m_hEvent)
        {
            CloseHandle(m_hEvent);
        }
    }

    BOOL Init(BOOL bManualReset, BOOL bInitialState, LPTSTR lpName = NULL)
    {
        m_hEvent = CreateEvent(NULL, bManualReset, bInitialState, lpName);
        return (NULL != m_hEvent);
    }

    BOOL Ready() const
    {
        return (NULL != m_hEvent);
    }

    BOOL Wait(DWORD dwTimeout = INFINITE) const
    {
        ASSERT(Ready());
        return (WAIT_OBJECT_0 == WaitForSingleObject(m_hEvent, dwTimeout));
    }

    void Set() const
    {
        ASSERT(Ready());
        SetEvent(m_hEvent);
    }

    void Reset() const
    {
        ASSERT(Ready());
        ResetEvent(m_hEvent);
    }

    HANDLE GetHandle() const
    {
        return m_hEvent;
    }
};

class CUniquelyNamedEvent : public CEvent
{
private:
    TCHAR   m_tszEventName[MAX_PATH];

public:
    CUniquelyNamedEvent() : CEvent()
    {
        m_tszEventName[0] = TEXT('\0');
    }

    BOOL Init(BOOL bManualReset, BOOL bInitialState, LPTSTR lpPrefix)
    {
        if (!lpPrefix)
            lpPrefix = TEXT("");
        
        HANDLE hEvent;
        DWORD dwTick = GetTickCount();
        for( ; ; )  // Forever...
        {
            (void)_sntprintfz(m_tszEventName, MAX_PATH, TEXT("%s%x"), lpPrefix, dwTick);
            hEvent = CreateEvent(NULL, bManualReset, bInitialState, m_tszEventName);
            if (!hEvent)
            {
                return FALSE;
            }
            else if (ERROR_ALREADY_EXISTS == GetLastError())
            {
                CloseHandle(hEvent);
                dwTick++;
            }
            else
            {
                m_hEvent = hEvent;
                break;
            }
        }

        return TRUE;
    }

    const TCHAR * GetName()
    {
        return m_tszEventName;
    }
};

class COneTimeEvent : CEvent
{
private:
    BOOL    m_bAlreadyHappened;

public:
    COneTimeEvent() : CEvent()
    {
        m_bAlreadyHappened = FALSE;
    }

    BOOL Init()
    {
        return CEvent::Init(TRUE, FALSE, NULL);
    }

    BOOL Wait(DWORD dwTimeout = INFINITE)
    {
        return CEvent::Wait(dwTimeout);
    }

    void Set()
    {
        if (!m_bAlreadyHappened)
        {
            CEvent::Set();
            m_bAlreadyHappened = TRUE;
        }
    }
};
*/

#if defined(UNDER_CE)

// Implementation of Win32 APIs for CE
WINBASEAPI
VOID
WINAPI
GetSystemTimeAsFileTime(
    __out LPFILETIME lpSystemTimeAsFileTime
    );

#endif // defined(UNDER_CE)


#endif  // !defined(TOOL_BOX_HEADER)
