// ------------------------------------------------------------------------------------ //
//																						//
//	File: Asura_PC_WindowsRegistry.cpp													//
//																						//
//	Description: This supplies access to the window registry							//
//																						//
//	Created: Steve Keen & Mark Parry - 25/02/08											//
//																						//
//	Copyright (C) 2008 Rebellion, All Rights Reserved.									//
// ------------------------------------------------------------------------------------ //

#include "Core/Asura.h"

#ifdef ASURA_PC_SUPPORT_WINDOWS_REGISTRY

#include "Registry/Asura_PC_WindowsRegistry.h"
#include "Core/Asura_Windows.h"

// -------------------------------------------------------------------------------------

HKEY Asura_PC_WindowsRegistry::m_hDefaultMasterKeyHandle = HKEY_LOCAL_MACHINE;

// -------------------------------------------------------------------------------------

Asura_PC_WindowsRegistry::Asura_PC_WindowsRegistry()
{
	m_hSubKeyHandle	= NULL;
	m_bSubKeyOpen	= false;

	m_uValueTypeUnprocessed			= REG_NONE;
	m_iValueSize					= 0;
	m_eValueTypeProcessed			= ASURA_WINDOWS_REGISTRY_VALUE_TYPE_UNKNOWN;
	m_bCreatedSubKeyAlreadyExisted	= false;
}

// -------------------------------------------------------------------------------------

Asura_PC_WindowsRegistry::~Asura_PC_WindowsRegistry()
{
	CloseSubKey();
}

// -------------------------------------------------------------------------------------

HKEY Asura_PC_WindowsRegistry::GetDefaultMasterKey(void)
{
	return m_hDefaultMasterKeyHandle;
}

// -------------------------------------------------------------------------------------

void Asura_PC_WindowsRegistry::SetDefaultMasterKey( HKEY hDefaultMasterKeyHandle)
{
	m_hDefaultMasterKeyHandle = hDefaultMasterKeyHandle;
}

// -------------------------------------------------------------------------------------

void Asura_PC_WindowsRegistry::SetDefaultMasterKey_ClassesRoot(void)
{
	m_hDefaultMasterKeyHandle = HKEY_CLASSES_ROOT;
}

// -------------------------------------------------------------------------------------

void Asura_PC_WindowsRegistry::SetDefaultMasterKey_CurrentUser(void)
{
	m_hDefaultMasterKeyHandle = HKEY_CURRENT_USER;
}

// -------------------------------------------------------------------------------------

void Asura_PC_WindowsRegistry::SetDefaultMasterKey_LocalMachine(void)
{
	m_hDefaultMasterKeyHandle = HKEY_LOCAL_MACHINE;
}

// -------------------------------------------------------------------------------------

void Asura_PC_WindowsRegistry::SetDefaultMasterKey_Users(void)
{
	m_hDefaultMasterKeyHandle = HKEY_USERS;
}

// -------------------------------------------------------------------------------------

HKEY Asura_PC_WindowsRegistry::GetMasterKeyClassesRoot(void)
{
	return HKEY_CLASSES_ROOT;
}

// -------------------------------------------------------------------------------------

HKEY Asura_PC_WindowsRegistry::GetMasterKeyCurrentUser(void)
{
	return HKEY_CURRENT_USER;
}

// -------------------------------------------------------------------------------------

HKEY Asura_PC_WindowsRegistry::GetMasterKeyLocalMachine(void)
{
	return HKEY_LOCAL_MACHINE;
}

// -------------------------------------------------------------------------------------

HKEY Asura_PC_WindowsRegistry::GetMasterKeyUsers(void)
{
	return HKEY_USERS;
}

// -------------------------------------------------------------------------------------

// -------------------------------------------------------------------------------------
//tidy the subKey (remove '/' off the end if necessary, some versions of windows don't like it!)
//----------------------------------------------------------------------------------------------
//	In:
//		pszOutputSubKey, where to store the subKey (should be at least eTidySubKeySize characters)
//		pszSubKey, the subKey to tidy
//		masterKeyHandle&, so we can override the master key handle
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::TidySubKey(char* const pszOutputSubKey, const char* const pszSubKey, HKEY& hMasterKeyHandle)
{
	if( pszOutputSubKey == NULL)
	{
		return(false);
	}
	pszOutputSubKey[0] = 0;
	if( (pszSubKey == NULL) || (pszSubKey[0] == 0) )
	{
		return false;
	}

	const char* s = pszSubKey;
	while( OverrideKeyHandle( /*&*/s, hMasterKeyHandle ) )
	{
	}
	strcpy_s( pszOutputSubKey, eTidySubKeySize, s );

	int iStringLength = (int)strlen(pszOutputSubKey);
	while( iStringLength > 0 )
	{
		const char lastChar = pszOutputSubKey[iStringLength - 1];
		if( ( lastChar != '\\' ) && ( lastChar != '/' ) )
		{
			break;
		}
		iStringLength--;
		pszOutputSubKey[iStringLength] = 0;
	}
	
	return true;
}

// -------------------------------------------------------------------------------------

bool Asura_PC_WindowsRegistry::OverrideKeyHandle(const char* &pszSubKey, HKEY& hMasterKeyHandle)
{
	if (OverrideKeyHandle( pszSubKey, hMasterKeyHandle, "HKEY_CLASSES_ROOT",	HKEY_CLASSES_ROOT))
	{
		return true;
	}
	if (OverrideKeyHandle( pszSubKey, hMasterKeyHandle, "HKEY_CURRENT_USER",	HKEY_CURRENT_USER))
	{
		return true;
	}
	if (OverrideKeyHandle( pszSubKey, hMasterKeyHandle, "HKEY_LOCAL_MACHINE",	HKEY_LOCAL_MACHINE))
	{
		return true;
	}
	if (OverrideKeyHandle( pszSubKey, hMasterKeyHandle, "HKEY_USERS",			HKEY_USERS))
	{
		return true;
	}

	return false;
}

// -------------------------------------------------------------------------------------

bool Asura_PC_WindowsRegistry::OverrideKeyHandle(const char* &pszSubKey, HKEY& hMasterKeyHandle, const char* const pszOverrideName, HKEY hOverrideMasterKeyHandle)
{
	if( (pszSubKey != NULL) && (pszSubKey[0] != 0) )
	{
		const int iOverrideNameLength = (int)strlen(pszOverrideName);
		if( _strnicmp( pszSubKey, pszOverrideName, iOverrideNameLength ) == 0 )
		{
			pszSubKey += iOverrideNameLength;
			while( (pszSubKey[0]=='\\') || (pszSubKey[0]=='/') )
			{
				pszSubKey++;
			}
			hMasterKeyHandle = hOverrideMasterKeyHandle;
			return true;
		}
	}

	return false;
}

// -------------------------------------------------------------------------------------
//close a registry subkey
// -------------------------------------------------------------------------------------
//	In:
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::CloseSubKey(void)
{
	if (m_bSubKeyOpen)
	{
		const LONG lastError = ::RegCloseKey((HKEY)m_hSubKeyHandle);
		m_bSubKeyOpen	= false;
		m_hSubKeyHandle	= NULL;

		m_uValueTypeUnprocessed			= REG_NONE;
		m_iValueSize					= 0;
		m_eValueTypeProcessed			= ASURA_WINDOWS_REGISTRY_VALUE_TYPE_UNKNOWN;
		m_bCreatedSubKeyAlreadyExisted	= false;

		if (lastError != ERROR_SUCCESS)
		{
			Asura_Assert( lastError == ERROR_SUCCESS, "Asura_PC_WindowsRegistry::CloseSubKey, ::RegCloseKey FAILED");
			return false;
		}
	}
	return true;
}

// -------------------------------------------------------------------------------------
//open a registry subkey
// -------------------------------------------------------------------------------------
//	In:
//		subKey, the subkey to open
//		masterKeyHandle, the master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::OpenSubKey(const char* const pszSubKey, HKEY hMasterKeyHandle /* = m_hDefaultMasterKeyHandle */)
{
	//close any currently open subkey
	CloseSubKey();

	char acTidiedSubKey[eTidySubKeySize];
	if (!TidySubKey( acTidiedSubKey, pszSubKey, hMasterKeyHandle))
	{
		return false;
	}

	//open the requested subkey
	HKEY hSubKeyHandle = NULL;
	const LONG lastError = ::RegOpenKeyExA( hMasterKeyHandle, acTidiedSubKey, 0, KEY_ALL_ACCESS, &hSubKeyHandle);
	if (lastError != ERROR_SUCCESS)
	{
		if (lastError != ERROR_FILE_NOT_FOUND)	//not found
		{
			Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::OpenSubKey '%s(%s)', ::RegOpenKeyExA FAILED", pszSubKey, acTidiedSubKey));
		}
		return false;
	}
	m_hSubKeyHandle = hSubKeyHandle;
	m_bSubKeyOpen = true;
	return true;
}

// -------------------------------------------------------------------------------------
//create a registry subkey
//--------------------------------------------------------------------------------------
//	In:
//		subKey, the subkey to create
//		masterKeyHandle, the master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::CreateSubKey(const char* const pszSubKey, HKEY hMasterKeyHandle /* = m_hDefaultMasterKeyHandle */)
{
	//close any currently open subkey
	CloseSubKey();

	char acTidiedSubKey[eTidySubKeySize];
	if (!TidySubKey( acTidiedSubKey, pszSubKey, hMasterKeyHandle))
	{
		return false;
	}

	//create the requested subkey
	DWORD dwDisposition;
	HKEY hSubKeyHandle = NULL;
	const LONG lastError = ::RegCreateKeyExA( hMasterKeyHandle, acTidiedSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, 
												KEY_ALL_ACCESS, NULL, &hSubKeyHandle, &dwDisposition);
	if (lastError != ERROR_SUCCESS)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::CreateSubKey '%s(%s)', ::RegCreateKeyExA FAILED", pszSubKey, acTidiedSubKey));
//		EI_ERROR("Asura_PC_WindowsRegistry::CreateSubKey '%s(%s)', ::RegCreateKeyExA FAILED, %s\n", subKey, tidiedSubKey, EI_SYSTEM_ERROR_STRING(lastError));
		return false;
	}
	m_hSubKeyHandle = hSubKeyHandle;
	m_bSubKeyOpen = true;
	m_bCreatedSubKeyAlreadyExisted = (dwDisposition == REG_OPENED_EXISTING_KEY);

	return true;
}

// -------------------------------------------------------------------------------------
//check if key exists
// -------------------------------------------------------------------------------------
//see if a key exists
//	In:
//		subKey, the subkey to create
//		masterKeyHandle, the master key
//	Out:
//		returns true if the key exists

bool Asura_PC_WindowsRegistry::DoesSubKeyExists(const char* const pszSubKey, HKEY hMasterKeyHandle /* = m_hDefaultMasterKeyHandle */)
{
	Asura_PC_WindowsRegistry xTemp;
	//see if we can open it
	if( xTemp.OpenSubKey( pszSubKey, hMasterKeyHandle))
	{
		xTemp.CloseSubKey();
		return true;
	}
	return false;
}

// -------------------------------------------------------------------------------------
//Delete a registry subkey
//!!!  BE CAREFULL WITH THIS CALL  !!!
//it deletes all levels below the subkey, so deleting a main subkey could be very bad news
// -------------------------------------------------------------------------------------
//	In:
//		subKey, the subkey to delete
//		masterKeyHandle, the master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::DeleteSubKey(const char* const pszSubKey, HKEY hMasterKeyHandle /* = m_hDefaultMasterKeyHandle */)
{
	char acTidiedSubKey[eTidySubKeySize];
	if (!TidySubKey( acTidiedSubKey, pszSubKey, hMasterKeyHandle))
	{
		return false;
	}

	//Delete the requested subkey
	const LONG lastError = ::RegUnLoadKeyA( hMasterKeyHandle, acTidiedSubKey);
	if (lastError != ERROR_SUCCESS)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::DeleteSubKey '%s(%s)', ::RegUnLoadKeyA FAILED", pszSubKey, acTidiedSubKey));
//		EI_ERROR("Asura_PC_WindowsRegistry::DeleteSubKey '%s(%s)', ::RegUnLoadKeyA FAILED, %s\n", subKey, tidiedSubKey, EI_SYSTEM_ERROR_STRING(lastError));
		return false;
	}
	return true;
}

// -------------------------------------------------------------------------------------
//get the value type, processed value type and value data size of the ValueName
//	(the subkey must have been previously opened)
// -------------------------------------------------------------------------------------
//	In:
//		valueName, the keyvalue to get information for
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::GetValueTypeAndSizeFromOpen(const char* const pszValueName)
{
	if (!m_bSubKeyOpen)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::GetValueTypeAndSizeFromOpen '%s', subkey not open", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::GetValueTypeAndSizeFromOpen '%s', subkey not open\n", valueName);
		return false;
	}

	//get the information
	DWORD dwValueType;
	DWORD dwValueSize;
	const LONG lastError = ::RegQueryValueExA((HKEY)m_hSubKeyHandle, pszValueName, NULL, &dwValueType, NULL, &dwValueSize);
	if (lastError != ERROR_SUCCESS)
	{
		if (lastError != ERROR_FILE_NOT_FOUND)	//not found
		{
			Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::GetValueTypeAndSizeFromOpen '%s', ::RegQueryValueExA FAILED", pszValueName));
//			EI_ERROR("Asura_PC_WindowsRegistry::GetValueTypeAndSizeFromOpen '%s', ::RegQueryValueExA FAILED, %s\n", valueName, EI_SYSTEM_ERROR_STRING(lastError));
		}

		m_uValueTypeUnprocessed	= REG_NONE;
		m_iValueSize			= 0;
		m_eValueTypeProcessed	= ASURA_WINDOWS_REGISTRY_VALUE_TYPE_ERROR;
		return false;
	}

	m_uValueTypeUnprocessed	= (u_int)dwValueType;
	m_iValueSize				= (int)dwValueSize;

	switch( dwValueType)
	{
		case REG_EXPAND_SZ:
		case REG_MULTI_SZ:
		case REG_SZ:
		case REG_LINK:
			m_eValueTypeProcessed = ASURA_WINDOWS_REGISTRY_VALUE_TYPE_STRING;
			break;

		case REG_DWORD:
			m_eValueTypeProcessed = ASURA_WINDOWS_REGISTRY_VALUE_TYPE_NUMBER;
			break;

		case REG_BINARY:
			m_eValueTypeProcessed = ASURA_WINDOWS_REGISTRY_VALUE_TYPE_BINARY;
			break;

		default:
			m_eValueTypeProcessed = ASURA_WINDOWS_REGISTRY_VALUE_TYPE_UNSUPPORTED;
			break;
	}
	return true;
}

// -------------------------------------------------------------------------------------

ASURA_WINDOWS_REGISTRY_VALUE_TYPE Asura_PC_WindowsRegistry::GetProcessedValueType(const u_int uValueTypeUnprocessed)
{
	switch( uValueTypeUnprocessed)
	{
		case REG_EXPAND_SZ:
		case REG_MULTI_SZ:
		case REG_SZ:
		case REG_LINK:
			return(ASURA_WINDOWS_REGISTRY_VALUE_TYPE_STRING);
		case REG_DWORD:
			return(ASURA_WINDOWS_REGISTRY_VALUE_TYPE_NUMBER);
		case REG_BINARY:
			return(ASURA_WINDOWS_REGISTRY_VALUE_TYPE_BINARY);
		default:
			return(ASURA_WINDOWS_REGISTRY_VALUE_TYPE_UNSUPPORTED);
	}
}

// -------------------------------------------------------------------------------------

const char* Asura_PC_WindowsRegistry::GetProcessedValueTypeString(const ASURA_WINDOWS_REGISTRY_VALUE_TYPE eValueType)
{
	switch( eValueType)
	{
		case ASURA_WINDOWS_REGISTRY_VALUE_TYPE_UNKNOWN:
			return "unknown";
		case ASURA_WINDOWS_REGISTRY_VALUE_TYPE_ERROR:
			return "error";
		case ASURA_WINDOWS_REGISTRY_VALUE_TYPE_NUMBER:
			return "number";
		case ASURA_WINDOWS_REGISTRY_VALUE_TYPE_STRING:
			return "string";
		case ASURA_WINDOWS_REGISTRY_VALUE_TYPE_BINARY:
			return "binary";
		case ASURA_WINDOWS_REGISTRY_VALUE_TYPE_UNSUPPORTED:
			return "unsupported";
		default:
			return "???";
	}
}

// -------------------------------------------------------------------------------------
//check to see if a processed value type is what we want
// -------------------------------------------------------------------------------------
//	In:
//		valueName, the keyvalue to check
//		processedValueType, the type we are looking for
//		valueSize, the size we are looking for (or -1 if we don't care about the size)
//		reportSizeDifference, we don't always want to report if the size is the only difference
//	Out:
//		returns true if it matches what we want

bool Asura_PC_WindowsRegistry::CheckProcessedValueTypeAndSizeFromOpen(const char* const pszValueName, const ASURA_WINDOWS_REGISTRY_VALUE_TYPE eProcessedValueType, const int iValueSize, const bool bReportSizeDifference /* = true */)
{
	//ok, need to find out what the processed value type is
	if (!GetValueTypeAndSizeFromOpen( pszValueName))
	{
		return false;
	}

	if( (m_eValueTypeProcessed == eProcessedValueType) &&
		((iValueSize == -1) || (iValueSize == m_iValueSize)) )
	{
		//value is of the right type and size
		return true;
	}

	if (m_eValueTypeProcessed == ASURA_WINDOWS_REGISTRY_VALUE_TYPE_ERROR)
	{
		//any errors would of been reported by GetValueTypeAndSizeFromOpen
		return false;
	}

	if (m_eValueTypeProcessed != eProcessedValueType)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::CheckProcessedValueTypeAndSizeFromOpen '%s', value type=%s(%d), expected %s(%d)",
							pszValueName,
							GetProcessedValueTypeString(m_eValueTypeProcessed), m_eValueTypeProcessed,
							GetProcessedValueTypeString(eProcessedValueType), eProcessedValueType));

		//EI_ERROR("Asura_PC_WindowsRegistry::CheckProcessedValueTypeAndSizeFromOpen '%s', value type=%s(%d), expected %s(%d)\n",
		//	valueName,
		//	GetProcessedValueTypeString(m_ValueTypeProcessed), m_ValueTypeProcessed,
		//	GetProcessedValueTypeString(processedValueType), processedValueType);
	}
	else if( bReportSizeDifference)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::CheckProcessedValueTypeAndSizeFromOpen '%s', value size=%d, expected %d",
							pszValueName, m_iValueSize, iValueSize));

		//EI_ERROR("Asura_PC_WindowsRegistry::CheckProcessedValueTypeAndSizeFromOpen '%s', value size=%d, expected %d\n",
		//	valueName, m_ValueSize, valueSize);
	}
	return false;
}

// -------------------------------------------------------------------------------------
//read a keyvalue into a buffer (the subkey must have been previously opened)
//the buffer address can be NULL, to just get the size of the value
// -------------------------------------------------------------------------------------
//	In:
//		valueName, the keyvalue to read
//		dataBuffer, where to store the value
//		dataSize, the size to try to read
//		outputSize, where to store the size of the value, or -1 if FAILED
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::GetValueFromOpen(const char* const pszValueName, void* const pDataBuffer, const int iDataSize, int* const piOutputSize)
{
	//in case an error occurs
	if( piOutputSize != NULL)
	{
		*piOutputSize = -1;
	}
	
	//is there a subkey open?
	if (!m_bSubKeyOpen)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::ReadValueFromOpen '%s', subkey not open", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::ReadValueFromOpen '%s', subkey not open\n", valueName);
		return false;
	}

	//valid data size? (can be ignored if dataBuffer == NULL, as then we just want the buffer size)
	if( (pDataBuffer != NULL) && (iDataSize <= 0) )
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::ReadValueFromOpen '%s', invalid data size", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::ReadValueFromOpen '%s', invalid data size\n", valueName);
		return false;
	}

	//read the requested value
	DWORD dwValueType;
	DWORD dwDataSize = (DWORD)iDataSize;
	const LONG lastError = ::RegQueryValueExA((HKEY)m_hSubKeyHandle, pszValueName, NULL, &dwValueType, (LPBYTE)pDataBuffer, &dwDataSize);
	if (lastError != ERROR_SUCCESS)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::ReadValueFromOpen '%s', ::RegQueryValueExA FAILED", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::ReadValueFromOpen '%s', ::RegQueryValueExA FAILED, %s\n", valueName, EI_SYSTEM_ERROR_STRING(lastError));
		return false;
	}

	//ok
	if( piOutputSize != NULL)
	{
		*piOutputSize = (int)dwDataSize;
	}
	return true;
}

// -------------------------------------------------------------------------------------
//set a keyvalue (the subkey must have been previously opened)
// -------------------------------------------------------------------------------------
//	In:
//		valueName, the keyvalue to set
//		pDataBuffer, pointer to the data buffer where to store the value
//		dataSize, the size to write
//		valueType, the type of the keyvalue (a windows registry type)
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::SetValueFromOpen(const char* const pszValueName, const void* pDataBuffer, const int iDataSize, const u_int uValueType)
{
	//is there a subkey open?
	if (!m_bSubKeyOpen)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', subkey not open", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', subkey not open\n", valueName);
		return false;
	}

	//valid buffer?
	if( pDataBuffer == NULL)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', invalid buffer=NULL", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', invalid buffer=NULL\n", valueName);
		return false;
	}

	if( iDataSize < 0)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', invalid data size=%d", pszValueName, iDataSize));
//		EI_ERROR("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', invalid data size=%d\n", valueName, dataSize);
		return false;
	}

	//set the requested value
	const LONG lastError = ::RegSetValueExA((HKEY)m_hSubKeyHandle, pszValueName, 0, (DWORD)uValueType, (CONST BYTE*)pDataBuffer, (DWORD)iDataSize);
	if (lastError != ERROR_SUCCESS)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', ::RegSetValueExA FAILED", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::SetValueFromOpen '%s', ::RegSetValueExA FAILED, %s\n", EI_SYSTEM_ERROR_STRING(lastError));
		return false;
	}
	return true;
}

// -------------------------------------------------------------------------------------
//Delete a keyvalue (the subkey must have been previously opened)
// -------------------------------------------------------------------------------------
//	In:
//		valueName, the keyvalue to delete
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::DeleteValueFromOpen(const char* const pszValueName)
{
	//is there a subkey open?
	if (!m_bSubKeyOpen)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::DeleteValueFromOpen '%s', subkey not open", pszValueName));
//		EI_ERROR("Asura_PC_WindowsRegistry::DeleteValueFromOpen '%s', subkey not open\n", valueName);
		return false;
	}

	//Delete the requested value
	const LONG lastError = ::RegDeleteValueA((HKEY)m_hSubKeyHandle, pszValueName);
	if (lastError != ERROR_SUCCESS)
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::DeleteValueFromOpen '%s', ::RegDeleteValue FAILED", pszValueName));	
//		EI_ERROR("Asura_PC_WindowsRegistry::DeleteValueFromOpen '%s', ::RegDeleteValue FAILED, %s\n", valueName, EI_SYSTEM_ERROR_STRING(lastError));
		return false;
	}
	return true;
}

// -------------------------------------------------------------------------------------
//Reading from the registry (the subkey must have been previously opened)
// -------------------------------------------------------------------------------------
//read a registry number (the subkey must have been previously opened)
//	In:
//		valueName, the keyvalue of the string to read
//		*outputNumber, where to store the number
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::ReadNumberFromOpen(const char* const pszValueName, u_int* const puOutputNumber)
{
	if( !CheckProcessedValueTypeAndSizeFromOpen( pszValueName, ASURA_WINDOWS_REGISTRY_VALUE_TYPE_NUMBER, sizeof(DWORD)))
	{
		return false;
	}

	DWORD dwNumber;
	int iValueSize;
	if (!GetValueFromOpen( pszValueName, &dwNumber, sizeof(dwNumber), &iValueSize))
	{
		return false;
	}
	if( iValueSize != sizeof(dwNumber))
	{
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::ReadNumberFromOpen '%s', size read = %d, expected %d", pszValueName, iValueSize));
//		EI_ERROR("Asura_PC_WindowsRegistry::ReadNumberFromOpen '%s', size read = %d, expected %d\n", valueName, valueSize, sizeof(dwNumber));
		return false;
	}
	if( puOutputNumber != NULL)
	{
		*puOutputNumber = (u_int)dwNumber;
	}
	return true;
}

//read a registry string (the subkey must have been previously opened)
//	In:
//		valueName, the keyvalue of the string to read
//		stringBuffer, where to store the string (pass NULL to just get the SIZE)
//		stringBufferSize, the maximum SIZE of the string
//		*outputStringSize, where to store the SIZE read, or -1 if FAILED
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::ReadStringFromOpen(const char* const pszValueName, char* const pszStringBuffer, const int iStringBufferSize, int* const piOutputStringSize /* = NULL */)
{
	if (!CheckProcessedValueTypeAndSizeFromOpen( pszValueName, ASURA_WINDOWS_REGISTRY_VALUE_TYPE_STRING, -1))
	{
		if( piOutputStringSize != NULL)
		{
			*piOutputStringSize = -1;
		}
		return false;
	}
	return(GetValueFromOpen( pszValueName, pszStringBuffer, iStringBufferSize, piOutputStringSize));
}

//read a registry binary block (the subkey must have been previously opened)
//	In:
//		valueName, the keyvalue of the string to read
//		buffer, where to store the binary data (pass NULL to just get the size)
//		bufferSize, the maximum size of the buffer
//		*outputSize, where to store the size read, or -1 if FAILED
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::ReadBinaryFromOpen(const char* const pszValueName, void* const pBuffer, const int iBufferSize, int* const piOutputSize /* = NULL */)
{
	if (!CheckProcessedValueTypeAndSizeFromOpen( pszValueName, ASURA_WINDOWS_REGISTRY_VALUE_TYPE_BINARY, -1))
	{
		if( piOutputSize != NULL)
		{
			*piOutputSize = -1;
		}
		return false;
	}
	return(GetValueFromOpen( pszValueName, pBuffer, iBufferSize, piOutputSize));
}

// -------------------------------------------------------------------------------------
//Writing to the registry (the subkey must have been previously opened)
// -------------------------------------------------------------------------------------
//write a registry number (the subkey must have been previously opened / created)
//	In:
//		valueName, the keyvalue of the string to read
//		number, the number
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::WriteNumberFromOpen(const char* const pszValueName, const u_int uNumber)
{
	const DWORD dwNumber = (DWORD)uNumber;
	return SetValueFromOpen( pszValueName, &dwNumber, sizeof(dwNumber), REG_DWORD);
}

// -------------------------------------------------------------------------------------

bool Asura_PC_WindowsRegistry::WriteNumberIfChangedFromOpen(const char* const pszValueName, const u_int uNumber)
{
	if( m_bCreatedSubKeyAlreadyExisted)
	{
		u_int uTemp;
		if( ReadNumberFromOpen( pszValueName, &uTemp))
		{
			if( uTemp == uNumber)
			{
				//this value is already set
				return true;
			}
		}
	}
	const DWORD dwNumber = (DWORD)uNumber;
	return SetValueFromOpen( pszValueName, &dwNumber, sizeof(dwNumber), REG_DWORD);
}

//write a registry string (the subkey must have been previously opened / created)
//	In:
//		valueName, the keyvalue of the string to read
//		stringBuffer, pointer to the string
//		stringSize, the SIZE of the string, including NULL terminator (pass -1 to calculate)
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::WriteStringFromOpen(const char* const pszValueName, const char* const pszStringBuffer, int iStringSize /* = -1 */)
{
	if( (pszStringBuffer != NULL) && (iStringSize == -1) )
	{
		iStringSize = (int)strlen( pszStringBuffer) + 1;
	}
	return SetValueFromOpen( pszValueName, pszStringBuffer, iStringSize, REG_SZ);
}

// -------------------------------------------------------------------------------------

bool Asura_PC_WindowsRegistry::WriteStringIfChangedFromOpen(const char* const pszValueName, const char* const pszStringBuffer, int iStringSize /* = -1 */)
{
	if( (pszStringBuffer != NULL) && (iStringSize == -1) )
	{
		iStringSize = (int)strlen( pszStringBuffer) + 1;
	}
	if( m_bCreatedSubKeyAlreadyExisted)
	{
		if( (iStringSize >= 0) && (iStringSize <= eBufferSizeCheckIfChanged) )
		{
			if (CheckProcessedValueTypeAndSizeFromOpen( pszValueName, ASURA_WINDOWS_REGISTRY_VALUE_TYPE_STRING, iStringSize, false))
			{
				if( iStringSize == 0)
				{
					//this value is already set
					return true;
				}
				char acCheckStringBuffer[eBufferSizeCheckIfChanged];
				int iCheckStringSize;
				if( ReadStringFromOpen( pszValueName, acCheckStringBuffer, iStringSize, &iCheckStringSize))
				{
					if( iCheckStringSize == iStringSize)
					{
						if( memcmp( pszStringBuffer, acCheckStringBuffer, iStringSize) == 0)
						{
							//this value is already set
							return true;
						}
					}
				}
			}
		}
	}
	return SetValueFromOpen( pszValueName, pszStringBuffer, iStringSize, REG_SZ);
}

//write a binary block (the KEY must have been previously opened / created)
//	In:
//		valueName, the keyvalue of the binary to read
//		buffer, address of the binary data
//		bufferSize, the size of the binary data
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::WriteBinaryFromOpen(const char* const pszValueName, const void* const pBuffer, const int iBufferSize)
{
	return SetValueFromOpen( pszValueName, pBuffer, iBufferSize, REG_BINARY);
}

// -------------------------------------------------------------------------------------

bool Asura_PC_WindowsRegistry::WriteBinaryIfChangedFromOpen(const char* const pszValueName, const void* const pBuffer, const int iBufferSize)
{
	if( m_bCreatedSubKeyAlreadyExisted)
	{
		if( (iBufferSize >= 0) && (iBufferSize <= eBufferSizeCheckIfChanged) )
		{
			if (CheckProcessedValueTypeAndSizeFromOpen( pszValueName, ASURA_WINDOWS_REGISTRY_VALUE_TYPE_BINARY, iBufferSize, false))
			{
				if( iBufferSize == 0)
				{
					//this value is already set
					return true;
				}
				char acCheckBuffer[eBufferSizeCheckIfChanged];
				int iCheckSize;
				if( ReadBinaryFromOpen( pszValueName, acCheckBuffer, iBufferSize, &iCheckSize))
				{
					if( iCheckSize == iBufferSize)
					{
						if (memcmp( pBuffer, acCheckBuffer, iBufferSize) == 0)
						{
							//this value is already set
							return true;
						}
					}
				}
			}
		}
	}
	return SetValueFromOpen( pszValueName, pBuffer, iBufferSize, REG_BINARY);
}

//------------------------------------------------------------------------------
//Reading from the registry
//------------------------------------------------------------------------------
//read a registry number --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to read
//		*outputNumber, where to store the number
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::ReadNumber(const char* const pszSubKey, const char* const pszValueName, u_int* puOutputNumber, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !OpenSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = ReadNumberFromOpen( pszValueName, puOutputNumber);
	CloseSubKey();

	return bReturnValue;
}

//read a registry string --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to read
//		stringBuffer, where to store the string (pass NULL to just get the SIZE)
//		int stringBufferSize, the maximum SIZE of the string
//		*outputStringSize, where to store the SIZE read, or -1 if FAILED
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::ReadString(const char* const pszSubKey, const char* const pszValueName, char* const pszStringBuffer, const int iStringBufferSize, int* const piOutputStringSize /* = NULL */, HKEY hMasterKeyHandle /* = m_hDefaultMasterKeyHandle */)
{
	if( !OpenSubKey( pszSubKey, hMasterKeyHandle))
	{
		if( piOutputStringSize != NULL)
		{
			*piOutputStringSize = -1;
		}
		return false;
	}
	const bool bReturnValue = ReadStringFromOpen( pszValueName, pszStringBuffer, iStringBufferSize, piOutputStringSize);
	CloseSubKey();
	return bReturnValue;
}

//read a registry binary block --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to read
//		buffer, where to store the binary data (pass NULL to just get the size)
//		bufferSize, the maximum size of the buffer
//		*outputSize, where to store the size read, or -1 if FAILED
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::ReadBinary(const char* const pszSubKey, const char* const pszValueName, void* const pBuffer, const int iBufferSize, int* const piOutputSize /* = NULL */, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !OpenSubKey( pszSubKey, hMasterKeyHandle))
	{
		if( piOutputSize != NULL)
		{
			*piOutputSize = -1;
		}
		return false;
	}
	const bool bReturnValue = ReadBinaryFromOpen( pszValueName, pBuffer, iBufferSize, piOutputSize);
	CloseSubKey();
	return bReturnValue;
}

//------------------------------------------------------------------------------
//Writing to the registry
//------------------------------------------------------------------------------
//write a registry DWORD --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to read
//		unsigned int number, the number
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::WriteNumber(const char* const pszSubKey, const char* const pszValueName, const u_int uNumber, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !CreateSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = WriteNumberFromOpen( pszValueName, uNumber);
	CloseSubKey();
	return bReturnValue;
}

// -------------------------------------------------------------------------------------

bool Asura_PC_WindowsRegistry::WriteNumberIfChanged(const char* const pszSubKey, const char* const pszValueName, u_int uNumber, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !CreateSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = WriteNumberIfChangedFromOpen( pszValueName, uNumber);
	CloseSubKey();
	return bReturnValue;
}

//write a registry string --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to read
//		stringBuffer, pointer to the string
//		stringSize, the SIZE of the string, including NULL terminator (pass -1 to calculate)
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::WriteString(const char* const pszSubKey, const char* const pszValueName, const char* const pszStringBuffer, const int iStringSize /* = -1 */, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !CreateSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = WriteStringFromOpen( pszValueName, pszStringBuffer, iStringSize);
	CloseSubKey();
	return bReturnValue;
}
bool Asura_PC_WindowsRegistry::WriteStringIfChanged(const char* const pszSubKey, const char* const pszValueName, const char* const pszStringBuffer, const int iStringSize /* = -1 */, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !CreateSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = WriteStringIfChangedFromOpen( pszValueName, pszStringBuffer, iStringSize);
	CloseSubKey();
	return bReturnValue;
}

//write a binary block --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the binary to read
//		buffer, address of the binary data
//		bufferSize, the size of the binary data
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::WriteBinary(const char* const pszSubKey, const char* const pszValueName, const void* const pBuffer, const int iBufferSize, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !CreateSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = WriteBinaryFromOpen( pszValueName, pBuffer, iBufferSize);
	CloseSubKey();
	return bReturnValue;
}
bool Asura_PC_WindowsRegistry::WriteBinaryIfChanged(const char* const pszSubKey, const char* const pszValueName, const void* const pBuffer, const int iBufferSize, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !CreateSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = WriteBinaryIfChangedFromOpen( pszValueName, pBuffer, iBufferSize);
	CloseSubKey();
	return bReturnValue;
}

//------------------------------------------------------------------------------
//Delete a keyvalue from the registry
//------------------------------------------------------------------------------
//delete a registry value --- this is intended as the function to be used externally
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to delete
//		masterKeyHandle, master key
//	Out:
//		returns true if successful

bool Asura_PC_WindowsRegistry::DeleteValue(const char* const pszSubKey, const char* const pszValueName, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !OpenSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = DeleteValueFromOpen( pszValueName);
	CloseSubKey();
	return bReturnValue;
}

//------------------------------------------------------------------------------
//check if keyvalue exists
//------------------------------------------------------------------------------
//	In:
//		subKey, the name of the subkey
//		valueName, the keyvalue of the string to read
//		masterKeyHandle, master key
//	Out:
//		returns true if the subkey exists

bool Asura_PC_WindowsRegistry::DoesValueExist(const char* const pszSubKey, const char* const pszValueName, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	if( !OpenSubKey( pszSubKey, hMasterKeyHandle))
	{
		return false;
	}
	const bool bReturnValue = GetValueTypeAndSizeFromOpen( pszValueName);
	CloseSubKey();
	return bReturnValue;
}

//------------------------------------------------------------------------------
// enumerate
//------------------------------------------------------------------------------

int Asura_PC_WindowsRegistry::EnumerateKeys(const char* const pszSubKey, ASURA_ENUMERATE_REGISTRY_KEYS_CALLBACK callBack, void* const pUserData, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	LONG lastError;

	char acTidiedSubKey[eTidySubKeySize];
	if( !TidySubKey( acTidiedSubKey, pszSubKey, hMasterKeyHandle))
	{
		return -1;
	}
	//open the requested subkey
	HKEY hSubKeyHandle = NULL;
	lastError = ::RegOpenKeyExA( hMasterKeyHandle, acTidiedSubKey, 0, KEY_ALL_ACCESS, &hSubKeyHandle);
	if( lastError != ERROR_SUCCESS)
	{
		if( lastError != ERROR_FILE_NOT_FOUND)	//not found
		{
			Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::EnumerateKeys '%s(%s)', ::RegOpenKeyExA FAILED", pszSubKey, acTidiedSubKey));
//			EI_ERROR("Asura_PC_WindowsRegistry::EnumerateKeys '%s(%s)', ::RegOpenKeyExA FAILED, %s\n", subKey, tidiedSubKey, EI_SYSTEM_ERROR_STRING(lastError));
			return -1;
		}
		return 0;
	}

	int iIndex = 0;
	while (1)
	{
		char acKeyName[256];
		DWORD iKeyNameSize = sizeof(acKeyName);
		char acKeyClass[256];
		DWORD dwKeyClassSize = sizeof(acKeyClass);
		FILETIME xLastWriteTime;

		lastError = ::RegEnumKeyExA( hSubKeyHandle, (DWORD)iIndex, acKeyName, &iKeyNameSize, NULL, acKeyClass, &dwKeyClassSize, &xLastWriteTime);
		if (lastError != ERROR_SUCCESS)
		{
			if (lastError != ERROR_NO_MORE_ITEMS)
			{
//				EI_ERROR("Asura_PC_WindowsRegistry::EnumerateKeys '%s(%s)', ::RegEnumKeyExA index %d FAILED, %s\n", subKey, tidiedSubKey, index, EI_SYSTEM_ERROR_STRING(lastError));
				Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::EnumerateKeys '%s(%s)', ::RegEnumKeyExA index %d FAILED", pszSubKey, acTidiedSubKey, iIndex));
			}
			break;
		}
		if( callBack != NULL)
		{
			if( !callBack( iIndex, acKeyName, acKeyClass, pszSubKey, acTidiedSubKey, pUserData))
			{
				iIndex++;
				break;
			}
		}
		iIndex++;
	}
	lastError = ::RegCloseKey( hSubKeyHandle);
	if( lastError != ERROR_SUCCESS)
	{
//		EI_ERROR("Asura_PC_WindowsRegistry::EnumerateKeys '%s(%s)', ::RegCloseKey FAILED, %s\n", subKey, tidiedSubKey, EI_SYSTEM_ERROR_STRING(lastError));
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::EnumerateKeys '%s(%s)', ::RegCloseKey FAILED", pszSubKey, acTidiedSubKey));
	}
	return iIndex;
}

int Asura_PC_WindowsRegistry::EnumerateValues(const char* const pszSubKey, ASURA_ENUMERATE_REGISTRY_VALUES_CALLBACK callBack, void* const pUserData, void* const pValueBuffer /* = NULL */, const int iValueBufferSize /* = 0 */, HKEY hMasterKeyHandle /* = m_pDefaultMasterKeyHandle */)
{
	LONG lastError;

	char acTidiedSubKey[eTidySubKeySize];
	if( !TidySubKey( acTidiedSubKey, pszSubKey, hMasterKeyHandle))
	{
		return -1;
	}
	//open the requested subkey
	HKEY hSubKeyHandle = NULL;
	lastError = ::RegOpenKeyExA( hMasterKeyHandle, acTidiedSubKey, 0, KEY_ALL_ACCESS, &hSubKeyHandle);
	if( lastError != ERROR_SUCCESS)
	{
		if( lastError != ERROR_FILE_NOT_FOUND)	//not found
		{
//			EI_ERROR("Asura_PC_WindowsRegistry::EnumerateValues '%s(%s)', ::RegOpenKeyExA FAILED, %s\n", subKey, tidiedSubKey, EI_SYSTEM_ERROR_STRING(lastError));
			Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::EnumerateValues '%s(%s)', ::RegOpenKeyExA FAILED", pszSubKey, acTidiedSubKey));
			return -1;
		}
		return 0;
	}

	int iIndex = 0;
	while (1)
	{
		char acValueName[256];
		DWORD dwValueNameSize = sizeof(acValueName);
		DWORD dwValueTypeUnprocessed;
		DWORD dwValueSize = 0;
		BYTE* pcUseValueBuffer = NULL;
		bool bValueTooLargeForBuffer = false;

		if( ( pValueBuffer != NULL) && (iValueBufferSize > 0) )
		{
			pcUseValueBuffer	= (BYTE*)pValueBuffer;
			dwValueSize		= (DWORD)iValueBufferSize;
			memset(pValueBuffer, 0, iValueBufferSize);
		}
		lastError = ::RegEnumValueA( hSubKeyHandle, (DWORD)iIndex, acValueName, &dwValueNameSize, NULL, &dwValueTypeUnprocessed, pcUseValueBuffer, &dwValueSize);
		if( lastError == ERROR_MORE_DATA)
		{
			bValueTooLargeForBuffer = true;
		}
		else if( lastError != ERROR_SUCCESS)
		{
			if( lastError != ERROR_NO_MORE_ITEMS)
			{
//				EI_ERROR("Asura_PC_WindowsRegistry::EnumerateValues '%s(%s)', ::RegEnumValueA index %d FAILED, %s\n", subKey, tidiedSubKey, index, EI_SYSTEM_ERROR_STRING(lastError));
				Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::EnumerateValues '%s(%s)', ::RegEnumValueA index %d FAILED", pszSubKey, acTidiedSubKey, iIndex));
			}
			break;
		}
		const ASURA_WINDOWS_REGISTRY_VALUE_TYPE eValueTypeProcessed = GetProcessedValueType((u_int)dwValueTypeUnprocessed);
		if( callBack != NULL)
		{
			if (!callBack(	iIndex,								//entry index
							acValueName,						//enumerated value's name
							pValueBuffer,						//the value (if a buffer was passed to the enumerate function)
							(int)dwValueSize,					//the size of the value
							bValueTooLargeForBuffer,			//was the value too large for the passed buffer?
							eValueTypeProcessed,				//the processed value type
							(u_int)dwValueTypeUnprocessed,		//the unprocessed value type
							pszSubKey,							//the key that is being enumerated
							acTidiedSubKey,						//the key that is being enumerated (the tidied name)
							pUserData))							//user data
			{
				iIndex++;
				break;
			}
		}
		iIndex++;
	}
	lastError = ::RegCloseKey( hSubKeyHandle);
	if( lastError != ERROR_SUCCESS)
	{
		//EI_ERROR("Asura_PC_WindowsRegistry::EnumerateValues '%s(%s)', ::RegCloseKey FAILED, %s\n", subKey, tidiedSubKey, EI_SYSTEM_ERROR_STRING(lastError));
		Asura_Assertf( 0, ("Asura_PC_WindowsRegistry::EnumerateValues '%s(%s)', ::RegCloseKey FAILED", pszSubKey, acTidiedSubKey));
	}
	return iIndex;
}

#endif	//ASURA_PC_SUPPORT_WINDOWS_REGISTRY

//eof
