/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-17©  Modified: 2016-08-08©	//
//																																	//
// ThreeTimers.cpp : Defines the entry point for the application.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ThreeTimers.h"
#include "TT_Global.h"
#include "TT_Pixel.h"
#include "TT_PixelMap.h"
#include <mmsystem.h>
#include <atlstr.h>
#include <atltypes.h>
#include <fcntl.h>
#include <MultiMon.h>
#include <Winuser.h>
#include <WindowsX.h>
#include "dwmapi.h"
#include <cderr.h>

/////////////////////////////////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////////////////////////
// Global Variables:

const UINT_PTR			TT_cunpTimerIdEvent = 101;
const DWORD				TT_cdwTimerElapse   = 200;			//	In milliseconds.

const TCHAR * const	TT_cpcszUniqueClassName_ThreeTimers_ModifyTimerLabelTinyWnd = _T("ThreeTimers_ModifyTimerLabelTinyWnd");

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

HINSTANCE				TT_hInst								 = 0;		// Current instance.
UINT_PTR					TT_unpTimerIdEvent				 = 0;
HANDLE					TT_hMemFont_SegoeUI_TTF			 = 0;
unsigned __int64		TT_un64AppFileVersion			 = 0;
unsigned __int64		TT_un64AppProductVersion		 = 0;
TCHAR						TT_szModuleFileName[MAX_PATH]  = { _T("") };	// Read only.
TCHAR						TT_szStartingFolder[MAX_PATH]  = { _T("") };	// Read only.
bool						TT_bIsCoInitializeExFnctCalled = FALSE;
bool						TT_bIsFlashWndContinuously		 = FALSE;
bool						TT_bIsCalledFromEnterKey		 = FALSE;
HCURSOR					TT_hCursorClick_LXR				 = 0;
CString					TT_strREG_KEY__ADELUC_TTn;

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

HINSTANCE							TT_hDwmApiDll						= 0;
PFN_DwmIsCompositionEnabled	TT_pfnDwmIsCompositionEnabled = NULL;
PFN_DwmGetWindowAttribute		TT_pfnDwmGetWindowAttribute	= NULL;

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

DWORD			TT_dwTimerValue1 = TT_REG_VAL__Timer_Value__DFLT_VALUE_1;	//	Possible values (in milliseconds) from
DWORD			TT_dwTimerValue2 = TT_REG_VAL__Timer_Value__DFLT_VALUE_2;	//	 'TT_REG_VAL__Timer_Value__Min'
DWORD			TT_dwTimerValue3 = TT_REG_VAL__Timer_Value__DFLT_VALUE_3;	//	 to 'TT_REG_VAL__Timer_Value__Max'.

DWORD			TT_dwTimerUnit1 = TT_REG_VAL__Timer_Unit__DFLT_VALUE_1;		//	Possible values from
DWORD			TT_dwTimerUnit2 = TT_REG_VAL__Timer_Unit__DFLT_VALUE_2;		//	 'TT_REG_VAL__Timer_Unit__FIRST_VALUE'
DWORD			TT_dwTimerUnit3 = TT_REG_VAL__Timer_Unit__DFLT_VALUE_3;		//	 to 'TT_REG_VAL__Timer_Unit__LAST_VALUE'.

DWORD			TT_dwTimerEvent1 = TT_REG_VAL__Timer_Event__DFLT_VALUE_1;	//	Possible values from
DWORD			TT_dwTimerEvent2 = TT_REG_VAL__Timer_Event__DFLT_VALUE_2;	//	 'TT_REG_VAL__Timer_Event__FIRST_VALUE'
DWORD			TT_dwTimerEvent3 = TT_REG_VAL__Timer_Event__DFLT_VALUE_3;	//	 to 'TT_REG_VAL__Timer_Event__LAST_VALUE'.

DWORD			TT_dwTimerStarted1 = 0;				//	Internal use.  Value stored in milliseconds.
DWORD			TT_dwTimerStarted2 = 0;				//	Internal use.  Value stored in milliseconds.
DWORD			TT_dwTimerStarted3 = 0;				//	Internal use.  Value stored in milliseconds.

DWORD			TT_dwCountDownValue1 = 0;			//	Internal use.  Value stored in seconds.
DWORD			TT_dwCountDownValue2 = 0;			//	Internal use.  Value stored in seconds.
DWORD			TT_dwCountDownValue3 = 0;			//	Internal use.  Value stored in seconds.

bool			TT_bIsTimerStarted1 = FALSE;		//	Internal use.
bool			TT_bIsTimerStarted2 = FALSE;		//	Internal use.
bool			TT_bIsTimerStarted3 = FALSE;		//	Internal use.

bool			TT_bIsEventTriggered1 = FALSE;	//	Internal use.
bool			TT_bIsEventTriggered2 = FALSE;	//	Internal use.
bool			TT_bIsEventTriggered3 = FALSE;	//	Internal use.

bool			TT_bIsEventCalled1 = FALSE;		//	Internal use.  Used to prevents the triggered event to be called more than once per countdown.
bool			TT_bIsEventCalled2 = FALSE;		//	Internal use.	Used to prevents the triggered event to be called more than once per countdown.
bool			TT_bIsEventCalled3 = FALSE;		//	Internal use.	Used to prevents the triggered event to be called more than once per countdown.

bool			TT_bIsKeepWndOnTop		  = TRUE;
bool			TT_bIsShowInTitleBar		  = TRUE;
bool			TT_bIsFlashWndOnTimerUp	  = TRUE;
bool			TT_bIsUseAltIconOnTimerUp = TRUE;
bool			TT_bIsDisplaySmartCursors = TRUE;

TCHAR			TT_szTimerLabel1[TT_TimerLabel_MaxBufCnt] = _T("");
TCHAR			TT_szTimerLabel2[TT_TimerLabel_MaxBufCnt] = _T("");
TCHAR			TT_szTimerLabel3[TT_TimerLabel_MaxBufCnt] = _T("");

TCHAR			TT_szExtSndLabel1[TT_ExtSndLabel_MaxBufCnt] = _T("");
TCHAR			TT_szExtSndLabel2[TT_ExtSndLabel_MaxBufCnt] = _T("");
TCHAR			TT_szExtSndLabel3[TT_ExtSndLabel_MaxBufCnt] = _T("");

TCHAR			TT_szExtSndFileName1[TT_ExtSndFileName_MaxBufCnt] = _T("");
TCHAR			TT_szExtSndFileName2[TT_ExtSndFileName_MaxBufCnt] = _T("");
TCHAR			TT_szExtSndFileName3[TT_ExtSndFileName_MaxBufCnt] = _T("");

TCHAR			TT_szOpenFileLabel1[TT_OpenFileLabel_MaxBufCnt] = _T("");
TCHAR			TT_szOpenFileLabel2[TT_OpenFileLabel_MaxBufCnt] = _T("");
TCHAR			TT_szOpenFileLabel3[TT_OpenFileLabel_MaxBufCnt] = _T("");

TCHAR			TT_szOpenFileName1[TT_OpenFileName_MaxBufCnt] = _T("");
TCHAR			TT_szOpenFileName2[TT_OpenFileName_MaxBufCnt] = _T("");
TCHAR			TT_szOpenFileName3[TT_OpenFileName_MaxBufCnt] = _T("");

/////////////////////////////////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-16©  Modified: 2016-07-11©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
	bool		bStatus = FALSE;
	int		nRntVal = 0;
	DWORD		dwRtnVal;
	TCHAR		szStartingFolderTmp[MAX_PATH];

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

	UNREFERENCED_PARAMETER( hPrevInstance );
	UNREFERENCED_PARAMETER( lpCmdLine );

	TT_hInst = hInstance;	// Stores instance handle in our global variable.
	AfxSetResourceHandle( TT_hInst );

	_set_fmode( _O_BINARY );		// Required if you do not link with "binmode.obj".

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

	// Load the DLL and keep the handle to it.  No matter if the function succeeds or not.
	// Must load dynamicaly because this DLL exists only in Vista and more recent OS.  (Does not exist in XP.)

	if ( (TT_hDwmApiDll = LoadLibrary( _T("dwmapi.dll") )) != 0 )
	{
		TT_pfnDwmIsCompositionEnabled = (PFN_DwmIsCompositionEnabled)::GetProcAddress( TT_hDwmApiDll, _T("DwmIsCompositionEnabled") );
		TT_pfnDwmGetWindowAttribute   = (PFN_DwmGetWindowAttribute  )::GetProcAddress( TT_hDwmApiDll, _T("DwmGetWindowAttribute")   );
	}
	else
	{
		TT_pfnDwmIsCompositionEnabled = NULL;
		TT_pfnDwmGetWindowAttribute	= NULL;
	}

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

	FOREVER
	{
		if ( ((dwRtnVal = ::GetModuleFileName( TT_hInst, TT_szModuleFileName, _countof( TT_szModuleFileName ) )) == 0) ||
				(dwRtnVal >= _countof( TT_szModuleFileName )) ) break;

		//------------------------------------------------
		//	For explanations about 'GetFullPathName()' see the remarks section in 'GetCurrentDirectory()'.

		if ( ((dwRtnVal = ::GetCurrentDirectory( _countof( szStartingFolderTmp ), szStartingFolderTmp )) == 0) ||
				(dwRtnVal >= _countof( szStartingFolderTmp )) ) break;

		if ( ((dwRtnVal = ::GetFullPathName( szStartingFolderTmp, _countof( TT_szStartingFolder ), TT_szStartingFolder, NULL )) == 0) ||
				(dwRtnVal >= _countof( TT_szStartingFolder )) ) break;

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

		if ( !TT_SHGetVersionNumbers( TT_szModuleFileName, &TT_un64AppFileVersion, 0, &TT_un64AppProductVersion, 0 ) ) break;

		TT_strREG_KEY__ADELUC_TTn.Format( TT_REG_KEY__ADELUC_TTn, (unsigned int)TT_SHGetVersionMajor( TT_un64AppFileVersion ) );

		if ( !TT_InstallPrivateFonts() ) break;
			
		if ( (TT_hCursorClick_LXR = ::LoadCursor( TT_hInst, MAKEINTRESOURCE( IDC_CURSOR_ARROW_CLICK_LXR ) )) == NULL ) break;

		if ( !TT_StartInstance( hInstance, nCmdShow ) ) break;

		bStatus = TRUE;
		break;
	}

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

	TT_UninstallPrivateFonts();

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

	if ( TT_bIsCoInitializeExFnctCalled )
	{
		CoUninitialize();
		TT_bIsCoInitializeExFnctCalled = FALSE;
	}

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

	if ( TT_hDwmApiDll != 0 )
	{
		TT_pfnDwmIsCompositionEnabled = NULL;
		TT_pfnDwmGetWindowAttribute	= NULL;

		FreeLibrary( TT_hDwmApiDll );
		TT_hDwmApiDll = 0;
	}

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

	return( nRntVal );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-16©  Modified: 2016-06-30©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

BOOL TT_StartInstance( HINSTANCE hInstance, int nCmdShow )
{
	if ( ::DialogBox( TT_hInst, MAKEINTRESOURCE( IDD_THREETIMERS ), 0, DlgThreeTimersProc ) == -1 )
	{
		::MessageBeep( MB_ICONHAND );
	}

	return( TRUE );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-07-18©  Modified: 2015-07-22©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

long TT_RegWriteString( HKEY hRootKey, const char *pcszKey, const char *pcszStringName, const char *pcszString )
{
   HKEY		hkCurrent = 0;
	long		lResult1, lResult2;
   DWORD		dwDisposition;

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

   if ( (lResult1 = RegCreateKeyEx( hRootKey, pcszKey, 0, "", REG_OPTION_NON_VOLATILE,
				KEY_ALL_ACCESS, 0, &hkCurrent, &dwDisposition )) == ERROR_SUCCESS )
	{
		lResult1 = RegSetValueEx( hkCurrent, pcszStringName, 0, REG_SZ,
											(const unsigned char *)pcszString, _tcslen( pcszString ) + EOS_CHAR_COUNT );
		lResult2 = RegCloseKey( hkCurrent );

		if ( (lResult1 == ERROR_SUCCESS) && (lResult2 != ERROR_SUCCESS) ) lResult1 = lResult2;
	}

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

	return( lResult1 );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-07-18©  Modified: 2015-07-22©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

long TT_RegWriteInteger( HKEY hRootKey, const char *pcszKey, const char *pcszValueName, const int cnValue )
{
   HKEY		hkCurrent = 0;
	long		lResult1, lResult2;
   DWORD		dwDisposition;

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

   if ( (lResult1 = RegCreateKeyEx( hRootKey, pcszKey, 0, "", REG_OPTION_NON_VOLATILE,
				KEY_ALL_ACCESS, 0, &hkCurrent, &dwDisposition )) == ERROR_SUCCESS )
	{
		lResult1 = RegSetValueEx( hkCurrent, pcszValueName, 0, REG_DWORD,
											(const unsigned char *)&cnValue, sizeof( cnValue ) );
		lResult2 = RegCloseKey( hkCurrent );

		if ( (lResult1 == ERROR_SUCCESS) && (lResult2 != ERROR_SUCCESS) ) lResult1 = lResult2;
	}

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

	return( lResult1 );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-07-18©  Modified: 2015-07-20©	//
//																																	//
//	Purpose:																														//
//																																	//
// Note: 'pcszDefaultString', 'pcszString' and 'punBufferSize' may be 0.									//
//																																	//
//	Result: If the return value is 'ERROR_FILE_NOT_FOUND' and ('pcszDefaultString' != 0) then the 	//
//			  contents of the 'pcszDefaultString' buffer will be copied in the 'pcszString' buffer 	//
//			  only if ('pcszString' != 0) and ('punBufferSize' != 0) and *('punBufferSize') is large	//
//			  enough.  If the return value is different from 'ERROR_SUCCESS' or 								//
//			  'ERROR_FILE_NOT_FOUND' then the contents of the 'pcszString' buffer are undefined.		//
//																																	//
// Note:	When 'pcszStringName' specifies the default value name, 'ERROR_OUTOFMEMORY' or				//
//			'ERROR_BADKEY' can also be returned.																		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

long TT_RegReadString( HKEY hRootKey, const char *pcszKey, const char *pcszStringName,
							   const char *pcszDefaultString, char *pcszString, unsigned int *punBufferSize )
{
	HKEY				hkCurrent		 = 0;
	DWORD				dwType			 = REG_NONE;
	unsigned int	unBufferSizeBkp = ((punBufferSize != 0) ? punBufferSize[0] : 0);
	int				nDefaultValueCount;
	long				lResult1, lResult2;

//---------------------------------------------------------------------------------------------------
//	This is a patch because when the default value does not exist, RegQueryValueEx() always returns
//	an empty string with the ERROR_SUCCESS error code.

	if ( (pcszStringName == 0) || (_tcslen( pcszStringName ) == 0) )	// Ask for the default value?
	{
		lResult1 = TT_RegTestKey( hRootKey, pcszKey, 0, &nDefaultValueCount, 0 );

		if ( (lResult1 == ERROR_SUCCESS) && (nDefaultValueCount == 0) ) lResult1 = ERROR_FILE_NOT_FOUND;
	}
	else lResult1 = ERROR_SUCCESS;

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

	if ( lResult1 == ERROR_SUCCESS )
	{
		if ( (lResult1 = RegOpenKeyEx( hRootKey, pcszKey, 0, KEY_READ, &hkCurrent )) == ERROR_SUCCESS )
		{
			if ( punBufferSize == 0 )
				lResult1 = RegQueryValueEx( hkCurrent, pcszStringName, 0, &dwType, 0, 0 );
			else
				lResult1 = RegQueryValueEx( hkCurrent, pcszStringName, 0, &dwType, (LPBYTE)pcszString, (LPDWORD)punBufferSize );

			if ( (lResult1 == ERROR_SUCCESS) && (dwType != REG_SZ) ) lResult1 = ERROR_INVALID_DATATYPE;

			lResult2 = RegCloseKey( hkCurrent );

			if ( (lResult1 == ERROR_SUCCESS) && (lResult2 != ERROR_SUCCESS) ) lResult1 = lResult2;
		}
		else if ( punBufferSize != 0 ) *(punBufferSize) = 0;
	}

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

	if ( lResult1 == ERROR_FILE_NOT_FOUND )
	{
		if ( punBufferSize != 0 )
		{
			if ( pcszDefaultString != 0 )
			{
				*(punBufferSize) = (_tcslen( pcszDefaultString ) + EOS_CHAR_COUNT);

				if ( pcszString != 0 )
				{
					if ( unBufferSizeBkp >= *(punBufferSize) )		//	Is 'pcszString' buffer large enough?
					{
						_tcscpy( pcszString, pcszDefaultString );		//	No possible overflow here.
					}
					else lResult1 = ERROR_MORE_DATA;
				}
			}
			else *(punBufferSize) = 0;
		}
	}

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

	return( lResult1 );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-11-17©  Modified: 2015-07-20©	//
//																																	//
//	Purpose:																														//
//																																	//
// 'pcszDefaultString': May be 0.  The contents of the 'pcszDefaultString' buffer will be copied	//
//								in the returned string only if 'pcszDefaultString' is != 0 and the call 	//
//								to the 'DT_RegReadString()' function returns 'ERROR_FILE_NOT_FOUND'.			//
//																																	//
//	Result: If successful, returns a pointer to a zero terminated string.  Otherwise returns 0. 		//
//																																	//
// Note: Do not forget to call 'GlobalFree()' with the returned string pointer if it is != 0.		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

char * TT_RegGetString( HKEY hRootKey, const char *pcszKey, const char *pcszStringName, const char *pcszDefaultString )
{
	char			  *pszKeyValue  = 0;
	unsigned int	unBufferSize = 0;
	long				lResult;
	
//---------------------------------------------------------------------------------------------------

	lResult = TT_RegReadString( hRootKey, pcszKey, pcszStringName, pcszDefaultString, 0, &unBufferSize );

	if ( (lResult == ERROR_SUCCESS) || ((lResult == ERROR_FILE_NOT_FOUND) && (pcszDefaultString != 0)) )
	{
		if ( (unBufferSize != 0) && ((pszKeyValue = (char *)::GlobalAlloc( GPTR, unBufferSize )) != 0) )
		{
			lResult = TT_RegReadString( hRootKey, pcszKey, pcszStringName, pcszDefaultString, pszKeyValue, &unBufferSize );

			if ( !((lResult == ERROR_SUCCESS) || ((lResult == ERROR_FILE_NOT_FOUND) && (pcszDefaultString != 0))) )
			{
				::GlobalFree( pszKeyValue );
				pszKeyValue = 0;
			}
		}
	}

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

	return( pszKeyValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-07-18©  Modified: 2016-03-19©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: If the return value is not 'ERROR_SUCCESS' then *('pnValue') will be set with				//
//			  'cnDefaultValue'.																								//
//																																	//
// Note:	When 'pcszValueName' specifies the default value name and the default value cannot 			//
//			fit in 'pnValue', then 'ERROR_MORE_DATA' is returned.													//
//																																	//
// Note:	When 'pcszValueName' specifies the default value name, 'ERROR_OUTOFMEMORY' or					//
//			'ERROR_BADKEY' can also be returned.																		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

long TT_RegReadInteger( HKEY hRootKey, const char *pcszKey, const char *pcszValueName, const int cnDefaultValue, int *pnValue )
{
	HKEY		hkCurrent = 0;
	DWORD		dwType	 = REG_NONE;
	int		nDefaultValueCount;
	DWORD		dwSize;
	long		lResult1, lResult2;

//---------------------------------------------------------------------------------------------------
//	This is a patch because when the default value does not exist, RegQueryValueEx() always returns
//	an empty string with the ERROR_SUCCESS error code.

	if ( (pcszValueName == 0) || (_tcslen( pcszValueName ) == 0) )	// Ask for the default value?
	{
		lResult1 = TT_RegTestKey( hRootKey, pcszKey, 0, &nDefaultValueCount, 0 );

		if ( (lResult1 == ERROR_SUCCESS) && (nDefaultValueCount == 0) ) lResult1 = ERROR_FILE_NOT_FOUND;
	}
	else lResult1 = ERROR_SUCCESS;

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

	if ( lResult1 == ERROR_SUCCESS )
	{
		if ( (lResult1 = RegOpenKeyEx( hRootKey, pcszKey, 0, KEY_READ, &hkCurrent )) == ERROR_SUCCESS )
		{
			dwSize	= sizeof( *pnValue );
			lResult1 = RegQueryValueEx( hkCurrent, pcszValueName, 0, &dwType, (LPBYTE)pnValue, &dwSize );
			lResult2 = RegCloseKey( hkCurrent );

			if ( (lResult1 == ERROR_SUCCESS) && (dwType != REG_DWORD) ) lResult1 = ERROR_INVALID_DATATYPE;

			if ( (lResult1 == ERROR_SUCCESS) && (lResult2 != ERROR_SUCCESS) ) lResult1 = lResult2;
		}
	}

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

	if ( lResult1 != ERROR_SUCCESS )	*(pnValue) = cnDefaultValue;

	return( lResult1 );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2001-11-23©  Modified: 2015-07-22©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: ERROR_OUTOFMEMORY, ERROR_BADKEY, ERROR_FILE_NOT_FOUND or ERROR_SUCCESS.						//
//																																	//
// Note:	If result is not ERROR_SUCCESS then contents of 'pnSubKeyCount', 'pnDefaultValueCount'		//
//			and 'pnNonDefaultValueCount' are set to 0.  Boolean pointers maybe set to 0 if their		//
//			respective result is not needed.																				//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

#define	TT_MAX_KEY_LENGTH		(255 + EOS_CHAR_COUNT)

DWORD TT_RegTestKey( HKEY hRootKey, const char *pcszKey, int *pnSubKeyCount, int *pnDefaultValueCount, int *pnNonDefaultValueCount )
{
   HKEY		hkCurrent = 0;
	char	  *pszKeyOrValueName;
	int		nSubKeyCount, nDefaultValueCount, nNonDefaultValueCount;
	long		lResult1, lResult2;
	DWORD		dwKeyOrValueNameLength;

	nSubKeyCount = nDefaultValueCount = nNonDefaultValueCount = 0;

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

	if ( (pszKeyOrValueName = new char [TT_MAX_KEY_LENGTH]) != 0 )
	{
		if ( (pcszKey != 0) && (_tcslen( pcszKey ) != 0) )	//	Do not allow 0 or empty key name
		{
			if ( (lResult1 = RegOpenKeyEx( hRootKey, pcszKey, 0, KEY_READ, &hkCurrent )) == ERROR_SUCCESS )
			{

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

				for( ; lResult1 == ERROR_SUCCESS; nSubKeyCount++ )
				{
					dwKeyOrValueNameLength = TT_MAX_KEY_LENGTH;
					lResult1 = RegEnumKeyEx( hkCurrent, nSubKeyCount, pszKeyOrValueName, &dwKeyOrValueNameLength, 0, 0, 0, 0 );

					if ( lResult1 == ERROR_NO_MORE_ITEMS )
					{
						lResult1 = ERROR_SUCCESS;
						break;
					}
				}

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

				for( ; lResult1 == ERROR_SUCCESS; nNonDefaultValueCount++ )
				{
					dwKeyOrValueNameLength = TT_MAX_KEY_LENGTH;
					lResult1 = RegEnumValue( hkCurrent, nNonDefaultValueCount, pszKeyOrValueName, &dwKeyOrValueNameLength, 0, 0, 0, 0 );
 
					if ( lResult1 == ERROR_NO_MORE_ITEMS )
					{
						nNonDefaultValueCount -= nDefaultValueCount;
						lResult1 = ERROR_SUCCESS;
						break;
					}
					else if ( lResult1 == ERROR_SUCCESS )
					{
						if ( _tcslen( pszKeyOrValueName ) == 0 ) nDefaultValueCount++;	// Only one per Key.
					}
				}

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

				lResult2 = RegCloseKey( hkCurrent );

				if ( (lResult1 == ERROR_SUCCESS) && (lResult2 != ERROR_SUCCESS) ) lResult1 = lResult2;
			}
		}
		else
		{
			lResult1 = ERROR_BADKEY;
		}

		delete [] pszKeyOrValueName;
		pszKeyOrValueName = 0;
	}
	else
	{
		lResult1 = ERROR_OUTOFMEMORY;
	}
	
//---------------------------------------------------------------------------------------------------

	if ( lResult1 != ERROR_SUCCESS ) nSubKeyCount = nDefaultValueCount = nNonDefaultValueCount = 0;

	if ( pnSubKeyCount			 != 0 ) pnSubKeyCount[0]			 = nSubKeyCount;
	if ( pnDefaultValueCount	 != 0 ) pnDefaultValueCount[0]	 = nDefaultValueCount;
	if ( pnNonDefaultValueCount != 0 ) pnNonDefaultValueCount[0] = nNonDefaultValueCount;

	return( lResult1 );
}

#undef	TT_MAX_KEY_LENGTH


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-07-01©	//
//																																	//
//	Purpose:	Loads the information of timer 'cunTimerId' from the Registry.									//
//																																	//
//	'pszLabel': This buffer must contain at least 'TT_TimerLabel_MaxBufCnt' elements including the	//
//					NULL terminator.																							//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

void TT_LoadTimerInfoFromRegistry( const unsigned int cunTimerId, LPTSTR pszLabel, int *pnValue, int *pnUnitType, int *pnEventId )
{
	LPTSTR	pszTmp;
	int		nValue, nValue_DfltVal, nUnitType, nUnitType_DfltVal, nEventId, nEventId_DfltVal;
	CString	strLabel_DfltVal, strTimerKeyName, strRegKeyName;
	
//---------------------------------------------------------------------------------------------------

	if ( cunTimerId == 3 )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_3 );
		nValue_DfltVal		= TT_REG_VAL__Timer_Value__DFLT_VALUE_3;
		nUnitType_DfltVal = TT_REG_VAL__Timer_Unit__DFLT_VALUE_3;
		nEventId_DfltVal  = TT_REG_VAL__Timer_Event__DFLT_VALUE_3;
	}
	else if ( cunTimerId == 2 )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_2 );
		nValue_DfltVal		= TT_REG_VAL__Timer_Value__DFLT_VALUE_2;
		nUnitType_DfltVal = TT_REG_VAL__Timer_Unit__DFLT_VALUE_2;
		nEventId_DfltVal  = TT_REG_VAL__Timer_Event__DFLT_VALUE_2;
	}
	else	//	if ( cunTimerId == 1 )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_1 );
		nValue_DfltVal		= TT_REG_VAL__Timer_Value__DFLT_VALUE_1;
		nUnitType_DfltVal = TT_REG_VAL__Timer_Unit__DFLT_VALUE_1;
		nEventId_DfltVal  = TT_REG_VAL__Timer_Event__DFLT_VALUE_1;
	}

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

	strTimerKeyName.Format( TT_REG_KEY__Timer__, cunTimerId );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strTimerKeyName );

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

	if ( pszLabel != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszLabel, pszTmp, (TT_TimerLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszLabel[TT_TimerLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszLabel );
		}
		else _tcsEmpty( pszLabel );

		if ( _tcsIsEmpty( pszLabel ) ) _tcscpy_s( pszLabel, TT_TimerLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	//	'TT_REG_VAR__Timer_Unit' must be read before 'TT_REG_VAR__Timer_Value'.
	TT_RegReadInteger( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Unit, nUnitType_DfltVal, &nUnitType );

	if ( (nUnitType < TT_REG_VAL__Timer_Unit__FIRST_VALUE) || (nUnitType > TT_REG_VAL__Timer_Unit__LAST_VALUE) )
	{
		nUnitType = nUnitType_DfltVal;
	}

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

	TT_RegReadInteger( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Value, nValue_DfltVal, &nValue );

	if		  ( nValue < TT_REG_VAL__Timer_Value__Min ) nValue = TT_REG_VAL__Timer_Value__Min;
	else if ( nValue > TT_REG_VAL__Timer_Value__Max ) nValue = TT_REG_VAL__Timer_Value__Max;

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

	TT_RegReadInteger( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Event, nEventId_DfltVal, &nEventId );

	if ( (nEventId < TT_REG_VAL__Timer_Event__FIRST_VALUE) || (nEventId > TT_REG_VAL__Timer_Event__LAST_VALUE) )
	{
		nEventId = nEventId_DfltVal;
	}

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

	if ( pnValue	 != NULL ) *(pnValue)	 = nValue;
	if ( pnUnitType != NULL ) *(pnUnitType) = nUnitType;
	if ( pnEventId  != NULL ) *(pnEventId)  = nEventId;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-07-01©	//
//																																	//
//	Purpose:	Saves the information of timer 'cunTimerId' to the Registry.									//
//																																	//
//	Result: See the Registry functions for possible returned values.											//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int TT_SaveTimerInfoToRegistry( const unsigned int cunTimerId, LPCTSTR pcszLabel, const int cnValue,
										  const int cnUnitType, const int cnEventId )
{
	long		lResult1, lResult2, lResult3, lResult4;
	CString	strTimerKeyName, strRegKeyName;

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

	strTimerKeyName.Format( TT_REG_KEY__Timer__, cunTimerId );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strTimerKeyName );

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

	lResult1 = TT_RegWriteString(  HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Label, ((pcszLabel != NULL) ? pcszLabel : _T("")) );
	lResult2 = TT_RegWriteInteger( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Value, cnValue	  );
	lResult3 = TT_RegWriteInteger( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Unit , cnUnitType );
	lResult4 = TT_RegWriteInteger( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__Timer_Event, cnEventId  );

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

	if ( lResult1 == ERROR_SUCCESS )
	{
		if		  ( lResult2 != ERROR_SUCCESS ) lResult1 = lResult2;
		else if ( lResult3 != ERROR_SUCCESS ) lResult1 = lResult3;
		else if ( lResult4 != ERROR_SUCCESS ) lResult1 = lResult4;
	}

	return( lResult1 );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-07-01©	//
//																																	//
//	Purpose:	Loads the application settings from the Registry.													//
//																																	//
//	'pszExtSndLabel#': This buffer must contain at least 'TT_ExtSndLabel_MaxBufCnt' elements			//
//							 including the NULL terminator.																//
//																																	//
//	'pszExtSndFileName#': This buffer must contain at least 'TT_ExtSndFileName_MaxBufCnt' elements	//
//								 including the NULL terminator.															//
//																																	//
//	'pszOpenFileLabel#': This buffer must contain at least 'TT_OpenFileLabel_MaxBufCnt' elements		//
//							   including the NULL terminator.															//
//																																	//
//	'pszOpenFileName#': This buffer must contain at least 'TT_OpenFileName_MaxBufCnt' elements		//
//							  including the NULL terminator.																//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

void TT_LoadMiscSettingsFromRegistry( bool *pbIsKeepWndOnTop, bool *pbIsShowInTitleBar, bool *pbIsFlashWndOnTimerUp, 
												  bool *pbIsUseAltIconOnTimerUp, bool *pbIsDisplaySmartCursors,
												  LPTSTR pszExtSndLabel1, LPTSTR pszExtSndFileName1, LPTSTR pszExtSndLabel2,
												  LPTSTR pszExtSndFileName2, LPTSTR pszExtSndLabel3, LPTSTR pszExtSndFileName3,
												  LPTSTR pszOpenFileLabel1, LPTSTR pszOpenFileName1, LPTSTR pszOpenFileLabel2,
												  LPTSTR pszOpenFileName2, LPTSTR pszOpenFileLabel3, LPTSTR pszOpenFileName3 )
{
	LPTSTR	pszTmp;
	int		nKeepWindowOnTop, nKeepWindowOnTop_DfltVal, nShowTimerInTitleBar, nShowTimerInTitleBar_DfltVal;
	int		nFlashWndOnTimerUp, nFlashWndOnTimerUp_DfltVal, nUseAltIconOnTimerUp, nUseAltIconOnTimerUp_DfltVal;
	int		nDisplaySmartCursors, nDisplaySmartCursors_DfltVal;
	CString	strLabel_DfltVal, strExtSndKeyName, strOpenFileKeyName, strRegKeyName;

//===================================================================================================

	nKeepWindowOnTop_DfltVal = TRUE;
	TT_RegReadInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__KeepWindowOnTop, nKeepWindowOnTop_DfltVal, &nKeepWindowOnTop );

	if ( pbIsKeepWndOnTop != NULL ) *(pbIsKeepWndOnTop) = (nKeepWindowOnTop != 0);

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

	nShowTimerInTitleBar_DfltVal = TRUE;
	TT_RegReadInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__ShowTimerInTitleBar, nShowTimerInTitleBar_DfltVal, &nShowTimerInTitleBar );

	if ( pbIsShowInTitleBar != NULL ) *(pbIsShowInTitleBar) = (nShowTimerInTitleBar != 0);

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

	nFlashWndOnTimerUp_DfltVal = TRUE;
	TT_RegReadInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__FlashWndOnTimerUp, nFlashWndOnTimerUp_DfltVal, &nFlashWndOnTimerUp );

	if ( pbIsFlashWndOnTimerUp != NULL ) *(pbIsFlashWndOnTimerUp) = (nFlashWndOnTimerUp != 0);

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

	nUseAltIconOnTimerUp_DfltVal = TRUE;
	TT_RegReadInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__UseAltIconOnTimerUp, nUseAltIconOnTimerUp_DfltVal, &nUseAltIconOnTimerUp );

	if ( pbIsUseAltIconOnTimerUp != NULL ) *(pbIsUseAltIconOnTimerUp) = (nUseAltIconOnTimerUp != 0);

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

	nDisplaySmartCursors_DfltVal = TRUE;
	TT_RegReadInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__DisplaySmartCursors, nDisplaySmartCursors_DfltVal, &nDisplaySmartCursors );

	if ( pbIsDisplaySmartCursors != NULL ) *(pbIsDisplaySmartCursors) = (nDisplaySmartCursors != 0);

//===================================================================================================

	strExtSndKeyName.Format( TT_REG_KEY__ExternalSound__, 1 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strExtSndKeyName );

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

	if ( pszExtSndLabel1 != NULL )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_1 );

		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszExtSndLabel1, pszTmp, (TT_ExtSndLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszExtSndLabel1[TT_ExtSndLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszExtSndLabel1 );
		}
		else _tcsEmpty( pszExtSndLabel1 );

		if ( _tcsIsEmpty( pszExtSndLabel1 ) ) _tcscpy_s( pszExtSndLabel1, TT_ExtSndLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	if ( pszExtSndFileName1 != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_FileName )) != 0 )
		{
			_tcsncpy( pszExtSndFileName1, pszTmp, (TT_ExtSndFileName_MaxBufCnt - EOS_CHAR_COUNT) );
			pszExtSndFileName1[TT_ExtSndFileName_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
		}
		else _tcsEmpty( pszExtSndFileName1 );
	}

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

	strExtSndKeyName.Format( TT_REG_KEY__ExternalSound__, 2 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strExtSndKeyName );

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

	if ( pszExtSndLabel2 != NULL )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_2 );

		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszExtSndLabel2, pszTmp, (TT_ExtSndLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszExtSndLabel2[TT_ExtSndLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszExtSndLabel2 );
		}
		else _tcsEmpty( pszExtSndLabel2 );

		if ( _tcsIsEmpty( pszExtSndLabel2 ) ) _tcscpy_s( pszExtSndLabel2, TT_ExtSndLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	if ( pszExtSndFileName2 != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_FileName )) != 0 )
		{
			_tcsncpy( pszExtSndFileName2, pszTmp, (TT_ExtSndFileName_MaxBufCnt - EOS_CHAR_COUNT) );
			pszExtSndFileName2[TT_ExtSndFileName_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
		}
		else _tcsEmpty( pszExtSndFileName2 );
	}

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

	strExtSndKeyName.Format( TT_REG_KEY__ExternalSound__, 3 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strExtSndKeyName );

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

	if ( pszExtSndLabel3 != NULL )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_3 );

		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszExtSndLabel3, pszTmp, (TT_ExtSndLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszExtSndLabel3[TT_ExtSndLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszExtSndLabel3 );
		}
		else _tcsEmpty( pszExtSndLabel3 );

		if ( _tcsIsEmpty( pszExtSndLabel3 ) ) _tcscpy_s( pszExtSndLabel3, TT_ExtSndLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	if ( pszExtSndFileName3 != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_FileName )) != 0 )
		{
			_tcsncpy( pszExtSndFileName3, pszTmp, (TT_ExtSndFileName_MaxBufCnt - EOS_CHAR_COUNT) );
			pszExtSndFileName3[TT_ExtSndFileName_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
		}
		else _tcsEmpty( pszExtSndFileName3 );
	}

//===================================================================================================

	strOpenFileKeyName.Format( TT_REG_KEY__OpenFile__, 1 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strOpenFileKeyName );

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

	if ( pszOpenFileLabel1 != NULL )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_1 );

		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszOpenFileLabel1, pszTmp, (TT_OpenFileLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszOpenFileLabel1[TT_OpenFileLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszOpenFileLabel1 );
		}
		else _tcsEmpty( pszOpenFileLabel1 );

		if ( _tcsIsEmpty( pszOpenFileLabel1 ) ) _tcscpy_s( pszOpenFileLabel1, TT_OpenFileLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	if ( pszOpenFileName1 != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_FileName )) != 0 )
		{
			_tcsncpy( pszOpenFileName1, pszTmp, (TT_OpenFileName_MaxBufCnt - EOS_CHAR_COUNT) );
			pszOpenFileName1[TT_OpenFileName_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
		}
		else _tcsEmpty( pszOpenFileName1 );
	}

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

	strOpenFileKeyName.Format( TT_REG_KEY__OpenFile__, 2 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strOpenFileKeyName );

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

	if ( pszOpenFileLabel2 != NULL )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_2 );

		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszOpenFileLabel2, pszTmp, (TT_OpenFileLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszOpenFileLabel2[TT_OpenFileLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszOpenFileLabel2 );
		}
		else _tcsEmpty( pszOpenFileLabel2 );

		if ( _tcsIsEmpty( pszOpenFileLabel2 ) ) _tcscpy_s( pszOpenFileLabel2, TT_OpenFileLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	if ( pszOpenFileName2 != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_FileName )) != 0 )
		{
			_tcsncpy( pszOpenFileName2, pszTmp, (TT_OpenFileName_MaxBufCnt - EOS_CHAR_COUNT) );
			pszOpenFileName2[TT_OpenFileName_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
		}
		else _tcsEmpty( pszOpenFileName2 );
	}

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

	strOpenFileKeyName.Format( TT_REG_KEY__OpenFile__, 3 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strOpenFileKeyName );

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

	if ( pszOpenFileLabel3 != NULL )
	{
		strLabel_DfltVal.LoadString( IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_3 );

		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_Label, strLabel_DfltVal )) != 0 )
		{
			_tcsncpy( pszOpenFileLabel3, pszTmp, (TT_OpenFileLabel_MaxBufCnt - EOS_CHAR_COUNT) );
			pszOpenFileLabel3[TT_OpenFileLabel_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
			TT_TrimString( pszOpenFileLabel3 );
		}
		else _tcsEmpty( pszOpenFileLabel3 );

		if ( _tcsIsEmpty( pszOpenFileLabel3 ) ) _tcscpy_s( pszOpenFileLabel3, TT_OpenFileLabel_MaxBufCnt, strLabel_DfltVal );
	}

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

	if ( pszOpenFileName3 != NULL )
	{
		if ( (pszTmp = TT_RegGetString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_FileName )) != 0 )
		{
			_tcsncpy( pszOpenFileName3, pszTmp, (TT_OpenFileName_MaxBufCnt - EOS_CHAR_COUNT) );
			pszOpenFileName3[TT_OpenFileName_MaxBufCnt - EOS_CHAR_COUNT] = _T('\0');
			::GlobalFree( pszTmp );
		}
		else _tcsEmpty( pszOpenFileName3 );
	}
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-07-01©	//
//																																	//
//	Purpose:	Saves the application settings to the Registry.														//
//																																	//
//	Result: See the Registry functions for possible returned values.											//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int TT_SaveMiscSettingsToRegistry( const bool cbIsKeepWndOnTop, const bool cbIsShowInTitleBar, const bool cbIsFlashWndOnTimerUp,
											  const bool cbIsUseAltIconOnTimerUp, const bool cbIsDisplaySmartCursors,
									 		  LPCTSTR pcszExtSndLabel1, LPCTSTR pcszExtSndFileName1, LPCTSTR pcszExtSndLabel2,
											  LPCTSTR pcszExtSndFileName2, LPCTSTR pcszExtSndLabel3, LPCTSTR pcszExtSndFileName3,
											  LPCTSTR pcszOpenFileLabel1, LPCTSTR pcszOpenFileName1, LPCTSTR pcszOpenFileLabel2,
											  LPCTSTR pcszOpenFileName2, LPCTSTR pcszOpenFileLabel3, LPCTSTR pcszOpenFileName3 )
{
	long		lResult01, lResult02, lResult03, lResult04, lResult05;
	long		lResult11, lResult12, lResult13, lResult14, lResult15, lResult16;
	long		lResult21, lResult22, lResult23, lResult24, lResult25, lResult26;
	CString	strExtSndKeyName, strOpenFileKeyName, strRegKeyName;

//===================================================================================================

	lResult01 = TT_RegWriteInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__KeepWindowOnTop	 , (int)cbIsKeepWndOnTop		  );
	lResult02 = TT_RegWriteInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__ShowTimerInTitleBar, (int)cbIsShowInTitleBar		  );
	lResult03 = TT_RegWriteInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__FlashWndOnTimerUp	 , (int)cbIsFlashWndOnTimerUp	  );
	lResult04 = TT_RegWriteInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__UseAltIconOnTimerUp, (int)cbIsUseAltIconOnTimerUp );
	lResult05 = TT_RegWriteInteger( HKEY_CURRENT_USER, TT_strREG_KEY__ADELUC_TTn, TT_REG_VAR__DisplaySmartCursors, (int)cbIsDisplaySmartCursors );

//===================================================================================================

	strExtSndKeyName.Format( TT_REG_KEY__ExternalSound__, 1 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strExtSndKeyName );

	lResult11 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_Label,
											 ((pcszExtSndLabel1 != NULL) ? pcszExtSndLabel1 : _T("")) );

	lResult12 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_FileName,
											 ((pcszExtSndFileName1 != NULL) ? pcszExtSndFileName1 : _T("")) );

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

	strExtSndKeyName.Format( TT_REG_KEY__ExternalSound__, 2 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strExtSndKeyName );

	lResult13 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_Label,
											 ((pcszExtSndLabel2 != NULL) ? pcszExtSndLabel2 : _T("")) );

	lResult14 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_FileName,
											 ((pcszExtSndFileName2 != NULL) ? pcszExtSndFileName2 : _T("")) );

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

	strExtSndKeyName.Format( TT_REG_KEY__ExternalSound__, 3 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strExtSndKeyName );

	lResult15 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_Label,
											 ((pcszExtSndLabel3 != NULL) ? pcszExtSndLabel3 : _T("")) );

	lResult16 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__ExtSnd_FileName,
											 ((pcszExtSndFileName3 != NULL) ? pcszExtSndFileName3 : _T("")) );

//===================================================================================================

	strOpenFileKeyName.Format( TT_REG_KEY__OpenFile__, 1 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strOpenFileKeyName );

	lResult21 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_Label,
											 ((pcszOpenFileLabel1 != NULL) ? pcszOpenFileLabel1 : _T("")) );

	lResult22 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_FileName,
											 ((pcszOpenFileName1 != NULL) ? pcszOpenFileName1 : _T("")) );

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

	strOpenFileKeyName.Format( TT_REG_KEY__OpenFile__, 2 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strOpenFileKeyName );

	lResult23 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_Label,
											 ((pcszOpenFileLabel2 != NULL) ? pcszOpenFileLabel2 : _T("")) );

	lResult24 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_FileName,
											 ((pcszOpenFileName2 != NULL) ? pcszOpenFileName2 : _T("")) );

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

	strOpenFileKeyName.Format( TT_REG_KEY__OpenFile__, 3 );
	strRegKeyName.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, (LPCTSTR)strOpenFileKeyName );

	lResult25 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_Label,
											 ((pcszOpenFileLabel3 != NULL) ? pcszOpenFileLabel3 : _T("")) );

	lResult26 = TT_RegWriteString( HKEY_CURRENT_USER, strRegKeyName, TT_REG_VAR__OpenFile_FileName,
											 ((pcszOpenFileName3 != NULL) ? pcszOpenFileName3 : _T("")) );

//===================================================================================================

	if ( lResult01 == ERROR_SUCCESS )
	{
		if		  ( lResult02 != ERROR_SUCCESS ) lResult01 = lResult02;
		else if ( lResult03 != ERROR_SUCCESS ) lResult01 = lResult03;
		else if ( lResult04 != ERROR_SUCCESS ) lResult01 = lResult04;
		else if ( lResult05 != ERROR_SUCCESS ) lResult01 = lResult05;
		else if ( lResult11 != ERROR_SUCCESS ) lResult01 = lResult11;
		else if ( lResult12 != ERROR_SUCCESS ) lResult01 = lResult12;
		else if ( lResult13 != ERROR_SUCCESS ) lResult01 = lResult13;
		else if ( lResult14 != ERROR_SUCCESS ) lResult01 = lResult14;
		else if ( lResult15 != ERROR_SUCCESS ) lResult01 = lResult15;
		else if ( lResult16 != ERROR_SUCCESS ) lResult01 = lResult16;
		else if ( lResult21 != ERROR_SUCCESS ) lResult01 = lResult21;
		else if ( lResult22 != ERROR_SUCCESS ) lResult01 = lResult22;
		else if ( lResult23 != ERROR_SUCCESS ) lResult01 = lResult23;
		else if ( lResult24 != ERROR_SUCCESS ) lResult01 = lResult24;
		else if ( lResult25 != ERROR_SUCCESS ) lResult01 = lResult25;
		else if ( lResult26 != ERROR_SUCCESS ) lResult01 = lResult26;
	}

	return( lResult01 );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2003-11-17©  Modified: 2016-03-22©	//
//																																	//
//	Purpose:																														//
//																																	//
// Note:	'pun64FileVersion', 'pszFileVersion', 'pun64ProductVersion' and 'pszProductVersion'			//
//			may be set to 0.  If 'pszFileVersion' or 'pszProductVersion' are not 0 then they must		//
//			contain enough space for TT_MINSTRBUF__VERSION characters, NULL character included.			//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_SHGetVersionNumbers( LPCTSTR pcszFileName, unsigned __int64 *pun64FileVersion, LPTSTR pszFileVersion,
																   unsigned __int64 *pun64ProductVersion, LPTSTR pszProductVersion )
{
	bool						bStatus				 = FALSE;
	LPVOID					pData					 = 0;
	unsigned __int64		un64FileVersion	 = 0;
	unsigned __int64		un64ProductVersion = 0;
	DWORD						dwUseless, dwFVISize, dwFFISize, dwVer1, dwVer2;
	VS_FIXEDFILEINFO	  *pFFI;
	TCHAR						szFileVersion[TT_MINSTRBUF__VERSION]	 = _T("0.0.0.0");
	TCHAR						szProductVersion[TT_MINSTRBUF__VERSION] = _T("0.0.0.0");

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

	dwFVISize = GetFileVersionInfoSize( (LPTSTR)pcszFileName, &dwUseless );

	if ( dwFVISize != 0 ) 
	{ 
		if ( (pData = malloc( dwFVISize )) != 0 )
		{
			if ( GetFileVersionInfo( (LPTSTR)pcszFileName, 0, dwFVISize, pData ) != 0 )
			{
				if ( VerQueryValue( pData, _T("\\"), (LPVOID *)&pFFI, (PUINT)&dwFFISize ) )
				{
					bStatus = TRUE;

					dwVer1 = pFFI->dwFileVersionMS; 
					dwVer2 = pFFI->dwFileVersionLS; 
					un64FileVersion = (((unsigned __int64)dwVer1 << 32) | dwVer2);
					_stprintf( szFileVersion, _T("%ld.%ld.%ld.%ld"), HIWORD( dwVer1 ), LOWORD( dwVer1 ), HIWORD( dwVer2 ), LOWORD( dwVer2 ) );

					dwVer1 = pFFI->dwProductVersionMS; 
					dwVer2 = pFFI->dwProductVersionLS; 
					un64ProductVersion = (((unsigned __int64)dwVer1 << 32) | dwVer2);
					_stprintf( szProductVersion, _T("%ld.%ld.%ld.%ld"), HIWORD( dwVer1 ), LOWORD( dwVer1 ), HIWORD( dwVer2 ), LOWORD( dwVer2 ) );
				}
			}

			free( pData );
			pData = 0;
		}
	}

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

	if ( pun64FileVersion	 != 0 ) *(pun64FileVersion) = un64FileVersion;
	if ( pszFileVersion		 != 0 ) _tcscpy( pszFileVersion, szFileVersion );
	if ( pun64ProductVersion != 0 ) *(pun64ProductVersion) = un64ProductVersion;
	if ( pszProductVersion	 != 0 ) _tcscpy( pszProductVersion, szProductVersion );

	return( bStatus ); 
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2012-08-21©  Modified: 2016-03-21©	//
//																																	//
//	Purpose:	Patch for the GetWindowRect() function used in Vista and more recent OS.					//
//				The difference in the results from these two functions is only noticeable when a		 	//
//				window, that is not resizable, has a border that is not thin.									//
//																																	//
//	Result: Returns the real size of the window rectangle that has its border thickness increased 	//
//			  by the Aero feature introduced in Vista.																//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_GetWindowBoundsRect( HWND hWnd, LPRECT lpRect )
{
	bool		bStatus = FALSE;
	BOOL		nIsEnabled;

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

	if ( lpRect != 0 )
	{
		if ( TT_hDwmApiDll != 0 )	// Do we need to fix the mess created by the Aero nice looking feature introduced in Vista?
		{
			if ( (TT_pfnDwmIsCompositionEnabled != NULL) && (TT_pfnDwmGetWindowAttribute != NULL) )
			{
				if ( SUCCEEDED( TT_pfnDwmIsCompositionEnabled( &nIsEnabled ) ) && (nIsEnabled != 0) )
				{
					bStatus = SUCCEEDED( TT_pfnDwmGetWindowAttribute( hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, lpRect, sizeof( RECT ) ) );
				}
			}
		} 

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

		if ( !bStatus ) bStatus = (::GetWindowRect( hWnd, lpRect ) != 0);	// Use old way of getting the window rectandle?
	}

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2012-08-28©  Modified: 2016-03-21©	//
//																																	//
//	Purpose: Returns TRUE if we are running under Vista or more recent OS and the Aero feature is	//
//				turned on.																										//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_IsAeroEnabled()
{
	BOOL	nIsEnabled = FALSE;

	if ( (TT_hDwmApiDll != 0) && (TT_pfnDwmIsCompositionEnabled != NULL) )	// Are we running under Vista or more recent OS?
	{
		if ( !SUCCEEDED( TT_pfnDwmIsCompositionEnabled( &nIsEnabled ) ) )
		{
			nIsEnabled = FALSE;	//	Just in case its value changed.
		}
	} 

	return( (nIsEnabled != 0) );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2008-09-12©  Modified: 2012-08-23©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'prectWorkArea': May be 0 if you do not need this information.  Will contain the values			//
//						  about the WorkArea of the target monitor.													//
//																																	//
//	'prectMonitor': May be 0 if you do not need this information.  Will contain the values				//
//						 about the target monitor.																			//
//																																	//
//	'pMonitorInfoEx': May be 0 if you do not need this information.  Will contain all the				//
//						   available information about the target monitor.											//
//																																	//
//	'cdwFlags': See MonitorFromRect() for possible values.  Default is MONITOR_DEFAULTTONEAREST.		//
//																																	//
//	Result: Returns FALSE only if functions MonitorFromRect() or GetMonitorInfo() failed and			//
//			  default values of primary display are returned instead.  Otherwise returns TRUE.			//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_GetMonitorAndWorkAreaInfoFromRect( const CRect & rcrectWindow, CRect *prectWorkArea, CRect *prectMonitor,
														 LPMONITORINFOEX pMonitorInfoEx, const DWORD cdwFlags )
{
	bool					bStatus = TRUE;
	CRect					rectMonitor, rectWorkArea;
	HMONITOR				hMonitor;
	MONITORINFOEX		monitorInfoEx;
  					 
	monitorInfoEx.cbSize = sizeof( MONITORINFOEX );

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

	if ( ((hMonitor = MonitorFromRect( rcrectWindow, cdwFlags )) != 0) && (GetMonitorInfo( hMonitor, &monitorInfoEx ) != 0) )
	{
		rectWorkArea = monitorInfoEx.rcWork;
		rectMonitor  = monitorInfoEx.rcMonitor;
	}
	else
	{
		bStatus = FALSE;		//	Indicates we are using default values.

		rectMonitor.left   = rectMonitor.top = 0;
		rectMonitor.right  = ::GetSystemMetrics( SM_CXSCREEN );
		rectMonitor.bottom = ::GetSystemMetrics( SM_CYSCREEN );

		if ( !SystemParametersInfo( SPI_GETWORKAREA, 0, &rectWorkArea, 0 ) ) rectWorkArea = rectMonitor;

		memset( &monitorInfoEx, 0, sizeof( MONITORINFOEX ) );
		monitorInfoEx.cbSize		= sizeof( MONITORINFOEX );
		monitorInfoEx.rcMonitor = rectMonitor;
		monitorInfoEx.rcWork		= rectWorkArea;
		monitorInfoEx.dwFlags	= MONITORINFOF_PRIMARY;
		_tcscpy( monitorInfoEx.szDevice, _T("\\\\.\\DISPLAY1") );
	}

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

	if ( prectWorkArea  != 0 ) *(prectWorkArea ) = rectWorkArea;
	if ( prectMonitor   != 0 ) *(prectMonitor  ) = rectMonitor;
	if ( pMonitorInfoEx != 0 ) *(pMonitorInfoEx) = monitorInfoEx;

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-28©  Modified: 2016-06-30©	//
//																																	//
//	Purpose:	Encloses 'pszPath' in quotation marks unless it is already enclosed.							//
//																																	//
//	Note:	Unlike 'PathQuoteSpaces()' this function will always enclose 'pszPath' in quotation marks	//
//			even if 'pszPath' contains no space character.  If 'pszPath' is empty then a string			//
//			containing two quotation marks will be returned unless 'cbAddQuotesEvenIfEmpty' is FALSE.	//
//																																	//
// 'pszPath': Must point on a buffer of at least 'MAX_PATH' elements.										//
//																																	//
//	Result: Returns TRUE if 'pszPath' was or it is now enclosed in in quotation marks or if			//
//			  'pszPath' is empty and 'cbAddQuotesEvenIfEmpty' is FALSE.  Returns FALSE if 'pszPath'	//
//			  is unchanged because adding quotation marks requires a buffer larger than 'MAX_PATH'.	//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_PathAddQuoteSpaces( LPTSTR pszPath, const bool cbAddQuotesEvenIfEmpty )
{
	bool		bStatus	 = FALSE;
	size_t	sztLength = _tcslen( pszPath );
	TCHAR		szPathTmp[MAX_PATH];

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

	if ( ((sztLength == 0) && cbAddQuotesEvenIfEmpty) || (sztLength == 1) ||
		  ((sztLength >= 2) && ((pszPath[0] != _T('\"')) || (pszPath[sztLength - 1] != _T('\"')))) )
	{
		if ( (sztLength < (MAX_PATH - EOS_CHAR_COUNT - 2)) )
		{
			_tcscpy( szPathTmp, pszPath );
			pszPath[0] = _T('\"');
			_tcscpy( &pszPath[1], szPathTmp );
			pszPath[sztLength + 1] = _T('\"');
			pszPath[sztLength + 2] = _T('\0');
			bStatus = TRUE;
		}
	}
	else bStatus = TRUE;		//	Already enclosed in quotation marks.

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-11-22©  Modified: 2012-08-30©	//
//																																	//
//	Purpose:	Center 'hwndChild' window on 'hwndParent' window or Work Area if 'hwndParent' is	set	//
//				to 0.  The 'hwndChild' window will be always entirely visible inside the Work Area.		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

void TT_CenterWindow( HWND hwndChild, HWND hwndParent )
{
	CRect		rectChild, rectParent, rectWorkArea, rectMonitorBait, rectDlgMaxBounds;
	int		nLeft, nTop, nExtraBorderX, nExtraBorderY;

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

	GetWindowRect( hwndChild, &rectChild );
	TT_GetWindowBoundsRect( hwndChild, &rectDlgMaxBounds );
	nExtraBorderX = ((rectDlgMaxBounds.Width()  - rectChild.Width() ) / 2);
	nExtraBorderY = ((rectDlgMaxBounds.Height() - rectChild.Height()) / 2);

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

	if ( hwndParent != 0 ) GetWindowRect( hwndParent, &rectMonitorBait );
	else						  rectMonitorBait = rectChild;

	TT_GetMonitorAndWorkAreaInfoFromRect( rectMonitorBait, &rectWorkArea );

	if ( hwndParent != 0 ) rectParent = rectMonitorBait;
	else						  rectParent = rectWorkArea;

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

	nLeft = rectParent.left + ((rectParent.Width()  - rectChild.Width() ) / 2);
	nTop	= rectParent.top  + ((rectParent.Height() - rectChild.Height()) / 2);

	if ( (nLeft + (rectChild.Width() + nExtraBorderX)) > rectWorkArea.right )
		nLeft = (rectWorkArea.right - (rectChild.Width() + nExtraBorderX));

	if ( (nTop + (rectChild.Height() + nExtraBorderY)) > rectWorkArea.bottom )
		nTop = (rectWorkArea.bottom - (rectChild.Height() + nExtraBorderY));

	if ( (nLeft - nExtraBorderX) < rectWorkArea.left ) nLeft = (rectWorkArea.left + nExtraBorderX);
	if ( (nTop  - nExtraBorderY) < rectWorkArea.top  ) nTop  = (rectWorkArea.top  + nExtraBorderY);

	SetWindowPos( hwndChild, 0, nLeft, nTop, 0, 0, (SWP_NOSIZE | SWP_NOZORDER) );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2000-11-28©  Modified: 2015-08-09©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

CString TT_GetWindowText( HWND hwnd )
{
	char		  *pszTmp;
	CString		strTmp;
	int			nTmpStrLength;

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

	nTmpStrLength = GetWindowTextLength( hwnd );

	if ( (pszTmp = strTmp.GetBuffer( nTmpStrLength )) != 0 )
	{
		nTmpStrLength = GetWindowText( hwnd, pszTmp, (nTmpStrLength + EOS_CHAR_COUNT) );
		strTmp.ReleaseBuffer( nTmpStrLength );
	}
	else strTmp.Empty();		// Memory error

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

	return( strTmp );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2010-02-05©  Modified: 2016-03-23©	//
//																																	//
//	Purpose: Remove blank spaces from the string.																	//
//				Characters removed are 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x20 and 0xA0. 							//
//																																	//
//	Note: Supports empty strings and strings without blank spaces at left or right.						//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

void TT_TrimStringLeft( LPTSTR pszString )
{
	LPTSTR	pszDst = pszString;

	for( bool bExitLoop = FALSE; !bExitLoop; )
	{
		switch( *(pszString) )
		{
		//	Horizontal Tab, New line, Vertical Tab, Form feed,	Carriage return, Space, Hard space.
		case 0x09:	case 0x0A:	case 0x0B:	case 0x0C:	case 0x0D:	case 0x20:	case 0xA0:
			pszString++;
			break;

		default:
			bExitLoop = TRUE;
			break;
		}
	}

	if ( pszString != pszDst ) while( (*(pszDst++) = *(pszString++)) != _T('\0') );
}

//===================================================================================================

void TT_TrimStringRight( LPTSTR pszString )
{
   size_t	sztLength = _tcslen( pszString );
	
   for( pszString += sztLength; (sztLength > 0); sztLength-- )
	{
		switch( *(--pszString) )
		{
		//	Horizontal Tab, New line, Vertical Tab, Form feed,	Carriage return, Space, Hard space.
		case 0x09:	case 0x0A:	case 0x0B:	case 0x0C:	case 0x0D:	case 0x20:	case 0xA0:
			*(pszString) = _T('\0');
			break;
		}

		if ( *(pszString) != _T('\0') ) break;
	}
}

//===================================================================================================

void TT_TrimString( LPTSTR pszString )
{
	TT_TrimStringLeft( pszString );
	TT_TrimStringRight( pszString );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-02-09©  Modified: 2016-03-25©	//
//																																	//
//	Purpose:	Verifies if the 'TT_WINDOWS_FILE__Notepad_exe' application file is present in a least 	//
//				one of the three possible locations in the Windows folder.  If it is the case, stores 	//
//				the location of the file in *('pstrCommandLine') and its window class name in				//
//				*('pstrWindowClassName').  The window class name is always										//
//				'TT_WINDOWS_WINCLASS_ID__Notepad'.																		//
//																																	//
//	'pstrCommandLine' and 'pstrWindowClassName': May be NULL if you do not need this information.	//
//																																	//
//	Note: The returned value in *('pstrCommandLine') is placed between double quotes.					//
//																																	//
//	Result: Returns TRUE if successful.  Otherwise returns FALSE and empties *('pstrCommandLine')	//
//			  and *('pstrWindowClassName').																				//
//																																	//
//	Note: If no default application executable file can be found then FALSE is returned.				//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_BIT_GetDfltValues_Notepad( CString *pstrCommandLine, CString *pstrWindowClassName )
{
	bool								bAppFound = FALSE;
	WIN32_FILE_ATTRIBUTE_DATA	fad;
	TCHAR								szFileName[MAX_PATH];

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

	if ( !bAppFound )
	{
		::GetWindowsDirectory(	szFileName, _countof( szFileName ) );
		::PathAppend( szFileName, TT_WINDOWS_FILE__Notepad_exe );

		if ( (::GetFileAttributesEx( szFileName, GetFileExInfoStandard, &fad ) != 0) &&
			  ((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) )	//	Real file exists?
		{
			bAppFound = TRUE;
		}
	}

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

	if ( !bAppFound )
	{
		::GetSystemDirectory( szFileName, _countof( szFileName ) );
		::PathAppend( szFileName, TT_WINDOWS_FILE__Notepad_exe );

		if ( (::GetFileAttributesEx( szFileName, GetFileExInfoStandard, &fad ) != 0) &&
			  ((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) )	//	Real file exists?
		{
			bAppFound = TRUE;
		}
	}

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

	if ( !bAppFound )
	{
		::GetWindowsDirectory(	szFileName, _countof( szFileName ) );
		::PathAppend( szFileName, _T("SysWOW64") );
		::PathAppend( szFileName, TT_WINDOWS_FILE__Notepad_exe );

		if ( (::GetFileAttributesEx( szFileName, GetFileExInfoStandard, &fad ) != 0) &&
			  ((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) )	//	Real file exists?
		{
			bAppFound = TRUE;
		}
	}

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

	if ( bAppFound )
	{
		if ( pstrCommandLine		 != NULL ) pstrCommandLine->Format( _T("\"%s\""), szFileName );
		if ( pstrWindowClassName != NULL ) *(pstrWindowClassName) = TT_WINDOWS_WINCLASS_ID__Notepad;
	}
	else
	{
		if ( pstrCommandLine		 != NULL ) pstrCommandLine->Empty();
		if ( pstrWindowClassName != NULL ) pstrWindowClassName->Empty();
	}

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

	return( bAppFound );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2015-04-08©  Modified: 2016-03-21©	//
//																																	//
//	Purpose:	Installs all the fonts located in the resource.														//
//																																	//
//	Result: Returns TRUE if successful.  Otherwise returns FALSE.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_InstallPrivateFonts()
{
	bool		bStatus = TRUE;
	HRSRC		hrsrcTDST;
	DWORD		dwResSize, dwFontsInstalledCount;
	HGLOBAL	hglobalFONT;
	PVOID		pvData;

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

	if ( bStatus && ((hrsrcTDST = FindResource( TT_hInst, TT_FONT_FILE_SEGOEUI_TTF, _T("PRIVATE_FONT") )) != 0) &&
			((dwResSize = SizeofResource( TT_hInst, hrsrcTDST )) != 0) )
	{
		if ( (hglobalFONT = LoadResource( TT_hInst, hrsrcTDST )) != 0 )
		{
			if ( (pvData = LockResource( hglobalFONT )) != 0 )
			{
				if ( (TT_hMemFont_SegoeUI_TTF = AddFontMemResourceEx( pvData, dwResSize, 0, &dwFontsInstalledCount)) == 0 ) bStatus = FALSE;

				UnlockResource( hglobalFONT );
				pvData = 0;
			}		
		
			FreeResource( hglobalFONT );
			hglobalFONT = 0;
		}		
	}		

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

	if ( !bStatus )
	{
		TT_UninstallPrivateFonts();
	}

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2015-04-08©  Modified: 2016-03-21©	//
//																																	//
//	Purpose: Closes all the font files previously opened by InstallPrivateFonts().						//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

void TT_UninstallPrivateFonts()
{
	if ( TT_hMemFont_SegoeUI_TTF != 0 )
	{
		RemoveFontMemResourceEx( TT_hMemFont_SegoeUI_TTF );
		TT_hMemFont_SegoeUI_TTF = 0;
	}
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2008-09-10©  Modified: 2016-07-12©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'pcszScreenRegKeyName': Example: "Software\Adeluc\Three Timers V2\MainWindow".						//
//																																	//
//	'pcrectScreenDefault': Contains default values.																	//
//																																	//
//	'prectScreen': May be 0 if you do not need this information.  Will contain the values about		//
//						the requested screen.  The screen is always aligned on WorkArea sides.  If the	//
//						screen dimensions are bigger than the WorkArea dimensions, then the screen will	//
//						be aligned on top/left edges of WorkArea.														//
//																																	//
//	'prectWorkArea': May be 0 if you do not need this information.  Will contain the values about	//
//						  the WorkArea of the target monitor.															//
//																																	//
//	'prectMonitor': May be 0 if you do not need this information.  Will contain the values about		//
//						 the target monitor.																					//
//																																	//
//	Result: Returns TRUE if the returned values come from the Registry.  Otherwise returns FALSE 	//
//			  if the returned values are default values or corrected values.									//
//																																	//
//	Note: The saved application screen position may become invalid if the monitor has been moved		//
//			or if the monitor no more exists.  When this happens the saved position is ignored and		//
//			the screen is centered in its new owner monitor work area with its default size.				//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_LoadScreenInfoFromRegistry( LPCTSTR pcszScreenRegKeyName, const CRect & rcrectScreenDefault,
												CRect *prectScreen, CRect *prectWorkArea, CRect *prectMonitor,
												const bool cbCenterInWorkArea, const bool cbAlignToWorkAreaEdges )
{
	bool		bFound = FALSE;	//	Set to not found by default.
	bool		bUnalteredValuesFromReg;
	CString	strMonitorRect, strTmp;
	CRect		rectScreen1, rectScreen2, rectMonitor, rectWorkArea, rectTmp;
	int		nValue;

//---------------------------------------------------------------------------------------------------
	
	if ( TT_RegReadInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__X, 0, &nValue ) == ERROR_SUCCESS )
	{
		rectScreen1.left = rectScreen1.right = nValue;

		if ( TT_RegReadInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__Y, 0, &nValue ) == ERROR_SUCCESS )
		{
			rectScreen1.top = rectScreen1.bottom = nValue;

			if ( TT_RegReadInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__CX, 0, &nValue ) == ERROR_SUCCESS )
			{
				rectScreen1.right += nValue;

				if ( TT_RegReadInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__CY, 0, &nValue ) == ERROR_SUCCESS )
				{
					rectScreen1.bottom += nValue;
					rectTmp = rectScreen1;
					rectTmp.NormalizeRect();
					bFound = ((rectScreen1 == rectTmp) != 0);
				}
			}
		}
	}

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

	if ( !bFound )	//	Memory error or at least one key or variable not found?
	{
		rectScreen1.left	 = rcrectScreenDefault.left;
		rectScreen1.top	 = rcrectScreenDefault.top;
		rectScreen1.right  = rcrectScreenDefault.Width();
		rectScreen1.bottom = rcrectScreenDefault.Height();
	}
	
	TT_GetMonitorAndWorkAreaInfoFromRect( rectScreen1, &rectWorkArea, &rectMonitor );

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

	if ( bFound )
	{
		strTmp.Format( TT_REG_KEY__MonitorRectangle, rectMonitor.left, rectMonitor.top, rectMonitor.right, rectMonitor.bottom );
		strMonitorRect.Format( _T("%s\\%s"), pcszScreenRegKeyName, (LPCTSTR)strTmp );
		bFound = FALSE;	//	Set to not found by default.

		if ( TT_RegReadInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__X, 0, &nValue ) == ERROR_SUCCESS )
		{
			rectScreen2.left = rectScreen2.right = nValue;

			if ( TT_RegReadInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__Y, 0, &nValue ) == ERROR_SUCCESS )
			{
				rectScreen2.top = rectScreen2.bottom = nValue;

				if ( TT_RegReadInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__CX, 0, &nValue ) == ERROR_SUCCESS )
				{
					rectScreen2.right += nValue;

					if ( TT_RegReadInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__CY, 0, &nValue ) == ERROR_SUCCESS )
					{
						rectScreen2.bottom += nValue;
						bFound = TRUE;
					}
				}
			}
		}
	}

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

	if ( !bFound )	//	Memory error or at least one key or variable not found?
	{
		rectScreen2.left = rectScreen2.top = rectScreen2.right = rectScreen2.bottom = 0;
	}

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

	bUnalteredValuesFromReg = bFound;

	//	The saved application window position may become invalid if the monitor has been moved
	//	 or if the monitor no more exists.  When this happens the saved position is ignored and
	//	 the window rectangle is set to the specified default.
	if ( rectScreen1 != rectScreen2 )
	{
		rectScreen1 = rcrectScreenDefault;
		bUnalteredValuesFromReg = FALSE;
	}

	if ( cbCenterInWorkArea )
	{
		rectScreen2 = rectScreen1;

		rectScreen1.left   = (rectWorkArea.left + ((rectWorkArea.Width()  - rectScreen2.Width() ) / 2));
		rectScreen1.top	 = (rectWorkArea.top  + ((rectWorkArea.Height() - rectScreen2.Height()) / 2));
		rectScreen1.right  = (rectScreen1.left + rectScreen2.Width());
		rectScreen1.bottom = (rectScreen1.top  + rectScreen2.Height());

		if ( rectScreen1 != rectScreen2 ) bUnalteredValuesFromReg = FALSE;
	}

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

	if ( cbAlignToWorkAreaEdges )
	{
		if ( rectScreen1.right > rectWorkArea.right )	//	Align to right?
		{
			rectScreen1.left  = (rectWorkArea.right - rectScreen1.Width() );
			rectScreen1.right = rectWorkArea.right;
			bUnalteredValuesFromReg = FALSE;
		}

		if ( rectScreen1.bottom > rectWorkArea.bottom )	//	Align to bottom?
		{
			rectScreen1.top    = (rectWorkArea.bottom - rectScreen1.Height());
			rectScreen1.bottom = rectWorkArea.bottom;
			bUnalteredValuesFromReg = FALSE;
		}

		if ( rectScreen1.left < rectWorkArea.left )	//	Align to left?
		{
			rectScreen1.right = (rectWorkArea.left + rectScreen1.Width());
			rectScreen1.left  = rectWorkArea.left;
			bUnalteredValuesFromReg = FALSE;
		}

		if ( rectScreen1.top < rectWorkArea.top )	//	Align to top?
		{
			rectScreen1.bottom = (rectWorkArea.top + rectScreen1.Height());
			rectScreen1.top    = rectWorkArea.top;
			bUnalteredValuesFromReg = FALSE;
		}
	}

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

	if ( prectScreen	 != 0 ) *(prectScreen  ) = rectScreen1;
	if ( prectWorkArea != 0 ) *(prectWorkArea) = rectWorkArea;
	if ( prectMonitor  != 0 ) *(prectMonitor ) = rectMonitor;

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

	return( bUnalteredValuesFromReg );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2008-09-10©  Modified: 2016-07-12©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'pcszScreenRegKeyName': Example: "Software\Adeluc\Three Timers V2\MainWindow".						//
//																																	//
//	'hwndScreen': Must be valid otherwise nothing will be saved.												//
//																																	//
//	'prectScreen': May be 0 if you do not need this information.  Will contain the values about		//
//						the current screen.																					//
//																																	//
//	'prectWorkArea': May be 0 if you do not need this information.  Will contain the values about	//
//						  the WorkArea of the target monitor.															//
//																																	//
//	'prectMonitor': May be 0 if you do not need this information.  Will contain the values about		//
//						 the target monitor.																					//
//																																	//
//	Result: Returns TRUE if successful.  Otherwise returns FALSE and fills requested rectangles		//
//		  with zero.  																											//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_SaveScreenInfoToRegistry( LPCTSTR pcszScreenRegKeyName, HWND hwndScreen,
											 CRect *prectScreen, CRect *prectWorkArea, CRect *prectMonitor )
{
	bool					bStatus = TRUE;
	CString				strMonitorRect, strTmp;
	CRect					rectScreen, rectMonitor, rectWorkArea;
	WINDOWPLACEMENT	wndpl;
		  				
	wndpl.length = sizeof( WINDOWPLACEMENT );

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

	if ( ::IsWindow( hwndScreen ) )
	{
		GetWindowPlacement( hwndScreen, &wndpl );		//	Always returns TRUE if you provide correct parameters.
		rectScreen = wndpl.rcNormalPosition;			// Rectangle is relative to Monitor's WorkArea.

		//	Does not matter if 'rectScreen' is in Monitor or WorkArea coordinates.
		TT_GetMonitorAndWorkAreaInfoFromRect( rectScreen, &rectWorkArea, &rectMonitor );

		if ( ((GetWindowLongPtr( hwndScreen, GWL_STYLE ) & WS_CHILD) == 0) &&
			  ((GetWindowLongPtr( hwndScreen, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW) == 0) )
		{
			//	Make rectangle relative to monitor.
			rectScreen.OffsetRect( (rectWorkArea.left - rectMonitor.left), (rectWorkArea.top - rectMonitor.top) );
		}

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

		strTmp.Format( TT_REG_KEY__MonitorRectangle, rectMonitor.left, rectMonitor.top, rectMonitor.right, rectMonitor.bottom );
		strMonitorRect.Format( _T("%s\\%s"), pcszScreenRegKeyName, (LPCTSTR)strTmp );

		TT_RegWriteInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__X , rectScreen.left		 );
		TT_RegWriteInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__Y , rectScreen.top		 );
		TT_RegWriteInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__CX, rectScreen.Width()  );
		TT_RegWriteInteger( HKEY_CURRENT_USER, pcszScreenRegKeyName, TT_REG_VAR__CY, rectScreen.Height() );

		TT_RegWriteInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__X , rectScreen.left		 );
		TT_RegWriteInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__Y , rectScreen.top		 );
		TT_RegWriteInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__CX, rectScreen.Width()  );
		TT_RegWriteInteger( HKEY_CURRENT_USER, strMonitorRect, TT_REG_VAR__CY, rectScreen.Height() );

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

		if ( prectScreen	 != 0 ) *(prectScreen  ) = rectScreen;
		if ( prectWorkArea != 0 ) *(prectWorkArea) = rectWorkArea;
		if ( prectMonitor  != 0 ) *(prectMonitor ) = rectMonitor;
	}

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

	else
	{
		bStatus = FALSE;

		if ( prectScreen	 != 0 ) prectScreen->SetRectEmpty();
		if ( prectWorkArea != 0 ) prectWorkArea->SetRectEmpty();
		if ( prectMonitor  != 0 ) prectMonitor->SetRectEmpty();
	}

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2013-04-07©  Modified: 2015-08-27©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: Return FALSE only when the specified WebLink can not be found.									//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_BrowseWebpageLink( LPCTSTR pcszWebpageLink, HWND hwndParent, bool bPromptOnError )
{
	bool	bStatus = TRUE;

//---------------------------------------------------------------------------------------------------
//	KNOWN BUG: If this application is started with the MS Visual Studio debugger, then the ShellExecute() function
//				  may randomly cause this application to freeze and the MS Visual Studio to hang and restart.

	if ( (int)ShellExecute( hwndParent, _T("open"), pcszWebpageLink, 0, _T("C:\\"), SW_SHOW ) <= HINSTANCE_ERROR )
	{	
		if ( bPromptOnError )
		{
			CString	strText;

			strText.Format( IDS_FMT_OPEN_WEBSITE_ERROR, pcszWebpageLink );
			::MessageBox( hwndParent, strText, NULL, (MB_ICONERROR | MB_OK) );
		}

		bStatus = FALSE;
	}

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2013-08-31©  Modified: 2016-03-21©	//
//																																	//
//	Purpose:	Creates a 32-bit bitmap, initializes it with the 'cpixCanvasColor' background color,	//
//				then blends the 'hiconSource' icon onto it.															//
//																																	//
//	IMPORTANT: Monochrome icons are not supported and only 32-bit icons are supported.					//
//																																	//
// Future improvement: To eventually implements support for transparency with 24-bit, 8-bit or   	//
//							  4-bit icons, see the DT_CreateDisabledIcon() function.								//
//																																	//
//	'hiconSource':	Must be a 32-bit icon otherwise its transparency will be ignored.						//
//																																	//
// 'cpixCanvasColor': Be sure to set its alpha component to 'JCH_PIXEL_CHANNEL_MAX_VAL' otherwise	//
//							 the resulting bitmap will contain transparency.										//
//																																	//
//	Result: Returns 0 only if an error occurred.  Otherwise returns the created bitmap handle.		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

HBITMAP TT_Create32BitsBitmapFrom32BitsIcon( HICON hiconSource, const JCH_Pixel cpixCanvasColor )
{
	HBITMAP			hbitmapCanvas = 0;
	HDC				hdcBitmap	  = 0;
	ICONINFO			iiSource;
	BITMAP			bmSource;
	BITMAPINFO		bmiSource;
	JCH_PixelMap	pixmapSource, pixmapCanvas;

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

	if ( ::GetIconInfo( hiconSource, &iiSource ) != 0 )
	{
		if ( ::GetObject( iiSource.hbmColor, sizeof( BITMAP ), &bmSource ) != 0 )
		{
			if ( (hdcBitmap = ::CreateCompatibleDC( 0 )) != 0 )
			{
				if ( pixmapSource.AllocatePixels( bmSource.bmWidth, bmSource.bmHeight ) &&
					  pixmapCanvas.AllocatePixels( bmSource.bmWidth, bmSource.bmHeight, TRUE, cpixCanvasColor ) )
				{
					bmiSource = *(pixmapSource.GetBitMapInfoAddress());		//	Required because GetDIBits() may modify 'bmiSource'.

					if ( ::GetDIBits( hdcBitmap, iiSource.hbmColor, 0, bmSource.bmHeight,
							pixmapSource.GetFirstPixelAddress(), &bmiSource, DIB_RGB_COLORS ) == bmSource.bmHeight )
					{
						pixmapSource.AlphaBlend( 0, 0, 0, 0, bmSource.bmWidth, bmSource.bmHeight, pixmapCanvas );

						if ( (hbitmapCanvas = CreateBitmap( bmSource.bmWidth, bmSource.bmHeight, 1, 32, 0 )) != 0 )
						{
							if ( !::GdiFlush() || (::SetDIBits( hdcBitmap, hbitmapCanvas, 0, bmSource.bmHeight, pixmapCanvas.GetFirstPixelAddress(), 
									pixmapCanvas.GetBitMapInfoAddress(), DIB_RGB_COLORS ) != bmSource.bmHeight) )
							{
								::DeleteObject( hbitmapCanvas );
								hbitmapCanvas = 0;
							}
						}
					}
				}

				::DeleteDC( hdcBitmap );
				hdcBitmap = 0;
			}
		}

		if ( iiSource.hbmColor != 0 ) ::DeleteObject( iiSource.hbmColor );
		if ( iiSource.hbmMask  != 0 ) ::DeleteObject( iiSource.hbmMask  );
	}

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

	return( hbitmapCanvas );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2001-05-12©  Modified: 2016-03-25©	//
//																																	//
//	Purpose:	Create the specified folder and its parent folders if they do not already exist.			//
//																																	//
//	Note: If the specified folder	already exists, nothing is done and TRUE is returned.					//
//																																	//
//	Result: If the function succeeds, return is TRUE, oherwise return is FALSE.							//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_CreateFolder( LPCTSTR pcszFolderPath, LPSECURITY_ATTRIBUTES lpSecurityAttributes )
{
	int		nIndex;
	int		nRecursiveCount = 1;
	TCHAR		szFolderPath[MAX_PATH];
	
//---------------------------------------------------------------------------------------------------

	if ( (pcszFolderPath == 0) || _tcsIsEmpty( pcszFolderPath ) || (_tcslen( pcszFolderPath ) >= _countof( szFolderPath )) ) return( FALSE );

	if ( ::PathFileExists( pcszFolderPath ) != 0 )
	{
		if ( ::PathIsDirectory( pcszFolderPath ) != 0 ) return( TRUE  );	// A folder aleady exists?
		else															return( FALSE );	// A file aleady exists?
	}

	_tcscpy_s( szFolderPath, pcszFolderPath );

//···································································································

	FOREVER
	{
		if ( ::CreateDirectory( szFolderPath, lpSecurityAttributes ) != 0 ) nRecursiveCount--;	// Successful?
		else																					  nRecursiveCount++;

		if ( nRecursiveCount == 0 ) break;

//···································································································

		_tcscpy_s( szFolderPath, pcszFolderPath );

		for( nIndex = 1; nIndex < nRecursiveCount; nIndex++ )
		{
			if ( ::PathRemoveFileSpec( szFolderPath ) == 0 ) break;			// Nothing removed from string?
		}

		if ( nIndex < nRecursiveCount ) break;										// Error occurs in previous loop?

		if ( _tcsIsEmpty( szFolderPath ) ) break;
	}

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

	return( ((nRecursiveCount == 0) ? TRUE : FALSE) );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-06-28©  Modified: 2016-06-28©	//
//																																	//
//	Purpose:	Extracts from the text pointed by 'pcszTimerValue' a timer value and stores it in		//
//				'*(punTimerValue)' in millisecond units.																//
//																																	//
//	'pcszTimerValue': Examples: "1" --> 1 hour OR 1 minute OR 1 second.										//
//													 (Check 'cunTimerUnit' to know which one it is.)				//
//																																	//
//										 "66:8" --> 66 hours & 8 minutes OR 66 minutes & 8 seconds.		 		//
//														 (Check 'cunTimerUnit' to know which one it is.)			//
//														 ('cunTimerUnit' != 'TT_REG_VAL__Timer_Unit__Seconds')	//
//																																	//
//										 "45:17s" --> 45 hours & 17 seconds OR 45 minutes & 17 seconds. 		//
//														   (Check 'cunTimerUnit' to know which one it is.)			//
//														   ('cunTimerUnit' != 'TT_REG_VAL__Timer_Unit__Seconds')	//
//																																	//
//										 "0:72:09" --> 0 hour & 72 minutes & 9 seconds.								//
//														   ('cunTimerUnit' == 'TT_REG_VAL__Timer_Unit__Hours')	//
//																																	//
//										 "0h72:09" --> 0 hour & 72 minutes & 9 seconds.								//
//														   ('cunTimerUnit' == Any)											//
//																																	//
//										 "90m35"	  --> 90 minutes & 35 seconds.  ('cunTimerUnit' == Any)		//
//																																	//
//										 "36h92s"  --> 36 hours & 92 seconds.  ('cunTimerUnit' == Any)			//
//																																	//
//										 "12h"     --> 12 hours.  ('cunTimerUnit' == Any)							//
//																																	//
//										 "300m"    --> 300 minutes.  ('cunTimerUnit' == Any)						//
//																																	//
//										 "150s"    --> 150 seconds.  ('cunTimerUnit' == Any)						//
//																																	//
//																																	//
//	'punTimerValue': The extracted value will be stored there in millisecond units.  The returned	//
//						  value will be clipped to 'TT_TimerValue_Min' and 'TT_TimerValue_Max'.				//
//																																	//
//	'cunTimerUnit': Possible values are 'TT_REG_VAL__Timer_Unit__Seconds',									//
//						 'TT_REG_VAL__Timer_Unit__Minutes' or 'TT_REG_VAL__Timer_Unit__Hours'.				//
//						 This value is used as a clue when the text pointed by 'pcszTimerValue' does not //
//						 contain enough information to guess the time unit used.									//
//																																	//
//	Result: Returns 1 if the value extraction is successful.  Returns 0 if the value extraction is	//
//			  successful but '*(punTimerValue)' has been clipped.  Returns -1 if the text pointed by	//
//			  'pcszTimerValue' can not be processed properly and in such case, depending on the value	//
//			  of 'cunTimerUnit', '*(punTimerValue)' will be set to 'TT_TimerValue_One_Hour' or			//
//			  'TT_TimerValue_One_Minute' or 'TT_TimerValue_One_Second'.											//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

//	Returns FALSE only on syntax error.	 '*(pstrExtractedNumber)' will be returned empty if no more number can be extracted.
bool TT_GetTimerValue_Sub1_ExtractNumber( LPCTSTR pcszTimerValue, unsigned int *punCurPos, CString *pstrExtractedNumber )
{
	bool				bStatus = TRUE;
	TCHAR				chCur;
	unsigned int	unStartingDigit, unLengthToCopy;

	pstrExtractedNumber->Empty();

	for( chCur = pcszTimerValue[*(punCurPos)]; (chCur == _T(' ')); chCur = pcszTimerValue[++(*(punCurPos))] );	//	Skips spaces.

	if ( _istdigit( chCur ) )
	{
		unStartingDigit = *(punCurPos);

		for( chCur = pcszTimerValue[++(*(punCurPos))]; _istdigit( chCur ); chCur = pcszTimerValue[++(*(punCurPos))] );	//	Skips digits.

		unLengthToCopy = (*(punCurPos) - unStartingDigit);
		_tcsncpy( pstrExtractedNumber->GetBufferSetLength( unLengthToCopy ), &pcszTimerValue[unStartingDigit], unLengthToCopy );
	}
	else if ( chCur != _T('\0') ) bStatus = FALSE;

	return( bStatus );
}

//===================================================================================================

//	Returns FALSE only on syntax error.  '*(punNumberUnit)' will be set to 'cunDfltNumberUnit' if end of string is reached.
bool TT_GetTimerValue_Sub2_ExtractNumberUnit( LPCTSTR pcszTimerValue, unsigned int *punCurPos, unsigned int *punNumberUnit, 
		const unsigned int cunDfltNumberUnit, const TCHAR cchHour, const TCHAR cchMinute, const TCHAR cchSecond, const TCHAR cchField )
{
	bool		bStatus = TRUE;
	TCHAR		chCur;

	*(punNumberUnit) = cunDfltNumberUnit;

	for( chCur = pcszTimerValue[*(punCurPos)]; (chCur == _T(' ')); chCur = pcszTimerValue[++(*(punCurPos))] );	//	Skips spaces.

	if		  ( chCur == cchHour									  ) *(punNumberUnit) = TT_REG_VAL__Timer_Unit__Hours;
	else if ( chCur == cchMinute								  ) *(punNumberUnit) = TT_REG_VAL__Timer_Unit__Minutes;
	else if ( chCur == cchSecond								  ) *(punNumberUnit) = TT_REG_VAL__Timer_Unit__Seconds;
	else if ( (chCur != cchField) && (chCur != _T('\0')) ) bStatus = FALSE;

	if ( bStatus && (chCur != _T('\0')) ) (*(punCurPos))++; 

	return( bStatus );
}

//===================================================================================================

int TT_GetTimerValue( LPCTSTR pcszTimerValue, unsigned int *punTimerValue, const unsigned int cunTimerUnit )
{
	int					nStatus					= 1;		//	Set to "Successful".
	unsigned int		unCurDfltNumberUnit	= cunTimerUnit;
	unsigned int		unExtractedNumberCnt = 0;
	unsigned int		unCurPos				   = 0;
	unsigned __int64	un64Hours				= 0;
	unsigned __int64	un64Minutes				= 0;
	unsigned __int64	un64Seconds				= 0;
	unsigned int		unNumberUnit;
	TCHAR					chHour, chMinute, chSecond, chField;
	bool					bIsHourCharDelimiterFound, bIsMinuteCharDelimiterFound, bIsSecondCharDelimiterFound; 
	CString				strTimerValue, strExtractedNumber, strTmp;

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

	strTimerValue = pcszTimerValue;
	strTimerValue.MakeLower();

	strTmp.LoadString( TT_hInst, IDS_CHAR_DELIMITER_HOUR );
	strTmp.MakeLower();
	chHour = strTmp[0];		//	Safe with empty string.

	strTmp.LoadString( TT_hInst, IDS_CHAR_DELIMITER_MINUTE );
	strTmp.MakeLower();
	chMinute = strTmp[0];	//	Safe with empty string.

	strTmp.LoadString( TT_hInst, IDS_CHAR_DELIMITER_SECOND );
	strTmp.MakeLower();
	chSecond = strTmp[0];	//	Safe with empty string.

	strTmp.LoadString( TT_hInst, IDS_CHAR_DELIMITER_FIELD );
	strTmp.MakeLower();
	chField = strTmp[0];		//	Safe with empty string.

	bIsHourCharDelimiterFound = bIsMinuteCharDelimiterFound = bIsSecondCharDelimiterFound = FALSE;

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

	if ( (chHour == _T('\0')) || (chMinute == _T('\0')) || (chSecond == _T('\0')) || (chField == _T('\0')) || 
		  (chHour == chMinute) || (chHour == chSecond) || (chHour == chField) ||
		  (chMinute == chSecond) || (chMinute == chField) || (chSecond == chField) )
	{
		nStatus = -1;
	}

//===================================================================================================

	while( nStatus == 1 )
	{
		if ( !TT_GetTimerValue_Sub1_ExtractNumber( strTimerValue, &unCurPos, &strExtractedNumber ) )
		{
			nStatus = -1;							//	Syntax error.
			break;
		}

		if ( strExtractedNumber.IsEmpty() )	//	Done?
		{
			break;
		}

		if ( unExtractedNumberCnt == 3 )		//	Already 3 numbers extracted?
		{
			nStatus = -1;							//	Error too many numbers.
			break;
		}

		if ( !TT_GetTimerValue_Sub2_ExtractNumberUnit( strTimerValue, &unCurPos, &unNumberUnit,
				unCurDfltNumberUnit, chHour, chMinute, chSecond, chField ) )
		{
			nStatus = -1;							//	Syntax error.
			break;
		}

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

		if ( unNumberUnit == TT_REG_VAL__Timer_Unit__Hours )
		{
			if ( bIsHourCharDelimiterFound || bIsMinuteCharDelimiterFound || bIsSecondCharDelimiterFound )
			{
				nStatus = -1;	//	Syntax error.
				break;
			}

			_stscanf( strExtractedNumber, _T("%I64u"), &un64Hours );		//	Impossible to fail.
			unExtractedNumberCnt++;
			bIsHourCharDelimiterFound = TRUE;
			unCurDfltNumberUnit = TT_REG_VAL__Timer_Unit__Minutes;
		}

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

		else if ( unNumberUnit == TT_REG_VAL__Timer_Unit__Minutes )
		{
			if ( bIsMinuteCharDelimiterFound || bIsSecondCharDelimiterFound )
			{
				nStatus = -1;	//	Syntax error.
				break;
			}

			_stscanf( strExtractedNumber, _T("%I64u"), &un64Minutes );		//	Impossible to fail.
			unExtractedNumberCnt++;
			bIsMinuteCharDelimiterFound = TRUE;
			unCurDfltNumberUnit = TT_REG_VAL__Timer_Unit__Seconds;
		}

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

		else if ( unNumberUnit == TT_REG_VAL__Timer_Unit__Seconds )
		{
			if ( bIsSecondCharDelimiterFound )
			{
				nStatus = -1;	//	Syntax error.
				break;
			}

			_stscanf( strExtractedNumber, _T("%I64u"), &un64Seconds );		//	Impossible to fail.
			unExtractedNumberCnt++;
			bIsSecondCharDelimiterFound = TRUE;
		}
	}

//===================================================================================================

	if ( nStatus == -1 )
	{
		if		  ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Hours	 ) *(punTimerValue) = TT_TimerValue_One_Hour;
		else if ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Minutes ) *(punTimerValue) = TT_TimerValue_One_Minute;
		else																			*(punTimerValue) = TT_TimerValue_One_Second;
	}
	else
	{
		unsigned __int64	un64TimerValue = (((un64Hours * 3600) + (un64Minutes * 60) + un64Seconds) * 1000);		

		if ( un64TimerValue < TT_TimerValue_Min )
		{
			if		  ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Hours	 ) *(punTimerValue) = TT_TimerValue_One_Hour;
			else if ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Minutes ) *(punTimerValue) = TT_TimerValue_One_Minute;
			else																			*(punTimerValue) = TT_TimerValue_One_Second;

			nStatus = 0;	//	Set to "Successful but clipped".
		}
		else if ( un64TimerValue > TT_TimerValue_Max )
		{
			*(punTimerValue) = TT_TimerValue_Max;
			nStatus = 0;	//	Set to "Successful but clipped".
		}
		else *(punTimerValue) = (unsigned int)un64TimerValue;
	}

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

	return( nStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-17©  Modified: 2016-06-29©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'cunTimerValue': Value in milliseconds.																			//
//																																	//
//	'cunTimerUnit': 'TT_REG_VAL__Timer_Unit__Seconds' --> "#s"													//
//						 'TT_REG_VAL__Timer_Unit__Minutes' --> "#m##s"												//
//						 'TT_REG_VAL__Timer_Unit__Hours'   --> "#h##m##s"											//
//																																	//
//	'cbKeepHeadingZero': TRUE --> 0h00m05s   FALSE --> 5s			 'TT_REG_VAL__Timer_Unit__Hours'		//
//								TRUE --> 0h12m34s	  FALSE --> 12m34s	 'TT_REG_VAL__Timer_Unit__Hours'		//
//								TRUE --> 1h23m45s	  FALSE --> 1h23m45s	 'TT_REG_VAL__Timer_Unit__Hours'		//
//								TRUE --> 0m05s		  FALSE --> 5s			 'TT_REG_VAL__Timer_Unit__Minutes'	//
//								TRUE --> 1m23s		  FALSE --> 1m23s		 'TT_REG_VAL__Timer_Unit__Minutes'	//
//																																	//
//	Result: Returns a formatted string.																					//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

CString TT_FormatTimerValue( const unsigned int cunTimerValue, const unsigned int cunTimerUnit, const bool cbKeepHeadingZero )
{
	unsigned int	unHours, unMinutes, unSeconds;
	CString			strFmt, strTime;

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

	if ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Hours )	//	Hours:Minutes:Seconds?
	{
		unSeconds  = (cunTimerValue / 1000);
		unMinutes  = (unSeconds / 60);
		unHours    = (unMinutes / 60);
		unMinutes -= (unHours * 60);
		unSeconds -= ((unHours * 3600) + (unMinutes * 60));

		if ( (unHours != 0) || cbKeepHeadingZero )
		{
			strFmt.LoadString( TT_hInst, IDS_FMT_TITLE_H_M_S );
			strTime.Format( strFmt, unHours, unMinutes, unSeconds );
		}
		else if ( unMinutes != 0 )
		{
			strFmt.LoadString( TT_hInst, IDS_FMT_TITLE_M_S );
			strTime.Format( strFmt, unMinutes, unSeconds );
		}
		else
		{
			strFmt.LoadString( TT_hInst, IDS_FMT_TITLE_S );
			strTime.Format( strFmt, unSeconds );
		}
	}
	else if ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Minutes )		//	Minutes:Seconds?
	{
		unSeconds  = (cunTimerValue / 1000);
		unMinutes  = (unSeconds / 60);
		unSeconds -= (unMinutes * 60);

		if ( (unMinutes != 0) || cbKeepHeadingZero )
		{
			strFmt.LoadString( TT_hInst, IDS_FMT_TITLE_M_S );
			strTime.Format( strFmt, unMinutes, unSeconds );
		}
		else
		{
			strFmt.LoadString( TT_hInst, IDS_FMT_TITLE_S );
			strTime.Format( strFmt, unSeconds );
		}
	}
	else //	if ( cunTimerUnit == TT_REG_VAL__Timer_Unit__Seconds )	//	Seconds?
	{
		unSeconds = (cunTimerValue / 1000);
		strFmt.LoadString( TT_hInst, IDS_FMT_TITLE_S );
		strTime.Format( strFmt, unSeconds );
	}

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

	return( strTime );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-03-23©	//
//																																	//
//	Purpose:																														//
//																																	//
// 'cnComboBoxId': This ComboBox control must contain the items for											//
//						 'TT_REG_VAL__Timer_Unit__Seconds', 'TT_REG_VAL__Timer_Unit__Minutes' and			//
//						 'TT_REG_VAL__Timer_Unit__Hours'.																//
//																																	//
//	Result: Returns 'TT_REG_VAL__Timer_Unit__Seconds' or 'TT_REG_VAL__Timer_Unit__Minutes' or			//
//			  'TT_REG_VAL__Timer_Unit__Hours'.																			//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned int TT_GetTimerUnitFromComboBox( HWND hwndDlg, const int cnComboBoxId )
{
	unsigned int	unFormat;
	LRESULT			npCurSel;

	npCurSel = ::SendDlgItemMessage( hwndDlg, cnComboBoxId, CB_GETCURSEL, 0, 0 );

	if		  ( npCurSel == 2 ) unFormat = TT_REG_VAL__Timer_Unit__Hours;
	else if ( npCurSel == 1 ) unFormat = TT_REG_VAL__Timer_Unit__Minutes;
	else							  unFormat = TT_REG_VAL__Timer_Unit__Seconds;

	return( unFormat );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-23©  Modified: 2016-03-23©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: Returns TRUE if successful.  Otherwise returns FALSE.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_PopulateTimerEventComboBox( HWND hwndDlg, const int cnComboBoxId, const int cnSelectedEvent )
{
	bool		bStatus		 = TRUE;
	HWND		hwndComboBox = ::GetDlgItem( hwndDlg, cnComboBoxId );
	LRESULT	npResult;
	CString	strBuiltInSnd1, strBuiltInSnd2, strBuiltInSnd3;

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

	strBuiltInSnd1.LoadString( IDS_EVENT_PLAY_BUILT_IN_SOUND_1 );
	strBuiltInSnd2.LoadString( IDS_EVENT_PLAY_BUILT_IN_SOUND_2 );
	strBuiltInSnd3.LoadString( IDS_EVENT_PLAY_BUILT_IN_SOUND_3 );

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

	::SendMessage( hwndComboBox, WM_SETREDRAW, FALSE, 0 );
	::SendMessage( hwndComboBox, CB_RESETCONTENT, 0, 0 );

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

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strBuiltInSnd1 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strBuiltInSnd2 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strBuiltInSnd3 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)TT_szExtSndLabel1 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)TT_szExtSndLabel2 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)TT_szExtSndLabel3 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)TT_szOpenFileLabel1 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)TT_szOpenFileLabel2 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	npResult = ::SendMessage( hwndComboBox, CB_ADDSTRING, 0, (LPARAM)TT_szOpenFileLabel3 );
																														  
	if ( (npResult == CB_ERR) || (npResult == CB_ERRSPACE) ) bStatus = FALSE;

	if ( (::SendMessage( hwndComboBox, CB_SETCURSEL, (WPARAM)cnSelectedEvent, 0 ) == CB_ERR) && (cnSelectedEvent != -1) ) bStatus = FALSE;

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

	::SendMessage( hwndComboBox, WM_SETREDRAW, TRUE, 0 );
	::InvalidateRect( hwndComboBox, NULL, TRUE );

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-03-22©	//
//																																	//
//	Purpose:																														//
//																																	//
// 'cnComboBoxId': This ComboBox control must contain the items for											//
//						 'TT_REG_VAL__Timer_Event__BuiltInSnd1',														//
//						 'TT_REG_VAL__Timer_Event__BuiltInSnd2',														//
//						 'TT_REG_VAL__Timer_Event__BuiltInSnd3',														//
//						 'TT_REG_VAL__Timer_Event__ExtSnd1', 'TT_REG_VAL__Timer_Event__ExtSnd2',			//
//						 'TT_REG_VAL__Timer_Event__ExtSnd3', 'TT_REG_VAL__Timer_Event__OpenFile1',			//
//						 'TT_REG_VAL__Timer_Event__OpenFile2' and 'TT_REG_VAL__Timer_Event__OpenFile3'.	//
//																																	//
//	Result: Returns 'TT_REG_VAL__Timer_Event__BuiltInSnd1' or													//
//						 'TT_REG_VAL__Timer_Event__BuiltInSnd2' or													//
//						 'TT_REG_VAL__Timer_Event__BuiltInSnd3' or													//
//						 'TT_REG_VAL__Timer_Event__ExtSnd1' or															//
//						 'TT_REG_VAL__Timer_Event__ExtSnd2' or															//
//						 'TT_REG_VAL__Timer_Event__ExtSnd3' or															//
//						 'TT_REG_VAL__Timer_Event__OpenFile1' or														//
//						 'TT_REG_VAL__Timer_Event__OpenFile2' or 'TT_REG_VAL__Timer_Event__OpenFile3'.	//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned int TT_GetEventIdFromComboBox( HWND hwndDlg, const int cnComboBoxId )
{
	unsigned int	unEventId;
	LRESULT			npCurSel;

	npCurSel = ::SendDlgItemMessage( hwndDlg, cnComboBoxId, CB_GETCURSEL, 0, 0 );

	if		  ( npCurSel == 8 ) unEventId = TT_REG_VAL__Timer_Event__OpenFile3;
	else if ( npCurSel == 7 ) unEventId = TT_REG_VAL__Timer_Event__OpenFile2;
	else if ( npCurSel == 6 ) unEventId = TT_REG_VAL__Timer_Event__OpenFile1;
	else if ( npCurSel == 5 ) unEventId = TT_REG_VAL__Timer_Event__ExtSnd3;
	else if ( npCurSel == 4 ) unEventId = TT_REG_VAL__Timer_Event__ExtSnd2;
	else if ( npCurSel == 3 ) unEventId = TT_REG_VAL__Timer_Event__ExtSnd1;
	else if ( npCurSel == 2 ) unEventId = TT_REG_VAL__Timer_Event__BuiltInSnd3;
	else if ( npCurSel == 1 ) unEventId = TT_REG_VAL__Timer_Event__BuiltInSnd2;
	else							  unEventId = TT_REG_VAL__Timer_Event__BuiltInSnd1;

	return( unEventId );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-25©  Modified: 2016-06-28©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'cnTimerGroupId': Possible values are 'IDC_TIMER_1_GR', 'IDC_TIMER_2_GR' or 'IDC_TIMER_3_GR'.	//
//																																	//
//	'cnTimerStartStopBtnId': Possible values are 'IDC_START_STOP_1_BT', 'IDC_START_STOP_1_BT' or		//
//									 'IDC_START_STOP_1_BT'.																	//
//																																	//
//	Result: Returns TRUE if the mouse position is over the area.  Otherwise returns FALSE.				//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_IsMouseOver_TimerGroupLabel( const int cnPosX, const int cnPosY, HWND hwndDlg,
												 const int cnTimerGroupId, const int cnTimerStartStopBtnId )
{
	bool		bIsMouseOver = FALSE;
	HWND		hwndGroup	 = ::GetDlgItem( hwndDlg, cnTimerGroupId );
	HWND		hwndBtn		 = ::GetDlgItem( hwndDlg, cnTimerStartStopBtnId	);
	CRect		rectGroup, rectBtn, rectArea;

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

	::GetWindowRect( hwndGroup, &rectGroup );
	::ScreenToClient( hwndDlg,  (LPPOINT)&rectGroup		  );
	::ScreenToClient( hwndDlg, ((LPPOINT)&rectGroup) + 1 );

	::GetWindowRect( hwndBtn, &rectBtn );
	::ScreenToClient( hwndDlg,  (LPPOINT)&rectBtn		);
	::ScreenToClient( hwndDlg, ((LPPOINT)&rectBtn) + 1 );

	rectArea = rectGroup;
	rectArea.bottom = rectArea.top;
	rectArea.NormalizeRect();

	rectArea.left	 = rectBtn.left;
	rectArea.top	 = rectGroup.top;
	rectArea.right	 = (rectGroup.right - (rectBtn.left - rectGroup.left));
	rectArea.bottom = (rectBtn.top - 1);	//	That leaves a 1 pixel free space.
	rectArea.NormalizeRect();

	if ( (cnPosX >= rectArea.left) && (cnPosX < rectArea.right) &&
		  (cnPosY >= rectArea.top) && (cnPosY < rectArea.bottom) )
	{
		bIsMouseOver = TRUE;
	}

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

	return( bIsMouseOver );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-22©  Modified: 2016-03-22©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: Returns TRUE if successful.  Otherwise returns FALSE.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_ExecuteOpenFile( LPCTSTR pcszOpenFileName )
{
	bool		bStatus = TRUE;
	int		nCharPos;
	CString	strAppFile, strParameters;

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

	if ( !_tcsIsEmpty_s( pcszOpenFileName ) )
	{
//	KNOWN BUG: If this application is started with the MS Visual Studio debugger, then the ShellExecute() function
//				  may randomly cause this application to freeze and the MS Visual Studio to hang and restart.

		strAppFile = pcszOpenFileName;

		if ( strAppFile[0] == _T('\"') )
		{
			if ( (nCharPos = strAppFile.Find( _T('\"'), 1 )) != -1 )
			{
				strParameters = strAppFile.Mid( (nCharPos + 1) );

				if ( (strParameters.GetLength() == 0) || strParameters[0] == _T(' ') )
				{
					strParameters.Trim();
					strAppFile = strAppFile.Mid( 1, (nCharPos - 1) );
					strAppFile.Trim();		//	Just in case.
				}
				else bStatus = FALSE;		//	Syntax error.
			}
			else bStatus = FALSE;			//	Syntax error.
		}
		else
		{
			if ( (nCharPos = strAppFile.Find( _T(' '), 1 )) != -1 )
			{
				strParameters = strAppFile.Mid( (nCharPos + 1) );
				strParameters.Trim();	//	Just in case.
				strAppFile = strAppFile.Mid( 0, nCharPos );
			}
		}

		if ( bStatus )
		{
			if ( (_tcsncmp( strAppFile, _T("http://"), 7 ) == 0) || (_tcsncmp( strAppFile, _T("https://"), 8 ) == 0) ||
				  ((strAppFile.GetLength() < MAX_PATH) && (::PathIsRelative( strAppFile ) == 0)) )
			{
				if ( (int)::ShellExecute( 0, _T("open"), strAppFile, strParameters, _T("C:\\"), SW_SHOW ) <= HINSTANCE_ERROR ) bStatus = FALSE;
			}
			else bStatus = FALSE;		//	Syntax error.
		}
	}
	else bStatus = FALSE;

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-03-25©	//
//																																	//
//	Purpose:																														//
//																																	//
// 'cunEventId': Must equal 'TT_REG_VAL__Timer_Event__BuiltInSnd1' or										//
//					  'TT_REG_VAL__Timer_Event__BuiltInSnd2' or														//
//					  'TT_REG_VAL__Timer_Event__BuiltInSnd3' or														//
//					  'TT_REG_VAL__Timer_Event__ExtSnd1' or															//
//					  'TT_REG_VAL__Timer_Event__ExtSnd2' or															//
//					  'TT_REG_VAL__Timer_Event__ExtSnd3' or															//
//					  'TT_REG_VAL__Timer_Event__OpenFile1' or															//
//					  'TT_REG_VAL__Timer_Event__OpenFile2' or															//
//					  'TT_REG_VAL__Timer_Event__OpenFile3'.															//
//																																	//
//	Result: Returns TRUE if successful.  Otherwise returns FALSE.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_ExecuteEventId( HWND hwndDlg, const unsigned int cunEventId )
{
	bool	bStatus = TRUE;

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

	if ( (cunEventId >= TT_REG_VAL__Timer_Event__BuiltInSnd1) && (cunEventId <= TT_REG_VAL__Timer_Event__BuiltInSnd3) )
	{
		DWORD		dwSoundFx = 0xFFFFFFFF;

		if		  ( cunEventId == TT_REG_VAL__Timer_Event__BuiltInSnd1 ) dwSoundFx = IDR_BUILT_IN_EVENT_SND_1_WAVE;
		else if ( cunEventId == TT_REG_VAL__Timer_Event__BuiltInSnd2 ) dwSoundFx = IDR_BUILT_IN_EVENT_SND_2_WAVE;
		else if ( cunEventId == TT_REG_VAL__Timer_Event__BuiltInSnd3 ) dwSoundFx = IDR_BUILT_IN_EVENT_SND_3_WAVE;

		if ( dwSoundFx != 0xFFFFFFFF )
		{
			bStatus = (::PlaySound( MAKEINTRESOURCE( dwSoundFx ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) ) != 0);
		}
		else bStatus = FALSE;
	}

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

	else if ( (cunEventId >= TT_REG_VAL__Timer_Event__ExtSnd1) && (cunEventId <= TT_REG_VAL__Timer_Event__ExtSnd3) )
	{
		LPCTSTR	pcszExtSnd = NULL;
		TCHAR		szExtSndFileName[TT_ExtSndFileName_MaxBufCnt];

		if		  ( cunEventId == TT_REG_VAL__Timer_Event__ExtSnd1 ) pcszExtSnd = TT_szExtSndFileName1;
		else if ( cunEventId == TT_REG_VAL__Timer_Event__ExtSnd2 ) pcszExtSnd = TT_szExtSndFileName2;
		else if ( cunEventId == TT_REG_VAL__Timer_Event__ExtSnd3 ) pcszExtSnd = TT_szExtSndFileName3;

		if ( pcszExtSnd != NULL )
		{
			_tcscpy_s( szExtSndFileName, pcszExtSnd );
			::PathUnquoteSpaces( szExtSndFileName );

			// Checking if file exists	to avoid 'PlaySound()' searching in other folders.
			if ( ::PathFileExists( szExtSndFileName ) && !::PathIsDirectory( szExtSndFileName ) )
			{
				bStatus = (::PlaySound( szExtSndFileName, TT_hInst, (SND_ASYNC | SND_FILENAME | SND_NODEFAULT) ) != 0);
			}
			else bStatus = FALSE;
		}
		else bStatus = FALSE;
	}

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

	else if ( (cunEventId >= TT_REG_VAL__Timer_Event__OpenFile1) && (cunEventId <= TT_REG_VAL__Timer_Event__OpenFile3) )
	{
		if		  ( cunEventId == TT_REG_VAL__Timer_Event__OpenFile1 ) bStatus = TT_ExecuteOpenFile( TT_szOpenFileName1 );
		else if ( cunEventId == TT_REG_VAL__Timer_Event__OpenFile2 ) bStatus = TT_ExecuteOpenFile( TT_szOpenFileName2 );
		else if ( cunEventId == TT_REG_VAL__Timer_Event__OpenFile3 ) bStatus = TT_ExecuteOpenFile( TT_szOpenFileName3 );
		else																			 bStatus = FALSE;
	}

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-16©  Modified: 2016-03-21©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

void TT_UpdateWindowTitle( HWND hwndDlg, const bool cbIsClearTitleBarOnly )
{
	CString	strText, strTitle;

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

	if ( cbIsClearTitleBarOnly || (!TT_bIsTimerStarted1 && !TT_bIsTimerStarted2 && !TT_bIsTimerStarted3) )
	{
		strTitle.LoadString( TT_hInst, IDS_APP_TITLE_THREETIMERS );
		::SetWindowText( hwndDlg, (LPCTSTR)strTitle );
	}
	else
	{
		if ( TT_bIsTimerStarted1 )
		{
			strText = TT_FormatTimerValue( (TT_dwCountDownValue1 * 1000), TT_GetTimerUnitFromComboBox( hwndDlg, IDC_TIME_UNIT_1_CB ) );
			strTitle = strText;
		}

		if ( TT_bIsTimerStarted2 )
		{
			strText = TT_FormatTimerValue( (TT_dwCountDownValue2 * 1000), TT_GetTimerUnitFromComboBox( hwndDlg, IDC_TIME_UNIT_2_CB ) );
			
			if ( !strTitle.IsEmpty() ) strTitle += _T(" | "); 
				
			strTitle += strText;
		}

		if ( TT_bIsTimerStarted3 )
		{
			strText = TT_FormatTimerValue( (TT_dwCountDownValue3 * 1000), TT_GetTimerUnitFromComboBox( hwndDlg, IDC_TIME_UNIT_3_CB ) );
			
			if ( !strTitle.IsEmpty() ) strTitle += _T(" | "); 
				
			strTitle += strText;
		}

		::SetWindowText( hwndDlg, (LPCTSTR)strTitle );
	}
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com  All rights reserved.  Created: 2001-05-11©  Modified: 2016-07-07©	//
//																																	//
//	Purpose:	Uses the shell's IShellLink and IPersistFile interfaces to create and store a shortcut	//
//				to the specified object.																					//
//																																	//
//	'pcszLinkPath': Full path and file name of the link file. (Ex.: "My test.lnk").						//
//																																	//
//	'pcszFilePath': Full path and file name of the shell link object.											//
//																																	//
//	'pcszWorkDir': May be set to 0.																						//
//																																	//
//	'pcszArgs': May be set to 0. 																							//
//																																	//
//	'pcszDescription': May be set to 0.																					//
//																																	//
//	'pcszIconPath' If set to 0 then the icon at 'nIcon' position from file pointed by					//
//						'pcszFilePath' will be used instead.															//
//																																	//
//	'nShowCmd': SW_SHOWNORMAL, SW_SHOWMINNOACTIVE or SW_SHOWMAXIMIZED.										//
//																																	//
// Note:	Do not put quotation marks in path strings. The folder, where the link file pointed by		//
//			'pcszLinkPath' will be created, must exist.																//
//																																	//
//	Result: Returns the result of calling the member functions of the interfaces or -1 for other		//
//			  errors.  Test the returned value like that: if ( SUCCEEDED( nResult ) ) then no error.	//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

HRESULT TT_CreateLink( LPCTSTR pcszLinkPath, LPCTSTR pcszFilePath, LPCTSTR pcszWorkDir, LPCTSTR pcszArgs,
							  LPCTSTR pcszDescription, int nIcon, LPCTSTR pcszIconPath, int nShowCmd )
{
	HRESULT		nResult = S_OK;
	IShellLink *psl;

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

	if ( !TT_bIsCoInitializeExFnctCalled )
	{
		if		  ( (nResult = CoInitialize( 0 )) == S_OK ) TT_bIsCoInitializeExFnctCalled = TRUE;
		else if ( nResult == S_FALSE )						  nResult = -1;	// Not supposed to be called twice.
	}

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

	if ( nResult == S_OK )
	{
		// Get a pointer to the IShellLink interface.
		nResult = CoCreateInstance( CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl );

		if ( SUCCEEDED( nResult ) )
		{
			IPersistFile	  *ppf;

			// Query IShellLink for the IPersistFile interface for saving the shortcut in persistent storage.
			nResult = psl->QueryInterface( IID_IPersistFile, (void **)&ppf );

			if ( SUCCEEDED( nResult ) )
			{

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

				FOREVER
				{
					nResult = psl->SetPath( pcszFilePath );		//	Sets the path and file name of a shell link object.

					if ( !SUCCEEDED( nResult ) ) break;

//···································································································

					if ( pcszWorkDir != 0 )
					{
						nResult = psl->SetWorkingDirectory( pcszWorkDir );		//	Sets the name of the working directory for a shell link object.

						if ( !SUCCEEDED( nResult ) ) break;
					}

//···································································································

					if ( pcszArgs != 0 )
					{
						nResult = psl->SetArguments( pcszArgs );		//	Sets the command-line arguments associated with a shell link object.

						if ( !SUCCEEDED( nResult ) ) break;
					}

//···································································································

					if ( pcszDescription != 0 )
					{
						nResult = psl->SetDescription( pcszDescription );		//	Sets the description string for a shell link object.

						if ( !SUCCEEDED( nResult ) ) break;
					}

//···································································································

					if ( pcszIconPath != 0 )
						nResult = psl->SetIconLocation( pcszIconPath, nIcon );	//	Sets the location (path and index) of the icon for a shell link object.
					else
						nResult = psl->SetIconLocation( pcszFilePath, nIcon );	//	Sets the location (path and index) of the icon for a shell link object.

					if ( !SUCCEEDED( nResult ) ) break;

//···································································································

					nResult = psl->SetShowCmd( nShowCmd );		//	Sets the show (SW_????) command for a shell link object.

					break;
				}

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

				if ( SUCCEEDED( nResult ) )
				{
					WCHAR	wszTmpFileName[MAX_PATH];

					// Ensure string is ANSI.
					if ( MultiByteToWideChar( CP_ACP, 0, pcszLinkPath, -1, wszTmpFileName, MAX_PATH ) != 0 )
						nResult = ppf->Save( wszTmpFileName, TRUE );		// Save the link via the IPersistFile::Save method.
					else
						nResult = -1;
				}

				ppf->Release();		// Release pointer to IPersistFile.
			}

			psl->Release();			// Release pointer to IShellLink.
		}
	}

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

	return( nResult );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com  All rights reserved.  Created: 2001-05-12©  Modified: 2016-03-25©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'pcszSubMenuFolder': May be set to 0.  Used to specify one or more submenus (folders) where		//
//								the shortcut will be actually created.													//
//																																	//
//	'pcszArgs': May be set to 0. 																							//
//																																	//
//	'pcszDescription': May be set to 0.																					//
//																																	//
// Note:	The link file specified by 'pcszLinkName' will be created or overwritten whatever			//
//			it has its read only attribute set or not.																//
//																																	//
//	Result: Returns the result of calling the functions inside this function or -1 for other			//
//			  errors.  Test the returned value like that: if ( SUCCEEDED( nResult ) ) then no error.	//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

HRESULT TT_CreateAppIcon( LPCTSTR pcszLinkName, LPCTSTR pcszAbsoluteAppFileName, LPCTSTR pcszStartingFolder,
								  LPCTSTR pcszSubMenuFolder, LPCTSTR pcszArgs, LPCTSTR pcszDescription,
								  const int cnIcon, const bool cbCreateItOnDesktopInstead )
{
	HRESULT			nResult = -1;		// Set to error by default.
	unsigned int	unAttributes;
	TCHAR				szLinkFileName[MAX_PATH];

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

	if ( ::SHGetFolderPath( 0, (cbCreateItOnDesktopInstead ? CSIDL_DESKTOPDIRECTORY : CSIDL_PROGRAMS),
								   0, SHGFP_TYPE_CURRENT, szLinkFileName ) == S_OK )
	{
		if ( !::PathIsRelative( pcszAbsoluteAppFileName ) )
		{
			if ( ::PathAppend( szLinkFileName, ((pcszSubMenuFolder != 0) ? pcszSubMenuFolder : _T("")) ) && TT_CreateFolder( szLinkFileName ) )
			{
				if ( ::PathAppend( szLinkFileName, pcszLinkName ) && ::PathAddExtension( szLinkFileName, TT_EXTENSION__lnk ) )
				{
					nResult = S_OK;	// Set to OK by default.

					if ( (unAttributes = ::GetFileAttributes( szLinkFileName )) != INVALID_FILE_ATTRIBUTES )	// File exists?
					{
						if ( (unAttributes & FILE_ATTRIBUTE_READONLY) != 0 )						// File is Read-only?
						{
							if ( ::SetFileAttributes( szLinkFileName, (unAttributes & ~FILE_ATTRIBUTE_READONLY) ) == 0 )
							{
								nResult = -1;	// Can not remove the read only attribute.
							}
						}
					}

					if ( SUCCEEDED( nResult ) )
					{
						nResult = TT_CreateLink( szLinkFileName, pcszAbsoluteAppFileName, pcszStartingFolder, pcszArgs,
														 pcszDescription, cnIcon, pcszAbsoluteAppFileName, SW_SHOWNORMAL );
					}
				}
			}
		}
	}

	return( nResult );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-25©  Modified: 2016-03-25©	//
//																																	//
//	Purpose:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_CreateDesktopShortcut( const bool cbPlaySound )
{
	bool		bStatus = FALSE;
	CString	strLinkName, strLinkDescription;

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

	if ( strLinkName.LoadString( IDS_LINKNAME_THREETIMERS ) && strLinkDescription.LoadString( IDS_LINKDESC_THREETIMERS ) )
	{
		if ( !_tcsIsEmpty( TT_szModuleFileName ) )	//	Additional checking just in case.
		{
			if ( SUCCEEDED( TT_CreateAppIcon( strLinkName, TT_szModuleFileName,
					 TT_szStartingFolder, 0, 0, strLinkDescription, -101, TRUE ) ) )
			{
				bStatus = TRUE;
			}
		}
	}

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

	if ( cbPlaySound )
	{
		::PlaySound( MAKEINTRESOURCE( (bStatus ? IDR_SHORTCUT_CREATED_WAVE : IDR_UHOH_MSG_WAVE) ),
						 TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
	}

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-07-12©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: Returns from the popup menu the selected menu item Id.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int TT_ProcessPopupMenu_TimersMenu( HWND hwndDlg, const bool cbIsShowFunnyExit )
{
	bool				bStatus					= FALSE;
	bool				bAddSeparator			= FALSE;
	HMENU				hMenuPopup				= 0;
	int				nIconCX					= JCH_Max( 16, ::GetSystemMetrics( SM_CXMENUCHECK ) );
	int				nIconCY					= JCH_Max( 16, ::GetSystemMetrics( SM_CYMENUCHECK ) );
	JCH_Pixel		pixMenuBgColor			= JCH_PixelFromColorRef( ::GetSysColor( COLOR_MENU ) );
	HBITMAP			hbitmapTag				= 0;
	HBITMAP			hbitmapSound			= 0;
	HBITMAP			hbitmapOpenFile		= 0;
	HBITMAP			hbitmapSettings		= 0;
	HBITMAP			hbitmapSaveFile		= 0;
	HBITMAP			hbitmapNewShortcut	= 0;
	HBITMAP			hbitmapAbout			= 0;
	HBITMAP			hbitmapExit				= 0;
	HICON				hiconTmp;
	int				nRtnValue;
	CRect				rectBtn;
	CPoint			pointScreenMouse;
	CString			strMenuItem;

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

	::GetWindowRect( ::GetDlgItem( hwndDlg, IDC_MENU ), &rectBtn );
	pointScreenMouse.x = (rectBtn.left + (rectBtn.Width()  / 2)); 
	pointScreenMouse.y = (rectBtn.top  + (rectBtn.Height() / 2)); 

//===================================================================================================

	FOREVER
	{
		if ( (hMenuPopup = ::CreatePopupMenu()) == 0 ) break;

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

		strMenuItem.LoadString( TT_hInst, IDS_MENU_ADJ_TIMERS_LABELS );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_ADJ_TIMERS_LABELS, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_TAG ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapTag = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_ADJ_TIMERS_LABELS, MF_BYCOMMAND, hbitmapTag, hbitmapTag );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_ADJ_EXTERNAL_SND );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_ADJ_EXTERNAL_SND, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_SOUND ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapSound = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_ADJ_EXTERNAL_SND, MF_BYCOMMAND, hbitmapSound, hbitmapSound );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_ADJ_OPEN_FILE );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_ADJ_OPEN_FILE, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_OPEN_FILE ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapOpenFile = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_ADJ_OPEN_FILE, MF_BYCOMMAND, hbitmapOpenFile, hbitmapOpenFile );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_ADJ_SETTINGS );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_ADJ_SETTINGS, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_SETTINGS ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapSettings = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_ADJ_SETTINGS, MF_BYCOMMAND, hbitmapSettings, hbitmapSettings );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_SAVE_CUR_SETTINGS );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_SAVE_CUR_SETTINGS, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_SAVE_FILE ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapSaveFile = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_SAVE_CUR_SETTINGS, MF_BYCOMMAND, hbitmapSaveFile, hbitmapSaveFile );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_CREATE_DESKTOP_SHORTCUT );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_CREATE_DESKTOP_SHORTCUT, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_NEW_SHORTCUT ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapNewShortcut = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_CREATE_DESKTOP_SHORTCUT, MF_BYCOMMAND, hbitmapNewShortcut, hbitmapNewShortcut );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_ABOUT );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_ABOUT, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_ABOUT ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapAbout = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_ABOUT, MF_BYCOMMAND, hbitmapAbout, hbitmapAbout );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		strMenuItem.LoadString( TT_hInst, (cbIsShowFunnyExit ? IDS_MENU_EXIT_FUNNY : IDS_MENU_EXIT) );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), (cbIsShowFunnyExit ? TT_IDM_EXIT_FUNNY : TT_IDM_EXIT), strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_ON_OFF ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapExit = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, (cbIsShowFunnyExit ? TT_IDM_EXIT_FUNNY : TT_IDM_EXIT), MF_BYCOMMAND, hbitmapExit, hbitmapExit );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_CLOSE );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_CloseMenu, strMenuItem ) == 0 ) break;

		bAddSeparator = TRUE;

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

		bStatus = TRUE;
		break;
	}

//===================================================================================================

	if ( !bStatus )
	{
		nRtnValue = TT_IDM_Error;
	}

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

	else
	{
		nRtnValue = (int)::TrackPopupMenuEx( hMenuPopup, (TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_NONOTIFY),
														 pointScreenMouse.x, pointScreenMouse.y, hwndDlg, 0 );
	}

//===================================================================================================

	if ( hbitmapTag != 0 )
	{
		::DeleteObject( hbitmapTag );
		hbitmapTag = 0;
	}

	if ( hbitmapSound != 0 )
	{
		::DeleteObject( hbitmapSound );
		hbitmapSound = 0;
	}

	if ( hbitmapOpenFile != 0 )
	{
		::DeleteObject( hbitmapOpenFile );
		hbitmapOpenFile = 0;
	}

	if ( hbitmapSettings != 0 )
	{
		::DeleteObject( hbitmapSettings );
		hbitmapSettings = 0;
	}

	if ( hbitmapSaveFile != 0 )
	{
		::DeleteObject( hbitmapSaveFile );
		hbitmapSaveFile = 0;
	}

	if ( hbitmapNewShortcut != 0 )
	{
		::DeleteObject( hbitmapNewShortcut );
		hbitmapNewShortcut = 0;
	}

	if ( hbitmapAbout != 0 )
	{
		::DeleteObject( hbitmapAbout );
		hbitmapAbout = 0;
	}

	if ( hbitmapExit != 0 )
	{
		::DeleteObject( hbitmapExit );
		hbitmapExit = 0;
	}

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

	if ( hMenuPopup != 0 )
	{
		::DestroyMenu( hMenuPopup );
		hMenuPopup = 0;
	}

//===================================================================================================

	if ( (nRtnValue == TT_IDM_ADJ_TIMERS_LABELS) || (nRtnValue == TT_IDM_ADJ_EXTERNAL_SND) ||
		  (nRtnValue == TT_IDM_ADJ_OPEN_FILE) || (nRtnValue == TT_IDM_ADJ_SETTINGS) )
	{
		INT_PTR	npResult = ::DialogBox( TT_hInst, MAKEINTRESOURCE( IDD_SETTINGS ), hwndDlg, DlgSettingsProc );

		if ( npResult == -1 )
		{
			::MessageBeep( MB_ICONHAND );
		}
		else if ( npResult == IDOK )
		{
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_1_GR ), TT_szTimerLabel1 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_2_GR ), TT_szTimerLabel2 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_3_GR ), TT_szTimerLabel3 );

			TT_PopulateTimerEventComboBox( hwndDlg, IDC_TIMER_EVENT_1_CB, (TT_dwTimerEvent1 - TT_REG_VAL__Timer_Event__FIRST_VALUE) );
			TT_PopulateTimerEventComboBox( hwndDlg, IDC_TIMER_EVENT_2_CB, (TT_dwTimerEvent2 - TT_REG_VAL__Timer_Event__FIRST_VALUE) );
			TT_PopulateTimerEventComboBox( hwndDlg, IDC_TIMER_EVENT_3_CB, (TT_dwTimerEvent3 - TT_REG_VAL__Timer_Event__FIRST_VALUE) );
		}
	}

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

	else if ( nRtnValue == TT_IDM_SAVE_CUR_SETTINGS )
	{
		bool		bStatus = TRUE;
		CString	strMainWindow;

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

		strMainWindow.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, TT_REG_KEY__MainWindow );

		if ( !TT_SaveScreenInfoToRegistry( strMainWindow, hwndDlg ) ) bStatus = FALSE;

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

		if ( TT_SaveMiscSettingsToRegistry( TT_bIsKeepWndOnTop, TT_bIsShowInTitleBar, TT_bIsFlashWndOnTimerUp,
				TT_bIsUseAltIconOnTimerUp, TT_bIsDisplaySmartCursors, TT_szExtSndLabel1, TT_szExtSndFileName1, TT_szExtSndLabel2,
				TT_szExtSndFileName2, TT_szExtSndLabel3, TT_szExtSndFileName3, TT_szOpenFileLabel1, TT_szOpenFileName1,
				TT_szOpenFileLabel2, TT_szOpenFileName2, TT_szOpenFileLabel3, TT_szOpenFileName3 ) != ERROR_SUCCESS )
		{
			bStatus = FALSE;
		}

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

		if ( TT_SaveTimerInfoToRegistry( 1, TT_szTimerLabel1, TT_dwTimerValue1, TT_dwTimerUnit1, TT_dwTimerEvent1 ) != ERROR_SUCCESS )
		{
			bStatus = FALSE;
		}

		if ( TT_SaveTimerInfoToRegistry( 2, TT_szTimerLabel2, TT_dwTimerValue2, TT_dwTimerUnit2, TT_dwTimerEvent2 ) != ERROR_SUCCESS )
		{
			bStatus = FALSE;
		}

		if ( TT_SaveTimerInfoToRegistry( 3, TT_szTimerLabel3, TT_dwTimerValue3, TT_dwTimerUnit3, TT_dwTimerEvent3 ) != ERROR_SUCCESS )
		{
			bStatus = FALSE;
		}

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

		if ( bStatus ) ::PlaySound( MAKEINTRESOURCE( IDR_SETTINGS_SAVED_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
		else				::MessageBeep( MB_ICONHAND );
	}

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

	else if ( nRtnValue == TT_IDM_CREATE_DESKTOP_SHORTCUT )
	{
		TT_CreateDesktopShortcut();
	}

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

	else if ( nRtnValue == TT_IDM_ABOUT )
	{
		if ( ::DialogBox( TT_hInst, MAKEINTRESOURCE( IDD_ABOUT ), hwndDlg, DlgAboutProc ) == -1 )
		{
			::MessageBeep( MB_ICONHAND );
		}
	}

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

	else if ( (nRtnValue == TT_IDM_EXIT) || (nRtnValue == TT_IDM_EXIT_FUNNY) )
	{
		::SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( ((nRtnValue == TT_IDM_EXIT_FUNNY) ?
							TT_IDC_Cmd__Ask_Exit_Funny : TT_IDC_Cmd__Ask_Exit), 0 ), 0 );
	}

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

	else	//	if ( (nRtnValue == TT_IDM_CloseMenu) || (nRtnValue == TT_IDM_NoMenu) || (nRtnValue == TT_IDM_Error) )
	{
		//	Do nothing.
 	}

//===================================================================================================

	return( nRtnValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-06-27©  Modified: 2016-08-08©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'cnTimerGroupId': Possible values are 'IDC_TIMER_1_GR', 'IDC_TIMER_2_GR' or 'IDC_TIMER_3_GR'.	//
//																																	//
//	Result: Returns from the popup menu the selected menu item Id.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int TT_ProcessPopupMenu_TimerGroupLabel( HWND hwndDlg, const int cnPosX, const int cnPosY, const int cnTimerGroupId )
{
	bool				bStatus					= FALSE;
	bool				bAddSeparator			= FALSE;
	HMENU				hMenuPopup				= 0;
	int				nIconCX					= JCH_Max( 16, ::GetSystemMetrics( SM_CXMENUCHECK ) );
	int				nIconCY					= JCH_Max( 16, ::GetSystemMetrics( SM_CYMENUCHECK ) );
	JCH_Pixel		pixMenuBgColor			= JCH_PixelFromColorRef( ::GetSysColor( COLOR_MENU ) );
	HBITMAP			hbitmapRename			= 0;
	HBITMAP			hbitmapReset			= 0;
	HICON				hiconTmp;
	unsigned int	unExtraFlags;
	int				nRtnValue;
	CPoint			pointScreenMouse( cnPosX, cnPosY );
	CString			strMenuItem, strTimerLabel;
	LPTSTR			pszTimerLabel;
	int				nTimerGroupId, nTimerLabelDfltStrId, nTimerStartStopBtnId;
	bool			  *pbIsEventTriggered;
	unsigned int	unMsgUsedToUpdate;

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

	::ClientToScreen( hwndDlg, &pointScreenMouse );

	if ( cnTimerGroupId == IDC_TIMER_1_GR )
	{
		pszTimerLabel			= TT_szTimerLabel1;
		nTimerGroupId			= IDC_TIMER_1_GR;
		nTimerLabelDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_1;
		nTimerStartStopBtnId = IDC_START_STOP_1_BT;
		pbIsEventTriggered	= &TT_bIsEventTriggered1;
		unMsgUsedToUpdate		= TT_WM_USER__TimerLabelChanged1;
	}
	else if ( cnTimerGroupId == IDC_TIMER_2_GR )
	{
		pszTimerLabel			= TT_szTimerLabel2;
		nTimerGroupId			= IDC_TIMER_2_GR;
		nTimerLabelDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_2;
		nTimerStartStopBtnId = IDC_START_STOP_2_BT;
		pbIsEventTriggered	= &TT_bIsEventTriggered2;
		unMsgUsedToUpdate		= TT_WM_USER__TimerLabelChanged2;
	}
	else	//	if ( cnTimerGroupId == IDC_TIMER_3_GR )
	{
		pszTimerLabel			= TT_szTimerLabel3;
		nTimerGroupId			= IDC_TIMER_3_GR;
		nTimerLabelDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_3;
		nTimerStartStopBtnId = IDC_START_STOP_3_BT;
		pbIsEventTriggered	= &TT_bIsEventTriggered3;
		unMsgUsedToUpdate		= TT_WM_USER__TimerLabelChanged3;
	}

//===================================================================================================

	FOREVER
	{
		if ( (hMenuPopup = ::CreatePopupMenu()) == 0 ) break;

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

		strMenuItem.LoadString( TT_hInst, IDS_MENU_MODIFY_TIMER_LABEL );

		if ( ::AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_MODIFY_TIMER_LABEL, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_RENAME ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapRename = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_MODIFY_TIMER_LABEL, MF_BYCOMMAND, hbitmapRename, hbitmapRename );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

		//················································

		strTimerLabel.LoadString( nTimerLabelDfltStrId );
		unExtraFlags = ((strTimerLabel != pszTimerLabel) ? MFS_ENABLED : MFS_DISABLED);

		strMenuItem.LoadString( TT_hInst, IDS_MENU_TIMER_LABEL_RESET );

		if ( ::AppendMenu( hMenuPopup, (unExtraFlags | MFT_STRING), TT_IDM_TIMER_LABEL_RESET, strMenuItem ) == 0 ) break;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_RESET ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapReset = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				::SetMenuItemBitmaps( hMenuPopup, TT_IDM_TIMER_LABEL_RESET, MF_BYCOMMAND, hbitmapReset, hbitmapReset );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

		//················································

		if ( TT_bIsUseAltIconOnTimerUp || *(pbIsEventTriggered) )
		{
			strMenuItem.LoadString( TT_hInst, IDS_MENU_RESET_TIMER_ICON );

			unExtraFlags = (*(pbIsEventTriggered) ? MFS_ENABLED : MFS_DISABLED);

			if ( ::AppendMenu( hMenuPopup, (unExtraFlags | MFT_STRING), TT_IDM_RESET_TIMER_ICON, strMenuItem ) == 0 ) break;

			bAddSeparator = TRUE;
		}

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_CLOSE );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_CloseMenu, strMenuItem ) == 0 ) break;

		bAddSeparator = TRUE;

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

		bStatus = TRUE;
		break;
	}

//===================================================================================================

	if ( !bStatus )
	{
		nRtnValue = TT_IDM_Error;
	}

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

	else
	{
		nRtnValue = (int)::TrackPopupMenuEx( hMenuPopup, (TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_NONOTIFY),
														 pointScreenMouse.x, pointScreenMouse.y, hwndDlg, 0 );
	}

//===================================================================================================

	if ( hbitmapRename != 0 )
	{
		::DeleteObject( hbitmapRename );
		hbitmapRename = 0;
	}

	if ( hbitmapReset != 0 )
	{
		::DeleteObject( hbitmapReset );
		hbitmapReset = 0;
	}

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

	if ( hMenuPopup != 0 )
	{
		::DestroyMenu( hMenuPopup );
		hMenuPopup = 0;
	}

//===================================================================================================

	if ( nRtnValue == TT_IDM_MODIFY_TIMER_LABEL )
	{
		//	We select the default "Menu" button to prevent a display bug when the 'TT_AskModifyTimerLabel()'
		//	function will return.  The display bug consists of two buttons appearing to have the focus.
		::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDC_MENU ), MAKELPARAM( TRUE, 0 ) );

		TT_AskModifyTimerLabel( hwndDlg, unMsgUsedToUpdate );
	}

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

	else if ( nRtnValue == TT_IDM_TIMER_LABEL_RESET )
	{
		strTimerLabel.LoadString( nTimerLabelDfltStrId );
		_tcscpy_s( pszTimerLabel, TT_TimerLabel_MaxBufCnt, strTimerLabel );
		::SetWindowText( ::GetDlgItem( hwndDlg, nTimerGroupId ), strTimerLabel.GetString() );
	}

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

	else if ( nRtnValue == TT_IDM_RESET_TIMER_ICON )
	{
		if ( *(pbIsEventTriggered) )
		{
			HICON		hiconTmp;

			*(pbIsEventTriggered) = FALSE;		//	Indicates to use the 'IDI_TIMER_START' icon.

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_TIMER_START ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );
			::PlaySound( MAKEINTRESOURCE( IDR_CHECKBOX_UNCHECKED_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
		}
	}

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

	else	//	if ( (nRtnValue == TT_IDM_CloseMenu) || (nRtnValue == TT_IDM_NoMenu) || (nRtnValue == TT_IDM_Error) )
	{
		//	Do nothing.
 	}

//===================================================================================================

	return( nRtnValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-23©  Modified: 2016-03-28©	//
//																																	//
//	Purpose:																														//
//																																	//
//	Result: Returns from the popup menu the selected menu item Id.												//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int TT_ProcessPopupMenu_AdvOptions( HWND hwndDlg )
{
	bool				bStatus					= FALSE;
	bool				bAddSeparator			= FALSE;
	HMENU				hMenuPopup				= 0;
	HMENU				hMenuPopup_TimersLabels, hMenuPopup_ExtSnd, hMenuPopup_OpenFile, hMenuPopup_OtherSettings;
	int				nIconCX					= JCH_Max( 16, ::GetSystemMetrics( SM_CXMENUCHECK ) );
	int				nIconCY					= JCH_Max( 16, ::GetSystemMetrics( SM_CYMENUCHECK ) );
	JCH_Pixel		pixMenuBgColor			= JCH_PixelFromColorRef( ::GetSysColor( COLOR_MENU ) );
	HBITMAP			hbitmapTag		 = 0;
	HBITMAP			hbitmapSound	 = 0;
	HBITMAP			hbitmapOpenFile = 0;
	HBITMAP			hbitmapSettings = 0;
	HBITMAP			hbitmapReset	 = 0;
	HBITMAP			hbitmapErase	 = 0;
	HBITMAP			hbitmapFill		 = 0;
	HICON				hiconTmp;
	int				nRtnValue, nMenuPopupPos;
	CRect				rectBtn;
	CPoint			pointScreenMouse;
	CString			strMenuItem;

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

	::GetWindowRect( ::GetDlgItem( hwndDlg, IDC_ADV_OPTIONS_BT ), &rectBtn );
	pointScreenMouse.x = (rectBtn.left + (rectBtn.Width()  / 2)); 
	pointScreenMouse.y = (rectBtn.top  + (rectBtn.Height() / 2)); 

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

	if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
			MAKEINTRESOURCE( IDI_RESET ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
	{
		hbitmapReset = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor );
		::DestroyIcon( hiconTmp );
		hiconTmp = 0;
	}

	if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
			MAKEINTRESOURCE( IDI_ERASE_FORM ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
	{
		hbitmapErase = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor );
		::DestroyIcon( hiconTmp );
		hiconTmp = 0;
	}

	if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
			MAKEINTRESOURCE( IDI_AUTO_FILL_FORM ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
	{
		hbitmapFill = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor );
		::DestroyIcon( hiconTmp );
		hiconTmp = 0;
	}

//===================================================================================================

	FOREVER
	{
		if ( (hMenuPopup = ::CreatePopupMenu()) == 0 ) break;

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

		if ( (hMenuPopup_TimersLabels = ::CreatePopupMenu()) == 0 ) break;

		strMenuItem.LoadString( TT_hInst, IDS_MENU_TIMERS_LABELS );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MF_POPUP), (UINT_PTR)hMenuPopup_TimersLabels, strMenuItem ) == 0 ) break;

		if ( (nMenuPopupPos = GetMenuItemCount( hMenuPopup )) == -1 ) break;

		nMenuPopupPos--;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_TAG ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapTag = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				SetMenuItemBitmaps( hMenuPopup, nMenuPopupPos, MF_BYPOSITION, hbitmapTag, hbitmapTag );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		if ( (hMenuPopup_ExtSnd = ::CreatePopupMenu()) == 0 ) break;

		strMenuItem.LoadString( TT_hInst, IDS_MENU_EXT_SND );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MF_POPUP), (UINT_PTR)hMenuPopup_ExtSnd, strMenuItem ) == 0 ) break;

		if ( (nMenuPopupPos = GetMenuItemCount( hMenuPopup )) == -1 ) break;

		nMenuPopupPos--;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_SOUND ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapSound = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				SetMenuItemBitmaps( hMenuPopup, nMenuPopupPos, MF_BYPOSITION, hbitmapSound, hbitmapSound );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		if ( (hMenuPopup_OpenFile = ::CreatePopupMenu()) == 0 ) break;

		strMenuItem.LoadString( TT_hInst, IDS_MENU_OPEN_FILE );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MF_POPUP), (UINT_PTR)hMenuPopup_OpenFile, strMenuItem ) == 0 ) break;

		if ( (nMenuPopupPos = GetMenuItemCount( hMenuPopup )) == -1 ) break;

		nMenuPopupPos--;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_OPEN_FILE ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapOpenFile = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				SetMenuItemBitmaps( hMenuPopup, nMenuPopupPos, MF_BYPOSITION, hbitmapOpenFile, hbitmapOpenFile );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		if ( (hMenuPopup_OtherSettings = ::CreatePopupMenu()) == 0 ) break;

		strMenuItem.LoadString( TT_hInst, IDS_MENU_OTHER_SETTINGS );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MF_POPUP), (UINT_PTR)hMenuPopup_OtherSettings, strMenuItem ) == 0 ) break;

		if ( (nMenuPopupPos = GetMenuItemCount( hMenuPopup )) == -1 ) break;

		nMenuPopupPos--;

		if ( (hiconTmp = (HICON)::LoadImage( TT_hInst,
				MAKEINTRESOURCE( IDI_SETTINGS ), IMAGE_ICON, nIconCX, nIconCY, LR_DEFAULTCOLOR )) != 0 )
		{
			if ( (hbitmapSettings = TT_Create32BitsBitmapFrom32BitsIcon( hiconTmp, pixMenuBgColor )) != 0 )
			{
				SetMenuItemBitmaps( hMenuPopup, nMenuPopupPos, MF_BYPOSITION, hbitmapSettings, hbitmapSettings );
			}

			::DestroyIcon( hiconTmp );
			hiconTmp = 0;
		}

		bAddSeparator = TRUE;

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

		if ( bAddSeparator && (bAddSeparator = (AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_SEPARATOR), 0, 0 ) == 0)) ) break;

		//················································

		strMenuItem.LoadString( TT_hInst, IDS_MENU_CLOSE );

		if ( AppendMenu( hMenuPopup, (MFS_ENABLED | MFT_STRING), TT_IDM_CloseMenu, strMenuItem ) == 0 ) break;

		bAddSeparator = TRUE;

//===================================================================================================
// Creating sub-menus in 'hMenuPopup_TimersLabels'.

		strMenuItem.LoadString( TT_hInst, IDS_MENU_TIMERS_LABELS_RESET );

		if ( ::AppendMenu( hMenuPopup_TimersLabels, (MFS_ENABLED | MFT_STRING), TT_IDM_TIMERS_LABELS_RESET, strMenuItem ) == 0 ) break;

		if ( hbitmapReset != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_TimersLabels, TT_IDM_TIMERS_LABELS_RESET, MF_BYCOMMAND, hbitmapReset, hbitmapReset );
		}

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

		strMenuItem.LoadString( TT_hInst, IDS_MENU_TIMERS_LABELS_FILL );

		if ( ::AppendMenu( hMenuPopup_TimersLabels, (MFS_ENABLED | MFT_STRING), TT_IDM_TIMERS_LABELS_FILL, strMenuItem ) == 0 ) break;

		if ( hbitmapFill != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_TimersLabels, TT_IDM_TIMERS_LABELS_FILL, MF_BYCOMMAND, hbitmapFill, hbitmapFill );
		}

//===================================================================================================
// Creating sub-menus in 'hMenuPopup_ExtSnd'.

		strMenuItem.LoadString( TT_hInst, IDS_MENU_EXT_SND_RESET );

		if ( ::AppendMenu( hMenuPopup_ExtSnd, (MFS_ENABLED | MFT_STRING), TT_IDM_EXT_SND_RESET, strMenuItem ) == 0 ) break;

		if ( hbitmapErase != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_ExtSnd, TT_IDM_EXT_SND_RESET, MF_BYCOMMAND, hbitmapErase, hbitmapErase );
		}

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

		strMenuItem.LoadString( TT_hInst, IDS_MENU_EXT_SND_FILL );

		if ( ::AppendMenu( hMenuPopup_ExtSnd, (MFS_ENABLED | MFT_STRING), TT_IDM_EXT_SND_FILL, strMenuItem ) == 0 ) break;

		if ( hbitmapFill != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_ExtSnd, TT_IDM_EXT_SND_FILL, MF_BYCOMMAND, hbitmapFill, hbitmapFill );
		}

//===================================================================================================
// Creating sub-menus in 'hMenuPopup_OpenFile'.

		strMenuItem.LoadString( TT_hInst, IDS_MENU_OPEN_FILE_RESET );

		if ( ::AppendMenu( hMenuPopup_OpenFile, (MFS_ENABLED | MFT_STRING), TT_IDM_OPEN_FILE_RESET, strMenuItem ) == 0 ) break;

		if ( hbitmapErase != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_OpenFile, TT_IDM_OPEN_FILE_RESET, MF_BYCOMMAND, hbitmapErase, hbitmapErase );
		}

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

		strMenuItem.LoadString( TT_hInst, IDS_MENU_OPEN_FILE_FILL );

		if ( ::AppendMenu( hMenuPopup_OpenFile, (MFS_ENABLED | MFT_STRING), TT_IDM_OPEN_FILE_FILL, strMenuItem ) == 0 ) break;

		if ( hbitmapFill != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_OpenFile, TT_IDM_OPEN_FILE_FILL, MF_BYCOMMAND, hbitmapFill, hbitmapFill );
		}

//===================================================================================================
// Creating sub-menus in 'hMenuPopup_OtherSettings'.

		strMenuItem.LoadString( TT_hInst, IDS_MENU_OTHER_SETTINGS_RESET );

		if ( ::AppendMenu( hMenuPopup_OtherSettings, (MFS_ENABLED | MFT_STRING), TT_IDM_OTHER_SETTINGS_RESET, strMenuItem ) == 0 ) break;

		if ( hbitmapReset != 0 )
		{
			::SetMenuItemBitmaps( hMenuPopup_OtherSettings, TT_IDM_OTHER_SETTINGS_RESET, MF_BYCOMMAND, hbitmapReset, hbitmapReset );
		}

//===================================================================================================

		bStatus = TRUE;
		break;
	}

//===================================================================================================

	if ( !bStatus )
	{
		nRtnValue = TT_IDM_Error;
	}

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

	else
	{
		nRtnValue = (int)::TrackPopupMenuEx( hMenuPopup, (TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_NONOTIFY),
														 pointScreenMouse.x, pointScreenMouse.y, hwndDlg, 0 );
	}

//===================================================================================================

	if ( hbitmapSound != 0 )
	{
		::DeleteObject( hbitmapSound );
		hbitmapSound = 0;
	}

	if ( hbitmapOpenFile != 0 )
	{
		::DeleteObject( hbitmapOpenFile );
		hbitmapOpenFile = 0;
	}

	if ( hbitmapSettings != 0 )
	{
		::DeleteObject( hbitmapSettings );
		hbitmapSettings = 0;
	}

	if ( hbitmapTag != 0 )
	{
		::DeleteObject( hbitmapTag );
		hbitmapTag = 0;
	}

	if ( hbitmapReset != 0 )
	{
		::DeleteObject( hbitmapReset );
		hbitmapReset = 0;
	}

	if ( hbitmapErase != 0 )
	{
		::DeleteObject( hbitmapErase );
		hbitmapErase = 0;
	}

	if ( hbitmapFill != 0 )
	{
		::DeleteObject( hbitmapFill );
		hbitmapFill = 0;
	}

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

	if ( hMenuPopup != 0 )
	{
		::DestroyMenu( hMenuPopup );
		hMenuPopup = 0;
	}

//===================================================================================================

	if ( (nRtnValue == TT_IDM_TIMERS_LABELS_RESET) || (nRtnValue == TT_IDM_TIMERS_LABELS_FILL) )
	{
		bool		bIsAutoFill = (nRtnValue == TT_IDM_TIMERS_LABELS_FILL);
		TCHAR		szTimerLabel1[TT_TimerLabel_MaxBufCnt];
		TCHAR		szTimerLabel2[TT_TimerLabel_MaxBufCnt];
		TCHAR		szTimerLabel3[TT_TimerLabel_MaxBufCnt];
		CString	strLabel;

		strLabel.LoadString( (bIsAutoFill ? IDS_Timer_Label__DemoValue_1 : IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_1) );
		_tcscpy_s( szTimerLabel1, strLabel );

		strLabel.LoadString( (bIsAutoFill ? IDS_Timer_Label__DemoValue_2 : IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_2) );
		_tcscpy_s( szTimerLabel2, strLabel );

		strLabel.LoadString( (bIsAutoFill ? IDS_Timer_Label__DemoValue_3 : IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_3) );
		_tcscpy_s( szTimerLabel3, strLabel );

		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_1_ED ), szTimerLabel1 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_2_ED ), szTimerLabel2 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_3_ED ), szTimerLabel3 );

		::PlaySound( MAKEINTRESOURCE( (bIsAutoFill ? IDR_USE_DEFAULT_VALUE_WAVE : IDR_CLEAR_VALUE_WAVE) ),
						 TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
	}

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

	else if ( (nRtnValue == TT_IDM_EXT_SND_RESET) || (nRtnValue == TT_IDM_EXT_SND_FILL) )
	{
		bool		bIsAutoFill = (nRtnValue == TT_IDM_EXT_SND_FILL);
		TCHAR		szExtSndLabel1[TT_ExtSndLabel_MaxBufCnt];
		TCHAR		szExtSndLabel2[TT_ExtSndLabel_MaxBufCnt];
		TCHAR		szExtSndLabel3[TT_ExtSndLabel_MaxBufCnt];
		TCHAR		szExtSndFileName1[TT_ExtSndFileName_MaxBufCnt];
		TCHAR		szExtSndFileName2[TT_ExtSndFileName_MaxBufCnt];
		TCHAR		szExtSndFileName3[TT_ExtSndFileName_MaxBufCnt];
		TCHAR		szWindowsMediaFolder[MAX_PATH];
		CString	strLabel, strMedia, strSoundName;

		strLabel.LoadString( (bIsAutoFill ? IDS_ExtSnd_Label__DemoValue_1 : IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_1) );
		_tcscpy_s( szExtSndLabel1, strLabel );

		strLabel.LoadString( (bIsAutoFill ? IDS_ExtSnd_Label__DemoValue_2 : IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_2) );
		_tcscpy_s( szExtSndLabel2, strLabel );

		strLabel.LoadString( (bIsAutoFill ? IDS_ExtSnd_Label__DemoValue_3 : IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_3) );
		_tcscpy_s( szExtSndLabel3, strLabel );

		if ( bIsAutoFill )
		{
			unsigned int	unRtnVal = ::GetWindowsDirectory( szWindowsMediaFolder, _countof( szWindowsMediaFolder ) );

			strMedia.LoadString( IDS_WINDOWS_MEDIA_FOLDER );

			if ( (unRtnVal == 0) || (unRtnVal >= _countof( szWindowsMediaFolder )) || !::PathAppend( szWindowsMediaFolder, strMedia ) )
			{
				_tcscpy( szWindowsMediaFolder, _T("C:\\") );
			}

			strSoundName.LoadString( IDS_ExtSnd_FileName__DemoValue_1 );
			_tcscpy_s( szExtSndFileName1, szWindowsMediaFolder );
			::PathAppend( szExtSndFileName1, strSoundName );
			TT_PathAddQuoteSpaces( szExtSndFileName1, FALSE );

			strSoundName.LoadString( IDS_ExtSnd_FileName__DemoValue_2 );
			_tcscpy_s( szExtSndFileName2, szWindowsMediaFolder );
			::PathAppend( szExtSndFileName2, strSoundName );
			TT_PathAddQuoteSpaces( szExtSndFileName2, FALSE );

			strSoundName.LoadString( IDS_ExtSnd_FileName__DemoValue_3 );
			_tcscpy_s( szExtSndFileName3, szWindowsMediaFolder );
			::PathAppend( szExtSndFileName3, strSoundName );
			TT_PathAddQuoteSpaces( szExtSndFileName3, FALSE );
		}
		else
		{
			_tcsEmpty( szExtSndFileName1 );
			_tcsEmpty( szExtSndFileName2 );
			_tcsEmpty( szExtSndFileName3 );
		}

		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_1_ED ), szExtSndLabel1 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_2_ED ), szExtSndLabel2 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_3_ED ), szExtSndLabel3 );

		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_1_ED ), szExtSndFileName1 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_2_ED ), szExtSndFileName2 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_3_ED ), szExtSndFileName3 );

		::PlaySound( MAKEINTRESOURCE( (bIsAutoFill ? IDR_USE_DEFAULT_VALUE_WAVE : IDR_CLEAR_VALUE_WAVE) ),
						 TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
	}

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

	else if ( (nRtnValue == TT_IDM_OPEN_FILE_RESET) || (nRtnValue == TT_IDM_OPEN_FILE_FILL) )
	{
		bool		bIsAutoFill = (nRtnValue == TT_IDM_OPEN_FILE_FILL);
		TCHAR		szOpenFileLabel1[TT_OpenFileLabel_MaxBufCnt];
		TCHAR		szOpenFileLabel2[TT_OpenFileLabel_MaxBufCnt];
		TCHAR		szOpenFileLabel3[TT_OpenFileLabel_MaxBufCnt];
		TCHAR		szOpenFileName1[TT_OpenFileName_MaxBufCnt];
		TCHAR		szOpenFileName2[TT_OpenFileName_MaxBufCnt];
		TCHAR		szOpenFileName3[TT_OpenFileName_MaxBufCnt];
		CString	strLabel, strFileName, strNotepadFileName;

		strLabel.LoadString( (bIsAutoFill ? IDS_OpenFile_Label__DemoValue_1 : IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_1) );
		_tcscpy_s( szOpenFileLabel1, strLabel );

		strLabel.LoadString( (bIsAutoFill ? IDS_OpenFile_Label__DemoValue_2 : IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_2) );
		_tcscpy_s( szOpenFileLabel2, strLabel );

		strLabel.LoadString( (bIsAutoFill ? IDS_OpenFile_Label__DemoValue_3 : IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_3) );
		_tcscpy_s( szOpenFileLabel3, strLabel );

		if ( bIsAutoFill )
		{
			strFileName.LoadString( IDS_OpenFile_FileName__DemoValue_1 );
			_tcscpy_s( szOpenFileName1, strFileName );

			strFileName.LoadString( IDS_OpenFile_FileName__DemoValue_2 );
			_tcscpy_s( szOpenFileName2, strFileName );

			strFileName.LoadString( IDS_OpenFile_FileName__DemoValue_3 );

			if ( TT_BIT_GetDfltValues_Notepad( &strNotepadFileName ) ) strFileName = (strNotepadFileName + _T(" ") + strFileName);

			_tcscpy_s( szOpenFileName3, strFileName );
		}
		else
		{
			_tcsEmpty( szOpenFileName1 );
			_tcsEmpty( szOpenFileName2 );
			_tcsEmpty( szOpenFileName3 );
		}

		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_1_ED ), szOpenFileLabel1 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_2_ED ), szOpenFileLabel2 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_3_ED ), szOpenFileLabel3 );

		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_1_ED ), szOpenFileName1 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_2_ED ), szOpenFileName2 );
		::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_3_ED ), szOpenFileName3 );

		::PlaySound( MAKEINTRESOURCE( (bIsAutoFill ? IDR_USE_DEFAULT_VALUE_WAVE : IDR_CLEAR_VALUE_WAVE) ),
						 TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
	}

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

	else if ( nRtnValue == TT_IDM_OTHER_SETTINGS_RESET )
	{
		TT_bIsKeepWndOnTop		  = TRUE;
		TT_bIsShowInTitleBar		  = TRUE;
		TT_bIsFlashWndOnTimerUp	  = TRUE;
		TT_bIsUseAltIconOnTimerUp = TRUE;
		TT_bIsDisplaySmartCursors = TRUE;

		::CheckDlgButton( hwndDlg, IDC_KEEP_WND_ON_TOP_CK			  , (TT_bIsKeepWndOnTop			 ? BST_CHECKED : BST_UNCHECKED) );
		::CheckDlgButton( hwndDlg, IDC_SHOW_TIMERS_IN_TITLEBAR_CK  , (TT_bIsShowInTitleBar		 ? BST_CHECKED : BST_UNCHECKED) );
		::CheckDlgButton( hwndDlg, IDC_FLASH_WINDOW_ON_TIMER_UP_CK , (TT_bIsFlashWndOnTimerUp	 ? BST_CHECKED : BST_UNCHECKED) );
		::CheckDlgButton( hwndDlg, IDC_SHOW_ALT_ICON_ON_TIMER_UP_CK, (TT_bIsUseAltIconOnTimerUp ? BST_CHECKED : BST_UNCHECKED) );
		::CheckDlgButton( hwndDlg, IDC_DISPLAY_SMART_CURSORS_CK	  , (TT_bIsDisplaySmartCursors ? BST_CHECKED : BST_UNCHECKED) );

		::PlaySound( MAKEINTRESOURCE( IDR_USE_DEFAULT_VALUE_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
	}

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

	else	//	if ( (nRtnValue == TT_IDM_CloseMenu) || (nRtnValue == TT_IDM_NoMenu) || (nRtnValue == TT_IDM_Error) )
	{
		//	Do nothing.
 	}

//===================================================================================================

	return( nRtnValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2003-08-12©  Modified: 2016-07-11©	//
//																																	//
//	Purpose:	OFNHookProc hook procedure message handler.															//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

UINT_PTR CALLBACK TT_AskWaveFile_HookProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{

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

	switch( uMsg )
	{
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	case WM_INITDIALOG:
		{
			OPENFILENAME  *pOFN = (OPENFILENAME *)lParam;

			::SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)pOFN );	 

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_CUSTOMLOADWAVE__PLAY_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_PLAY ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_CUSTOMLOADWAVE__STOP_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_STOP ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			return( TRUE );
			break;
		}
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	case WM_DESTROY:
		{
			OPENFILENAME  *pOFN = (OPENFILENAME *)::GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
			HICON				hiconTmp;

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

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_CUSTOMLOADWAVE__PLAY_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_CUSTOMLOADWAVE__STOP_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

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

			if ( pOFN != 0 )
			{
				struct TT_AskFile_Params  *pAFP = (struct TT_AskFile_Params *)pOFN->lCustData;

				pAFP->bPatch_CDN_INITDONE_Processed = FALSE;	// Avoid unwanted call to TT_CenterWindow() in WM_SIZE next time the dialog will open.
			}

			::PlaySound( 0, 0, 0 );		// Just to be sure that no sound is played anymore.

			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//	Messages order when dialog opens: WM_SIZE with minimal dialog dimensions, then WM_NOTIFY,	then
//	another WM_SIZE ONLY if a resizing is required.  The time comparaison is to prevent a quick
//	flashing display bug that occurs if no resizing was required after WM_NOTIFY (because the dialog
//	still has its minimal dimensions) and the user moves the dialog at position other than the one set
//	by TT_CenterWindow() and finally the user resize the dialog.  At this time the dialog sends a
//	WM_SIZE but it is the first one after WM_NOTIFY, so m_bPatch_CDN_INITDONE_Processed is set to TRUE
//	and TT_CenterWindow() is called moving back the dialog to the center!	With this patch, if more
// than 1 second elapses between the WM_NOTIFY message and the next WM_SIZE message, the
//	TT_CenterWindow() function will not be called.  On the other hands, a user has only one second
// if he wants to reproduce this bug!

	case WM_SIZE:
		{
			OPENFILENAME  *pOFN = (OPENFILENAME *)::GetWindowLongPtr( hwndDlg, GWLP_USERDATA );

			if ( pOFN != 0 )
			{
				struct TT_AskFile_Params  *pAFP = (struct TT_AskFile_Params *)pOFN->lCustData;
	
				if ( pAFP->bPatch_CDN_INITDONE_Processed )
				{
					pAFP->bPatch_CDN_INITDONE_Processed = FALSE;

					if ( (::GetTickCount() - pAFP->dwPatch_CDN_INITDONE_Tick) < 1000 )	// User has 1 second if he wants to see the bug!
					{
						TT_CenterWindow( ::GetParent( hwndDlg ), pOFN->hwndOwner );
					}
				}
			}

			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_NOTIFY:
		{
			LPNMHDR			pNMHdr			= (LPNMHDR)lParam;
			unsigned int	unRtnVal			= 0;	
			bool				bValueReturned = FALSE;

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

			if ( (pNMHdr->code == CDN_INITDONE) || (pNMHdr->code == CDN_FILEOK) )
			{
				LPOFNOTIFY						pOFNotify = (LPOFNOTIFY)pNMHdr;
				struct TT_AskFile_Params  *pAFP		 = (struct TT_AskFile_Params *)pOFNotify->lpOFN->lCustData;

				if ( pNMHdr->code == CDN_INITDONE )
				{
					TT_CenterWindow( ::GetParent( hwndDlg ), pOFNotify->lpOFN->hwndOwner );
					pAFP->bPatch_CDN_INITDONE_Processed = TRUE;
					pAFP->dwPatch_CDN_INITDONE_Tick = ::GetTickCount();
				}

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

				else if ( pNMHdr->code == CDN_FILEOK )
				{
					bValueReturned = TRUE;
					unRtnVal			= 0;	//	Accepted.
				}
			}

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

			if ( bValueReturned ) 
				::SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, unRtnVal );	//	Must be here.  Read about 'DWLP_MSGRESULT' for more info. 

			return( bValueReturned );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
	
	case WM_COMMAND:
		{
			int		nCommandId  = LOWORD( wParam );
			int		nNotifyCode = HIWORD( wParam );
			TCHAR		szWaveFileName[MAX_PATH];

			switch( nCommandId )
			{

//===================================================================================================

			case IDC_CUSTOMLOADWAVE__PLAY_BT:
				{
					CommDlg_OpenSave_GetFilePath( ::GetParent( hwndDlg ), szWaveFileName, _countof( szWaveFileName ) );

					// Checking if file exists	to avoid PlaySound() searching in other folders.
					if ( ::PathFileExists( szWaveFileName ) && !::PathIsDirectory( szWaveFileName ) )
					{
						::PlaySound( szWaveFileName, 0, (SND_ASYNC | SND_FILENAME | SND_NODEFAULT) );
					}

					return( TRUE );
					break;
				}

//===================================================================================================

			case IDC_CUSTOMLOADWAVE__STOP_BT:
				{
					::PlaySound( 0, 0, 0 );		//	Stop any currently played sound.
					return( TRUE );
					break;
				}

//===================================================================================================
			
			default:
				{
					return( FALSE );
					break;
				}

//===================================================================================================
			
			}

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	default:
		{
			return( 0 );
			break;
		}
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	}
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by JCH Inc.    All rights reserved.    Created: 2001-01-06©   Modified: 2001-05-27©			//
//																																	//
//	Purpose:	Customize the Load Image dialog box.																	//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

UINT_PTR CALLBACK TT_AskOpenFile_HookProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{

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

	switch( uMsg )
	{
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	case WM_INITDIALOG:
		{
			OPENFILENAME  *pOFN = (OPENFILENAME *)lParam;

			::SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)pOFN );

			return( TRUE );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	case WM_DESTROY:
		{
			OPENFILENAME  *pOFN = (OPENFILENAME *)::GetWindowLongPtr( hwndDlg, GWLP_USERDATA );

			if ( pOFN != 0 )
			{
				struct TT_AskFile_Params  *pAFP = (struct TT_AskFile_Params *)pOFN->lCustData;

				pAFP->bPatch_CDN_INITDONE_Processed = FALSE;	// Avoid unwanted call to TT_CenterWindow() in WM_SIZE next time the dialog will open.
			}

			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//	Messages order when dialog opens: WM_SIZE with minimal dialog dimensions, then WM_NOTIFY,	then
//	another WM_SIZE ONLY if a resizing is required.  The time comparison is to prevent a quick
//	flashing display bug that occurs if no resizing was required after WM_NOTIFY (because the dialog
//	still has its minimal dimensions) and the user moves the dialog at position other than the one set
//	by TT_CenterWindow() and finally the user resize the dialog.  At this time the dialog sends a
//	WM_SIZE but it is the first one after WM_NOTIFY, so bPatch_CDN_INITDONE_Processed is set to TRUE
//	and TT_CenterWindow() is called moving back the dialog to the center!	With this patch, if more
// than 1 second elapses between the WM_NOTIFY message and the next WM_SIZE message, the
//	TT_CenterWindow() function will not be called.  On the other hands, a user has only one second if
// he wants to reproduce this bug!

	case WM_SIZE:
		{
			OPENFILENAME  *pOFN = (OPENFILENAME *)::GetWindowLongPtr( hwndDlg, GWLP_USERDATA );

			if ( pOFN != 0 )
			{
				struct TT_AskFile_Params  *pAFP = (struct TT_AskFile_Params *)pOFN->lCustData;
	
				if ( pAFP->bPatch_CDN_INITDONE_Processed )
				{
					pAFP->bPatch_CDN_INITDONE_Processed = FALSE;

					if ( (::GetTickCount() - pAFP->dwPatch_CDN_INITDONE_Tick) < 1000 )	// User has 1 second if he wants to see the bug!
					{
						TT_CenterWindow( ::GetParent( hwndDlg ), pOFN->hwndOwner );
					}
				}
			}

			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_NOTIFY:
		{
			LPNMHDR			pNMHdr			= (LPNMHDR)lParam;
			unsigned int	unRtnVal			= 0;	
			bool				bValueReturned = FALSE;

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

			if ( (pNMHdr->code == CDN_INITDONE) || (pNMHdr->code == CDN_FILEOK) )
			{
				LPOFNOTIFY						pOFNotify = (LPOFNOTIFY)pNMHdr;
				struct TT_AskFile_Params  *pAFP		 = (struct TT_AskFile_Params *)pOFNotify->lpOFN->lCustData;

				if ( pNMHdr->code == CDN_INITDONE )
				{
					TT_CenterWindow( GetParent( hwndDlg ), pOFNotify->lpOFN->hwndOwner );
					pAFP->bPatch_CDN_INITDONE_Processed = TRUE;
					pAFP->dwPatch_CDN_INITDONE_Tick = ::GetTickCount();
				}

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

				else if ( pNMHdr->code == CDN_FILEOK )
				{
					bValueReturned = TRUE;
					unRtnVal			= 0;	//	Accepted.
				}
			}

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

			if ( bValueReturned ) 
				::SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, unRtnVal );	//	Must be here.  Read about 'DWLP_MSGRESULT' for more info. 

			return( bValueReturned );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	default:
		{
			return( 0 );
			break;
		}
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	}
}
 

/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-16©  Modified: 2016-08-08©	//
//																																	//
//	Purpose:	Message handler for the 'IDD_THREETIMERS' dialog box.												//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

INT_PTR CALLBACK DlgThreeTimersProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	INT_PTR	npRtnValue = FALSE;	// Set to "message not processed" by default.

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

	switch( uMsg )
	{

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_INITDIALOG:
		{
			if ( (TT_unpTimerIdEvent == 0) && (::SetTimer( hwndDlg, TT_cunpTimerIdEvent, TT_cdwTimerElapse, 0 ) != 0) )
			{
				HICON				hiconTmp;
				unsigned int	unTimerId;
				int				nValue, nUnitType, nEventId, nTimerGroupId, nTimerValueEditId, nUnitComboBoxId, nEventComboBoxId;
				TCHAR				szTimerLabel[TT_TimerLabel_MaxBufCnt];
				CRect				rectDlgDflt, rectDlg;
				CString			strMainWindow, strText, strCurTimerKeyName, strCurRegKeyName;
				CString			strSeconds, strMinutes, strHours;

				TT_unpTimerIdEvent = TT_cunpTimerIdEvent;
				TT_bIsFlashWndContinuously = FALSE;

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

				::GetWindowRect( hwndDlg, &rectDlgDflt );
				strMainWindow.Format( _T("%s\\%s"), (LPCTSTR)TT_strREG_KEY__ADELUC_TTn, TT_REG_KEY__MainWindow );

				TT_LoadScreenInfoFromRegistry( strMainWindow, rectDlgDflt, &rectDlg );
				::SetWindowPos( hwndDlg, (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
									 rectDlg.left, rectDlg.top, 0, 0, (SWP_NOSIZE | SWP_NOACTIVATE) );

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

				TT_LoadMiscSettingsFromRegistry( &TT_bIsKeepWndOnTop, &TT_bIsShowInTitleBar, &TT_bIsFlashWndOnTimerUp,
															&TT_bIsUseAltIconOnTimerUp, &TT_bIsDisplaySmartCursors,
															TT_szExtSndLabel1, TT_szExtSndFileName1, TT_szExtSndLabel2,
															TT_szExtSndFileName2, TT_szExtSndLabel3, TT_szExtSndFileName3,
															TT_szOpenFileLabel1, TT_szOpenFileName1, TT_szOpenFileLabel2,
															TT_szOpenFileName2, TT_szOpenFileLabel3, TT_szOpenFileName3 );

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

				strSeconds.LoadString( TT_hInst, IDS_SECONDS );
				strMinutes.LoadString( TT_hInst, IDS_MINUTES );
				strHours.LoadString(	  TT_hInst, IDS_HOURS	);

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

				for( unTimerId = 1; (unTimerId <= 3); unTimerId++ )
				{
					TT_LoadTimerInfoFromRegistry( unTimerId, szTimerLabel, &nValue, &nUnitType, &nEventId );

					if ( unTimerId == 1 )
					{
						_tcscpy_s( TT_szTimerLabel1, szTimerLabel );
						TT_dwTimerValue1  = nValue;
						TT_dwTimerUnit1   = nUnitType;
						TT_dwTimerEvent1  = nEventId;
						nTimerGroupId	   = IDC_TIMER_1_GR;
						nTimerValueEditId = IDC_TIMER_VALUE_1_ED;
						nUnitComboBoxId   = IDC_TIME_UNIT_1_CB;
						nEventComboBoxId  = IDC_TIMER_EVENT_1_CB;
					}
					else if ( unTimerId == 2 )
					{
						_tcscpy_s( TT_szTimerLabel2, szTimerLabel );
						TT_dwTimerValue2  = nValue;
						TT_dwTimerUnit2   = nUnitType;
						TT_dwTimerEvent2  = nEventId;
						nTimerGroupId	   = IDC_TIMER_2_GR;
						nTimerValueEditId = IDC_TIMER_VALUE_2_ED;
						nUnitComboBoxId   = IDC_TIME_UNIT_2_CB;
						nEventComboBoxId  = IDC_TIMER_EVENT_2_CB;
					}
					else if ( unTimerId == 3 )
					{
						_tcscpy_s( TT_szTimerLabel3, szTimerLabel );
						TT_dwTimerValue3  = nValue;
						TT_dwTimerUnit3   = nUnitType;
						TT_dwTimerEvent3  = nEventId;
						nTimerGroupId	   = IDC_TIMER_3_GR;
						nTimerValueEditId = IDC_TIMER_VALUE_3_ED;
						nUnitComboBoxId   = IDC_TIME_UNIT_3_CB;
						nEventComboBoxId  = IDC_TIMER_EVENT_3_CB;
					}

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

					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerGroupId ), szTimerLabel );

					::SendMessage( ::GetDlgItem( hwndDlg, nTimerValueEditId ), EM_SETLIMITTEXT, (TT_TimerValue_MaxBufCnt - EOS_CHAR_COUNT), 0 );
					strText = TT_FormatTimerValue( nValue, nUnitType, TRUE );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );

					::SendMessage( ::GetDlgItem( hwndDlg, nUnitComboBoxId ), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strSeconds );  
					::SendMessage( ::GetDlgItem( hwndDlg, nUnitComboBoxId ), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strMinutes );  
					::SendMessage( ::GetDlgItem( hwndDlg, nUnitComboBoxId ), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strHours	);  
					::SendMessage( ::GetDlgItem( hwndDlg, nUnitComboBoxId ), CB_SETCURSEL, (nUnitType - TT_REG_VAL__Timer_Unit__FIRST_VALUE), 0 );  

					TT_PopulateTimerEventComboBox( hwndDlg, nEventComboBoxId, (nEventId - TT_REG_VAL__Timer_Event__FIRST_VALUE) );
				}

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

				::CheckDlgButton( hwndDlg, IDC_KEEP_WND_ON_TOP_CK, (TT_bIsKeepWndOnTop ? BST_CHECKED : BST_UNCHECKED) );
				::SetWindowPos( hwndDlg, (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
									 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) );

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

				if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_1_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
					::DestroyIcon( hiconTmp );

				::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_1_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
									MAKEINTRESOURCE( IDI_TIMER_START ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );


				if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_2_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
					::DestroyIcon( hiconTmp );

				::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_2_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
									MAKEINTRESOURCE( IDI_TIMER_START ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );


				if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_3_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
					::DestroyIcon( hiconTmp );

				::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_3_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
									MAKEINTRESOURCE( IDI_TIMER_START ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );


				::SendMessage( ::GetDlgItem( hwndDlg, IDC_MENU ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
									MAKEINTRESOURCE( IDI_POPUP_MENU ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

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

				::SendMessage( hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)::LoadImage( TT_hInst, MAKEINTRESOURCE( IDI_THREETIMERS ),
									IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );		//	32x32 is required because of displayed icon in TaskBar.

				::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDC_START_STOP_1_BT ), MAKELPARAM( TRUE, 0 ) );
				npRtnValue = (INT_PTR)FALSE;	//	Focus has been set manually.
			}

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

			else
			{
				::EndDialog( hwndDlg, -1 );
			}

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

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_SYSCOMMAND:
		{
			int	nCommandId = (wParam & 0xFFF0);

			if ( nCommandId == SC_CLOSE )
			{
				bool	bIsFunnyExit = ((::GetKeyState( VK_SHIFT ) < 0) || (::GetKeyState( VK_CONTROL ) < 0));

				::SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( (bIsFunnyExit ? TT_IDC_Cmd__Ask_Exit_Funny : TT_IDC_Cmd__Ask_Exit), 0 ), 0 );

				npRtnValue = (INT_PTR)TRUE;
			}

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_COMMAND:
		{
			int	nCommandId	= LOWORD( wParam );
			int	nNotifyCode	= HIWORD( wParam );

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

			if ( nCommandId == IDOK )
			{
				//	We do nothing.
				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( nCommandId == IDCANCEL )
			{
				//	We trap the ESCAPE key here and do nothing.
				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nCommandId == TT_IDC_Cmd__Ask_Exit) || (nCommandId == TT_IDC_Cmd__Ask_Exit_Funny) )
			{
				bool				bExitApp		= TRUE;
				unsigned int	unTimerCount = 0;
				CString			strTitle, strMsg;

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

				if ( TT_bIsTimerStarted1 ) unTimerCount++;
				if ( TT_bIsTimerStarted2 ) unTimerCount++;
				if ( TT_bIsTimerStarted3 ) unTimerCount++;

				if ( unTimerCount != 0 )
				{
					strTitle.LoadString( TT_hInst, IDS_MSGBOXTITLE_ASK_EXIT_APP );
					strMsg.Format( ((unTimerCount <= 1) ? IDS_MSGBOXTEXT_ASK_EXIT_APP_1_TIMER :
																	  IDS_MSGBOXTEXT_ASK_EXIT_APP_N_TIMERS), unTimerCount );
					bExitApp = (::MessageBox( hwndDlg, strMsg, strTitle, (MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1) ) == IDYES);
				}

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

				if ( bExitApp )
				{
					::EndDialog( hwndDlg, 0 );	  	

					if ( nCommandId == TT_IDC_Cmd__Ask_Exit_Funny )
					{
						//	Must be 'SND_SYNC' here otherwise the sound will stop immediately.
						::PlaySound( MAKEINTRESOURCE( IDR_FUNNY_EXIT_WAVE ), TT_hInst, (SND_SYNC | SND_RESOURCE | SND_NODEFAULT) );
					}
				}

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_MENU) )
			{
				HWND	hwndCurFocus = ::GetFocus();
				int	nTimerStartStopBtnId;
				
				//	This special block of code is to start immediately the timer when the user press the "Enter" key
				//	while modifying a timer value.  This code works because the "Menu" button is the default button.

				if		  ( hwndCurFocus == ::GetDlgItem( hwndDlg, IDC_TIMER_VALUE_1_ED ) ) nTimerStartStopBtnId = IDC_START_STOP_1_BT;
				else if ( hwndCurFocus == ::GetDlgItem( hwndDlg, IDC_TIMER_VALUE_2_ED ) ) nTimerStartStopBtnId = IDC_START_STOP_2_BT;
				else if ( hwndCurFocus == ::GetDlgItem( hwndDlg, IDC_TIMER_VALUE_3_ED ) ) nTimerStartStopBtnId = IDC_START_STOP_3_BT;
				else																							  nTimerStartStopBtnId = 0;
				
				//------------------------------------------------

				if ( nTimerStartStopBtnId != 0 )
				{
					//	Sending this 'WM_NEXTDLGCTL' message here will trigger the immediate processing of the
					//	'WM_COMMAND' message with 'EN_KILLFOCUS' notification for the edit control that had the
					//	focus, allowing the validation and formatting of its value before the timer is started.
					TT_bIsCalledFromEnterKey = TRUE;	//	It can be cleared during the processing of the edit control on error/clipping.
					::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDC_MENU ), MAKELPARAM( TRUE, 0 ) );

					if ( TT_bIsCalledFromEnterKey )
					{
						TT_bIsCalledFromEnterKey = FALSE;
						::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), MAKELPARAM( TRUE, 0 ) );
						::SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( nTimerStartStopBtnId, BN_CLICKED ),
											(LPARAM)GetDlgItem( hwndDlg, nTimerStartStopBtnId ) );
					}
				}
				
				//················································

				else	//	Normal selection of the "Menu" button.
				{
					bool	bIsShowFunnyExit = ((::GetKeyState( VK_SHIFT ) < 0) || (::GetKeyState( VK_CONTROL ) < 0));

					//	This condition guarantees that all edit controls have been processed.
					if ( ::GetFocus() != ::GetDlgItem( hwndDlg, IDC_MENU ) )
						::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDC_MENU ), MAKELPARAM( TRUE, 0 ) );

					TT_ProcessPopupMenu_TimersMenu( hwndDlg, bIsShowFunnyExit );
				}
				
				//------------------------------------------------

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_KEEP_WND_ON_TOP_CK) )
			{
				TT_bIsKeepWndOnTop = (::IsDlgButtonChecked( hwndDlg, IDC_KEEP_WND_ON_TOP_CK ) == BST_CHECKED);

				::SetWindowPos( hwndDlg, (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
									 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) );

				::PlaySound( MAKEINTRESOURCE( (TT_bIsKeepWndOnTop ? IDR_CHECKBOX_CHECKED_WAVE :
								 IDR_CHECKBOX_UNCHECKED_WAVE) ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == CBN_SELCHANGE) &&
						 ((nCommandId == IDC_TIME_UNIT_1_CB) || (nCommandId == IDC_TIME_UNIT_2_CB) || (nCommandId == IDC_TIME_UNIT_3_CB)) )
			{
				DWORD			  *pdwTimerValue;
				DWORD			  *pdwTimerUnit;
				int				nTimerValueEditId, nUnitComboBoxId;
				CString			strText;

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

				if ( nCommandId == IDC_TIME_UNIT_1_CB )
				{
					pdwTimerValue		= &TT_dwTimerValue1;
					pdwTimerUnit		= &TT_dwTimerUnit1;
					nTimerValueEditId = IDC_TIMER_VALUE_1_ED;
					nUnitComboBoxId	= IDC_TIME_UNIT_1_CB;
				}
				else if ( nCommandId == IDC_TIME_UNIT_2_CB )
				{
					pdwTimerValue		= &TT_dwTimerValue2;
					pdwTimerUnit		= &TT_dwTimerUnit2;
					nTimerValueEditId = IDC_TIMER_VALUE_2_ED;
					nUnitComboBoxId	= IDC_TIME_UNIT_2_CB;
				}
				else if ( nCommandId == IDC_TIME_UNIT_3_CB )
				{
					pdwTimerValue		= &TT_dwTimerValue3;
					pdwTimerUnit		= &TT_dwTimerUnit3;
					nTimerValueEditId = IDC_TIMER_VALUE_3_ED;
					nUnitComboBoxId	= IDC_TIME_UNIT_3_CB;
				}

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

				*(pdwTimerUnit) = TT_GetTimerUnitFromComboBox( hwndDlg, nUnitComboBoxId );

				strText = TT_FormatTimerValue( *(pdwTimerValue), *(pdwTimerUnit), TRUE );
				::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == CBN_SELCHANGE) &&
						 ((nCommandId == IDC_TIMER_EVENT_1_CB) || (nCommandId == IDC_TIMER_EVENT_2_CB) || (nCommandId == IDC_TIMER_EVENT_3_CB)) )
			{
				if		  ( nCommandId == IDC_TIMER_EVENT_1_CB ) TT_dwTimerEvent1 = TT_GetEventIdFromComboBox( hwndDlg, nCommandId );
				else if ( nCommandId == IDC_TIMER_EVENT_2_CB ) TT_dwTimerEvent2 = TT_GetEventIdFromComboBox( hwndDlg, nCommandId );
				else if ( nCommandId == IDC_TIMER_EVENT_3_CB ) TT_dwTimerEvent3 = TT_GetEventIdFromComboBox( hwndDlg, nCommandId );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( ((nNotifyCode == BN_CLICKED) &&
						 ((nCommandId == IDC_START_STOP_1_BT) || (nCommandId == IDC_START_STOP_2_BT) || (nCommandId == IDC_START_STOP_3_BT))) ||
						 ((nCommandId == TT_IDC_Cmd__STOP_1 ) || (nCommandId == TT_IDC_Cmd__STOP_2 ) || (nCommandId == TT_IDC_Cmd__STOP_3)) )
			{
				bool				bIsMinimizeAsked = (::GetKeyState( VK_SHIFT ) < 0);	//	Shift key pressed?
				bool				bManualStop		  = ((nCommandId == IDC_START_STOP_1_BT) ||
															  (nCommandId == IDC_START_STOP_2_BT) || (nCommandId == IDC_START_STOP_3_BT));
				HWND				hwndCurFocus	  = ::GetFocus();
				unsigned int	unFormat;
				HICON				hiconTmp;
				bool			  *pbIsTimerStarted, *pbIsEventCalled, *pbIsEventTriggered;
				DWORD			  *pdwTimerValue;
				DWORD			  *pdwTimerStarted;
				DWORD			  *pdwCountDownValue;
				int				nTimerStartStopBtnId, nTimerValueEditId, nUnitComboBoxId;
				CString			strText;

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

				if ( (nCommandId == IDC_START_STOP_1_BT) || (nCommandId == TT_IDC_Cmd__STOP_1) )
				{
					pbIsTimerStarted		= &TT_bIsTimerStarted1;
					pbIsEventCalled		= &TT_bIsEventCalled1;
					pbIsEventTriggered	= &TT_bIsEventTriggered1;
					pdwTimerValue			= &TT_dwTimerValue1;
					pdwTimerStarted		= &TT_dwTimerStarted1;
					pdwCountDownValue		= &TT_dwCountDownValue1;
					nTimerStartStopBtnId = IDC_START_STOP_1_BT;
					nTimerValueEditId		= IDC_TIMER_VALUE_1_ED;
					nUnitComboBoxId		= IDC_TIME_UNIT_1_CB;
				}
				else if ( (nCommandId == IDC_START_STOP_2_BT) || (nCommandId == TT_IDC_Cmd__STOP_2) )
				{
					pbIsTimerStarted		= &TT_bIsTimerStarted2;
					pbIsEventCalled		= &TT_bIsEventCalled2;
					pbIsEventTriggered	= &TT_bIsEventTriggered2;
					pdwTimerValue			= &TT_dwTimerValue2;
					pdwTimerStarted		= &TT_dwTimerStarted2;
					pdwCountDownValue		= &TT_dwCountDownValue2;
					nTimerStartStopBtnId = IDC_START_STOP_2_BT;
					nTimerValueEditId		= IDC_TIMER_VALUE_2_ED;
					nUnitComboBoxId		= IDC_TIME_UNIT_2_CB;
				}
				else	// if ( (nCommandId == IDC_START_STOP_3_BT) || (nCommandId == TT_IDC_Cmd__STOP_3) )
				{
					pbIsTimerStarted		= &TT_bIsTimerStarted3;
					pbIsEventCalled		= &TT_bIsEventCalled3;
					pbIsEventTriggered	= &TT_bIsEventTriggered3;
					pdwTimerValue			= &TT_dwTimerValue3;
					pdwTimerStarted		= &TT_dwTimerStarted3;
					pdwCountDownValue		= &TT_dwCountDownValue3;
					nTimerStartStopBtnId = IDC_START_STOP_3_BT;
					nTimerValueEditId		= IDC_TIMER_VALUE_3_ED;
					nUnitComboBoxId		= IDC_TIME_UNIT_3_CB;
				}

				unFormat = TT_GetTimerUnitFromComboBox( hwndDlg, nUnitComboBoxId );

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

				if ( *(pbIsTimerStarted) == FALSE )
				{
					*(pbIsTimerStarted)   = TRUE;
					*(pbIsEventCalled)    = FALSE;		//	Used to prevents the triggered event to be called more than once per countdown.
					*(pbIsEventTriggered) = FALSE;		//	Indicates to use the 'IDI_TIMER_START' icon.
					*(pdwTimerStarted)    = ::GetTickCount();
					*(pdwCountDownValue)  = (*(pdwTimerValue) / 1000);		//	Converts value into seconds.

					strText = TT_FormatTimerValue( (*(pdwCountDownValue) * 1000), unFormat );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );

					strText.LoadString( TT_hInst, IDS_BTN_STOP_LABEL );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), (LPCTSTR)strText );

					if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
						::DestroyIcon( hiconTmp );

					::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
										MAKEINTRESOURCE( IDI_TIMER_STOP ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );

					if ( (hwndCurFocus == ::GetDlgItem( hwndDlg, nTimerValueEditId )) ||		//	Do we need to set the focus on an enabled control
						  (hwndCurFocus == ::GetDlgItem( hwndDlg, nUnitComboBoxId )) )			//	 so the shortkeys continue to be processed?
					{
						::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), MAKELPARAM( TRUE, 0 ) );
					}

					::EnableWindow( ::GetDlgItem( hwndDlg, nTimerValueEditId ), FALSE );
					::EnableWindow( ::GetDlgItem( hwndDlg, nUnitComboBoxId	), FALSE );
					::PlaySound( MAKEINTRESOURCE( IDR_TIMER_START_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

					if ( bIsMinimizeAsked ) ::ShowWindow( hwndDlg, SW_MINIMIZE ); 
				}
				else	//	if ( *(pbIsTimerStarted) == TRUE )
				{
					*(pbIsTimerStarted) = FALSE;

					if ( !bManualStop && TT_bIsUseAltIconOnTimerUp )
						*(pbIsEventTriggered) = TRUE;		//	Indicates to use the 'IDI_TIMER_START_DONE' icon.
					else
						*(pbIsEventTriggered) = FALSE;	//	Indicates to use the 'IDI_TIMER_START' icon.

					strText.LoadString( TT_hInst, IDS_BTN_START_LABEL );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), (LPCTSTR)strText );

					if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
						::DestroyIcon( hiconTmp );

					::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
										MAKEINTRESOURCE( (*(pbIsEventTriggered) ? IDI_TIMER_START_DONE : IDI_TIMER_START) ),
										IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );

					strText = TT_FormatTimerValue( *(pdwTimerValue), unFormat, TRUE );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );
					::EnableWindow( ::GetDlgItem( hwndDlg, nTimerValueEditId ), TRUE );
					::EnableWindow( ::GetDlgItem( hwndDlg, nUnitComboBoxId	), TRUE );

					if ( bManualStop )
					{
						::PlaySound( MAKEINTRESOURCE( IDR_TIMER_STOP_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
					}
				}

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

				if ( TT_bIsShowInTitleBar ) TT_UpdateWindowTitle( hwndDlg );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == EN_KILLFOCUS) &&
						 ((nCommandId == IDC_TIMER_VALUE_1_ED) || (nCommandId == IDC_TIMER_VALUE_2_ED) || (nCommandId == IDC_TIMER_VALUE_3_ED)) )
			{
				DWORD			  *pdwTimerValue;
				DWORD			  *pdwTimerUnit;
				int				nTimerValueEditId, nRtnVal;
				unsigned int	unValue;
				CString			strText;

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

				if ( nCommandId == IDC_TIMER_VALUE_1_ED )
				{
					pdwTimerValue		= &TT_dwTimerValue1;
					pdwTimerUnit		= &TT_dwTimerUnit1;
					nTimerValueEditId = IDC_TIMER_VALUE_1_ED;
				}
				else if ( nCommandId == IDC_TIMER_VALUE_2_ED )
				{
					pdwTimerValue		= &TT_dwTimerValue2;
					pdwTimerUnit		= &TT_dwTimerUnit2;
					nTimerValueEditId = IDC_TIMER_VALUE_2_ED;
				}
				else	// if ( nCommandId == IDC_TIMER_VALUE_3_ED )
				{
					pdwTimerValue		= &TT_dwTimerValue3;
					pdwTimerUnit		= &TT_dwTimerUnit3;
					nTimerValueEditId = IDC_TIMER_VALUE_3_ED;
				}

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

				strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ) );
				
				if ( (nRtnVal = TT_GetTimerValue( strText, &unValue, *(pdwTimerUnit) )) <= 0 )	//	Error or value clipped?
				{
					if ( nRtnVal == 0 ) *(pdwTimerValue) = unValue;		//	Successful but value clipped.

					TT_bIsCalledFromEnterKey = FALSE;	//	Cancels the timer auto-start because of error/clipping.
					strText = TT_FormatTimerValue( *(pdwTimerValue), *(pdwTimerUnit), TRUE );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );
					::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, nTimerValueEditId ), MAKELPARAM( TRUE, 0 ) );
					::PlaySound( MAKEINTRESOURCE( IDR_UHOH_MSG_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
				}
				else	//	Successful.
				{
					*(pdwTimerValue) = unValue;
					strText = TT_FormatTimerValue( *(pdwTimerValue), *(pdwTimerUnit), TRUE );
					::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );
				}

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

				npRtnValue = (INT_PTR)TRUE;
			}

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

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_DESTROY:
		{
			HICON		hiconTmp;

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

			if ( TT_unpTimerIdEvent != 0 )
			{
				::KillTimer( hwndDlg, TT_unpTimerIdEvent );
				TT_unpTimerIdEvent = 0;
			}

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

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_1_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_2_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_START_STOP_3_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_MENU ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( hwndDlg, WM_GETICON, ICON_SMALL, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			npRtnValue = (INT_PTR)TRUE;
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_TIMER:
		{
			if ( (TT_unpTimerIdEvent != 0) && (TT_unpTimerIdEvent == wParam) )
			{
				if ( TT_bIsTimerStarted1 || TT_bIsTimerStarted2 || TT_bIsTimerStarted3 )
				{
					DWORD				dwCurrentTime = ::GetMessageTime();
					bool				bUpdateTitle  = FALSE;
					bool			  *pbIsTimerStarted, *pbIsEventCalled;
					DWORD			  *pdwTimerValue;
					DWORD			  *pdwTimerStarted;
					DWORD			  *pdwCountDownValue;
					int				nTimerValueEditId, nUnitComboBoxId, nEventComboBoxId, nVirtualCmdId;
					DWORD				dwElapsedTime, dwCurCountDownValue;
					unsigned int	unTimerId, unFormat;
					CString			strText;

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

					for( unTimerId = 1; (unTimerId <= 3); unTimerId++ )
					{
						if ( unTimerId == 1 )
						{
							pbIsTimerStarted  = &TT_bIsTimerStarted1;
							pbIsEventCalled   = &TT_bIsEventCalled1;
							pdwTimerValue	   = &TT_dwTimerValue1;
							pdwTimerStarted   = &TT_dwTimerStarted1;
							pdwCountDownValue = &TT_dwCountDownValue1;
							nTimerValueEditId = IDC_TIMER_VALUE_1_ED;
							nUnitComboBoxId   = IDC_TIME_UNIT_1_CB;
							nEventComboBoxId  = IDC_TIMER_EVENT_1_CB;
							nVirtualCmdId		= TT_IDC_Cmd__STOP_1;
						}
						else if ( unTimerId == 2 )
						{
							pbIsTimerStarted  = &TT_bIsTimerStarted2;
							pbIsEventCalled   = &TT_bIsEventCalled2;
							pdwTimerValue	   = &TT_dwTimerValue2;
							pdwTimerStarted   = &TT_dwTimerStarted2;
							pdwCountDownValue = &TT_dwCountDownValue2;
							nTimerValueEditId = IDC_TIMER_VALUE_2_ED;
							nUnitComboBoxId   = IDC_TIME_UNIT_2_CB;
							nEventComboBoxId  = IDC_TIMER_EVENT_2_CB;
							nVirtualCmdId		= TT_IDC_Cmd__STOP_2;
						}
						else	//	if ( unTimerId == 3 )
						{
							pbIsTimerStarted	= &TT_bIsTimerStarted3;
							pbIsEventCalled   = &TT_bIsEventCalled3;
							pdwTimerValue	   = &TT_dwTimerValue3;
							pdwTimerStarted   = &TT_dwTimerStarted3;
							pdwCountDownValue = &TT_dwCountDownValue3;
							nTimerValueEditId = IDC_TIMER_VALUE_3_ED;
							nUnitComboBoxId   = IDC_TIME_UNIT_3_CB;
							nEventComboBoxId  = IDC_TIMER_EVENT_3_CB;
							nVirtualCmdId		= TT_IDC_Cmd__STOP_3;
						}

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

						if ( *(pbIsTimerStarted) )
						{
							dwElapsedTime = (dwCurrentTime - *(pdwTimerStarted));
							unFormat		  = TT_GetTimerUnitFromComboBox( hwndDlg, nUnitComboBoxId );

							if ( dwElapsedTime >= *(pdwTimerValue) )
							{
								*(pdwCountDownValue) = 0;
								strText = TT_FormatTimerValue( (*(pdwCountDownValue) * 1000), unFormat );
								::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );
								::UpdateWindow( ::GetDlgItem( hwndDlg, nTimerValueEditId ) );

								if ( TT_bIsShowInTitleBar ) TT_UpdateWindowTitle( hwndDlg );

								if ( TT_bIsFlashWndOnTimerUp )
								{
									FLASHWINFO	fwi = { sizeof( FLASHWINFO ), hwndDlg,  (FLASHW_CAPTION | FLASHW_TRAY), 4, 500 };

									if ( ::GetForegroundWindow() != hwndDlg )
									{
										TT_bIsFlashWndContinuously = TRUE;
										fwi.dwFlags |= FLASHW_TIMER;
										fwi.uCount   = 0xFFFFFFFF;
									}

									::FlashWindowEx( &fwi );
								}

								if ( !*(pbIsEventCalled) )		//	Prevents the triggered event to be called more than once per countdown.
								{
									*(pbIsEventCalled) = TRUE;
									TT_ExecuteEventId( hwndDlg, TT_GetEventIdFromComboBox( hwndDlg, nEventComboBoxId ) );
								}
								else ASSERT( 0 );

								::Sleep( 200 );	//	Gives a chance to briefly see the value 0.
								::SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( nVirtualCmdId, 0 ), 0 );
							}
							else
							{
								dwCurCountDownValue = (((*(pdwTimerValue) - dwElapsedTime) + 999) / 1000);

								if ( *(pdwCountDownValue) != dwCurCountDownValue )
								{
									*(pdwCountDownValue) = dwCurCountDownValue;
									strText = TT_FormatTimerValue( (*(pdwCountDownValue) * 1000), unFormat );

									::SetWindowText( ::GetDlgItem( hwndDlg, nTimerValueEditId ), (LPCTSTR)strText );
									bUpdateTitle = TRUE;
								}
							}
						}
					}

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

					if ( bUpdateTitle && TT_bIsShowInTitleBar ) TT_UpdateWindowTitle( hwndDlg );
				}

				npRtnValue = (INT_PTR)TRUE;
			}

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_ACTIVATE:
		{
			bool	bIsWndActivated = ((LOWORD( wParam ) == WA_ACTIVE) || (LOWORD( wParam ) == WA_CLICKACTIVE));

			if ( bIsWndActivated && TT_bIsFlashWndContinuously )
			{
				FLASHWINFO	fwi = { sizeof( FLASHWINFO ), hwndDlg,  (FLASHW_CAPTION | FLASHW_TRAY | FLASHW_STOP), 0, 0 };

				TT_bIsFlashWndContinuously = FALSE;
				::FlashWindowEx( &fwi );
			}

			npRtnValue = (INT_PTR)TRUE;

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hwndDlg, WM_ACTIVATE, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_SETCURSOR:
		{
			if ( TT_bIsDisplaySmartCursors )
			{
				DWORD		dwCursorPos = ::GetMessagePos();
				CPoint	pointMouse( GET_X_LPARAM( dwCursorPos ), GET_Y_LPARAM( dwCursorPos ) );

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

				::ScreenToClient( hwndDlg, &pointMouse );

				if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_1_GR, IDC_START_STOP_1_BT ) ||
					  TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_2_GR, IDC_START_STOP_2_BT ) ||
					  TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_3_GR, IDC_START_STOP_3_BT ) )
				{
					::SetCursor( TT_hCursorClick_LXR );
					npRtnValue = TRUE;
				}
			}

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hwndDlg, WM_SETCURSOR, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_LBUTTONDBLCLK:
		{
			bool				bIsControlKeyDown = ((wParam & MK_CONTROL) != 0);
			bool				bResetLabel			= FALSE;
			unsigned int	unMsgUsedToUpdate = 0;
			LPTSTR			pszTimerLabel;
			int				nTimerGroupId;
			CPoint			pointMouse( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) );
			CString			strTimerLabel;

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

			if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_1_GR, IDC_START_STOP_1_BT ) )
			{
				if ( bIsControlKeyDown )
				{
					pszTimerLabel = TT_szTimerLabel1;
					nTimerGroupId = IDC_TIMER_1_GR;
					strTimerLabel.LoadString( IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_1 );
					bResetLabel	  = (strTimerLabel != pszTimerLabel);
				}
				else unMsgUsedToUpdate = TT_WM_USER__TimerLabelChanged1;

				npRtnValue = TRUE;
			}
			else if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_2_GR, IDC_START_STOP_2_BT ) )
			{
				if ( bIsControlKeyDown )
				{
					pszTimerLabel = TT_szTimerLabel2;
					nTimerGroupId = IDC_TIMER_2_GR;
					strTimerLabel.LoadString( IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_2 );
					bResetLabel	  = (strTimerLabel != pszTimerLabel);
				}
				else unMsgUsedToUpdate = TT_WM_USER__TimerLabelChanged2;

				npRtnValue = TRUE;
			}
			else if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_3_GR, IDC_START_STOP_3_BT ) )
			{
				if ( bIsControlKeyDown )
				{
					pszTimerLabel = TT_szTimerLabel3;
					nTimerGroupId = IDC_TIMER_3_GR;
					strTimerLabel.LoadString( IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_3 );
					bResetLabel	  = (strTimerLabel != pszTimerLabel);
				}
				else unMsgUsedToUpdate = TT_WM_USER__TimerLabelChanged3;

				npRtnValue = TRUE;
			}

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

			if ( bResetLabel )
			{
				_tcscpy_s( pszTimerLabel, TT_TimerLabel_MaxBufCnt, strTimerLabel );
				::SetWindowText( ::GetDlgItem( hwndDlg, nTimerGroupId ), strTimerLabel.GetString() );
			}

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

			if ( unMsgUsedToUpdate != 0 )
			{
				//	We select the default "Menu" button to prevent a display bug when the 'TT_AskModifyTimerLabel()'
				//	function will return.  The display bug consists of two buttons appearing to have the focus.
				::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDC_MENU ), MAKELPARAM( TRUE, 0 ) );

				TT_AskModifyTimerLabel( hwndDlg, unMsgUsedToUpdate );
			}

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hwndDlg, WM_LBUTTONDBLCLK, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_LBUTTONDOWN:
		{
			bool		bResetBtnIcon = FALSE;
			int		nTimerStartStopBtnId;
			HICON		hiconTmp;
			CPoint	pointMouse( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) );

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

			if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_1_GR, IDC_START_STOP_1_BT ) )
			{
				if ( TT_bIsEventTriggered1 )
				{
					TT_bIsEventTriggered1 = FALSE;		//	Indicates to use the 'IDI_TIMER_START' icon.
					bResetBtnIcon			 = TRUE;
					nTimerStartStopBtnId	 = IDC_START_STOP_1_BT;
				}
				npRtnValue = TRUE;
			}
			else if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_2_GR, IDC_START_STOP_2_BT ) )
			{
				if ( TT_bIsEventTriggered2 )
				{
					TT_bIsEventTriggered2 = FALSE;		//	Indicates to use the 'IDI_TIMER_START' icon.
					bResetBtnIcon			 = TRUE;
					nTimerStartStopBtnId	 = IDC_START_STOP_2_BT;
				}
				npRtnValue = TRUE;
			}
			else if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_3_GR, IDC_START_STOP_3_BT ) )
			{
				if ( TT_bIsEventTriggered3 )
				{
					TT_bIsEventTriggered3 = FALSE;		//	Indicates to use the 'IDI_TIMER_START' icon.
					bResetBtnIcon			 = TRUE;
					nTimerStartStopBtnId	 = IDC_START_STOP_3_BT;
				}
				npRtnValue = TRUE;
			}

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

			if ( bResetBtnIcon )
			{
				if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
					::DestroyIcon( hiconTmp );

				::SendMessage( ::GetDlgItem( hwndDlg, nTimerStartStopBtnId ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
									MAKEINTRESOURCE( IDI_TIMER_START ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );
				::PlaySound( MAKEINTRESOURCE( IDR_CHECKBOX_UNCHECKED_WAVE ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );
			}

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hwndDlg, WM_LBUTTONDOWN, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_RBUTTONUP:
		{
			int		nTimerGroupId = 0;
			CPoint	pointMouse( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) );

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

			if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_1_GR, IDC_START_STOP_1_BT ) )
			{
				nTimerGroupId = IDC_TIMER_1_GR;
				npRtnValue	  = TRUE;
			}
			else if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_2_GR, IDC_START_STOP_2_BT ) )
			{
				nTimerGroupId = IDC_TIMER_2_GR;
				npRtnValue	  = TRUE;
			}
			else if ( TT_IsMouseOver_TimerGroupLabel( pointMouse.x, pointMouse.y, hwndDlg, IDC_TIMER_3_GR, IDC_START_STOP_3_BT ) )
			{
				nTimerGroupId = IDC_TIMER_3_GR;
				npRtnValue	  = TRUE;
			}

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

			if ( nTimerGroupId != 0 ) TT_ProcessPopupMenu_TimerGroupLabel( hwndDlg, pointMouse.x, pointMouse.y, nTimerGroupId );

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hwndDlg, WM_RBUTTONUP, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case TT_WM_USER__TimerLabelChanged1:
	case TT_WM_USER__TimerLabelChanged2:
	case TT_WM_USER__TimerLabelChanged3:
		{
			struct TT_ModifyTimerLabelTinyWnd  *pMTLTW = (struct TT_ModifyTimerLabelTinyWnd *)lParam;

			if ( pMTLTW != NULL )
			{
				::SetWindowText( ::GetDlgItem( pMTLTW->m_hwndDialogBox, pMTLTW->m_nTimerGroupId ), *(pMTLTW->m_pszTimerLabel) );

				if ( pMTLTW->m_bIsEnterKeyPressed && ::IsWindowEnabled( ::GetDlgItem( pMTLTW->m_hwndDialogBox, pMTLTW->m_nTimerValueEditId ) ) )
				{
					::SendMessage( pMTLTW->m_hwndDialogBox, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem(
										pMTLTW->m_hwndDialogBox, pMTLTW->m_nTimerValueEditId ), MAKELPARAM( TRUE, 0 ) );
				}
			}

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	}

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

	return( npRtnValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-21©  Modified: 2016-07-07©	//
//																																	//
//	Purpose:	Message handler for the 'IDD_SETTINGS' dialog box.													//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

INT_PTR CALLBACK DlgSettingsProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	INT_PTR		npRtnValue = FALSE;	// Set to "message not processed" by default.

	static bool			bIsKeepWndOnTop_Old			= TRUE;		//	Overwritten in 'WM_INITDIALOG'. 
	static bool			bIsShowInTitleBar_Old		= TRUE;		//	Overwritten in 'WM_INITDIALOG'.
	static bool			bIsFlashWndOnTimerUp_Old	= TRUE;		//	Overwritten in 'WM_INITDIALOG'.
	static bool			bIsUseAltIconOnTimerUp_Old	= TRUE;		//	Overwritten in 'WM_INITDIALOG'.
	static bool			bIsDisplaySmartCursors_Old = TRUE;		//	Overwritten in 'WM_INITDIALOG'.
	static COLORREF	clrEditTxtBg					= 0;
	static HBRUSH		hbrushEditTxtBg				= 0;

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

	switch( uMsg )
	{

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_INITDIALOG:
		{
			size_t	sztLength;

			bIsKeepWndOnTop_Old			= TT_bIsKeepWndOnTop; 
			bIsShowInTitleBar_Old		= TT_bIsShowInTitleBar;
			bIsFlashWndOnTimerUp_Old	= TT_bIsFlashWndOnTimerUp;
			bIsUseAltIconOnTimerUp_Old	= TT_bIsUseAltIconOnTimerUp;
			bIsDisplaySmartCursors_Old = TT_bIsDisplaySmartCursors;

			clrEditTxtBg = JCH_PixelToColorRef( JCH_PixelMixRGBA( JCH_PixelFromColorRef( ::GetSysColor( COLOR_WINDOW ) ),
																					JCH_PixelFromColorRef( ::GetSysColor( COLOR_3DFACE ) ),
																					(unsigned int)(0.50 * JCH_PIXEL_MIX_AMOUNT_MAX_VAL) ) );
			hbrushEditTxtBg = ::CreateSolidBrush( clrEditTxtBg );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_PLAY_1_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_PLAY ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_PLAY_2_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_PLAY ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_PLAY_3_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_PLAY ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );


			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_STOP_1_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_STOP ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_STOP_2_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_STOP ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_STOP_3_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_MEDIA_STOP ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );


			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LAUNCH_1_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_ROCKET ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LAUNCH_2_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_ROCKET ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LAUNCH_3_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_ROCKET ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );


			::SendMessage( ::GetDlgItem( hwndDlg, IDC_ADV_OPTIONS_BT ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_ATOM ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDOK ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_ACCEPT ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );

			::SendMessage( ::GetDlgItem( hwndDlg, IDCANCEL ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_CANCEL ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );


			::SendMessage( hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_SETTINGS ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_1_ED ), EM_SETLIMITTEXT, (_countof( TT_szTimerLabel1 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_2_ED ), EM_SETLIMITTEXT, (_countof( TT_szTimerLabel2 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_3_ED ), EM_SETLIMITTEXT, (_countof( TT_szTimerLabel3 ) - EOS_CHAR_COUNT), 0 );

			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_1_ED ), TT_szTimerLabel1 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_2_ED ), TT_szTimerLabel2 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_3_ED ), TT_szTimerLabel3 );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_1_ED ), EM_SETSEL, 0, 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_2_ED ), EM_SETSEL, 0, 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_3_ED ), EM_SETSEL, 0, 0 );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_1_ED ), EM_SETLIMITTEXT, (_countof( TT_szExtSndLabel1 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_2_ED ), EM_SETLIMITTEXT, (_countof( TT_szExtSndLabel2 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_3_ED ), EM_SETLIMITTEXT, (_countof( TT_szExtSndLabel3 ) - EOS_CHAR_COUNT), 0 );

			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_1_ED ), TT_szExtSndLabel1 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_2_ED ), TT_szExtSndLabel2 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_3_ED ), TT_szExtSndLabel3 );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_1_ED ), EM_SETSEL, 0, 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_2_ED ), EM_SETSEL, 0, 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_3_ED ), EM_SETSEL, 0, 0 );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_1_ED ), EM_SETLIMITTEXT, (_countof( TT_szExtSndFileName1 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_2_ED ), EM_SETLIMITTEXT, (_countof( TT_szExtSndFileName2 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_3_ED ), EM_SETLIMITTEXT, (_countof( TT_szExtSndFileName3 ) - EOS_CHAR_COUNT), 0 );

			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_1_ED ), TT_szExtSndFileName1 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_2_ED ), TT_szExtSndFileName2 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_3_ED ), TT_szExtSndFileName3 );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_1_ED ), EM_SETSEL, (sztLength = _tcslen( TT_szExtSndFileName1 )), sztLength );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_2_ED ), EM_SETSEL, (sztLength = _tcslen( TT_szExtSndFileName2 )), sztLength );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_3_ED ), EM_SETSEL, (sztLength = _tcslen( TT_szExtSndFileName3 )), sztLength );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_1_ED ), EM_SETLIMITTEXT, (_countof( TT_szOpenFileLabel1 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_2_ED ), EM_SETLIMITTEXT, (_countof( TT_szOpenFileLabel2 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_3_ED ), EM_SETLIMITTEXT, (_countof( TT_szOpenFileLabel3 ) - EOS_CHAR_COUNT), 0 );

			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_1_ED ), TT_szOpenFileLabel1 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_2_ED ), TT_szOpenFileLabel2 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_3_ED ), TT_szOpenFileLabel3 );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_1_ED ), EM_SETSEL, 0, 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_2_ED ), EM_SETSEL, 0, 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_3_ED ), EM_SETSEL, 0, 0 );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_1_ED ), EM_SETLIMITTEXT, (_countof( TT_szOpenFileName1 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_2_ED ), EM_SETLIMITTEXT, (_countof( TT_szOpenFileName2 ) - EOS_CHAR_COUNT), 0 );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_3_ED ), EM_SETLIMITTEXT, (_countof( TT_szOpenFileName3 ) - EOS_CHAR_COUNT), 0 );

			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_1_ED ), TT_szOpenFileName1 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_2_ED ), TT_szOpenFileName2 );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_3_ED ), TT_szOpenFileName3 );

			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_1_ED ), EM_SETSEL, (sztLength = _tcslen( TT_szOpenFileName1 )), sztLength );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_2_ED ), EM_SETSEL, (sztLength = _tcslen( TT_szOpenFileName2 )), sztLength );
			::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_3_ED ), EM_SETSEL, (sztLength = _tcslen( TT_szOpenFileName3 )), sztLength );

			//------------------------------------------------
				
			::CheckDlgButton( hwndDlg, IDC_KEEP_WND_ON_TOP_CK			  , (TT_bIsKeepWndOnTop			 ? BST_CHECKED : BST_UNCHECKED) );
			::CheckDlgButton( hwndDlg, IDC_SHOW_TIMERS_IN_TITLEBAR_CK  , (TT_bIsShowInTitleBar		 ? BST_CHECKED : BST_UNCHECKED) );
			::CheckDlgButton( hwndDlg, IDC_FLASH_WINDOW_ON_TIMER_UP_CK , (TT_bIsFlashWndOnTimerUp	 ? BST_CHECKED : BST_UNCHECKED) );
			::CheckDlgButton( hwndDlg, IDC_SHOW_ALT_ICON_ON_TIMER_UP_CK, (TT_bIsUseAltIconOnTimerUp ? BST_CHECKED : BST_UNCHECKED) );
			::CheckDlgButton( hwndDlg, IDC_DISPLAY_SMART_CURSORS_CK	  , (TT_bIsDisplaySmartCursors ? BST_CHECKED : BST_UNCHECKED) );

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

			TT_CenterWindow( hwndDlg, ::GetParent( hwndDlg ) );
			::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDOK ), MAKELPARAM( TRUE, 0 ) );
			npRtnValue = (INT_PTR)FALSE;	//	Focus has been set manually.
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_COMMAND:
		{
			int	nCommandId	= LOWORD( wParam );
			int	nNotifyCode	= HIWORD( wParam );

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

			if ( nCommandId == IDOK )
			{
				if ( ::GetFocus() == ::GetDlgItem( hwndDlg, IDOK ) )	//	This condition guarantees that all edit controls have been processed.
				{
					CString	strText;

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

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_1_ED ) );
					_tcscpy_s( TT_szTimerLabel1, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_2_ED ) );
					_tcscpy_s( TT_szTimerLabel2, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_3_ED ) );
					_tcscpy_s( TT_szTimerLabel3, strText );

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

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_1_ED ) );
					_tcscpy_s( TT_szExtSndLabel1, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_2_ED ) );
					_tcscpy_s( TT_szExtSndLabel2, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_3_ED ) );
					_tcscpy_s( TT_szExtSndLabel3, strText );

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

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_1_ED ) );
					_tcscpy_s( TT_szExtSndFileName1, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_2_ED ) );
					_tcscpy_s( TT_szExtSndFileName2, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_EXT_SND_3_ED ) );
					_tcscpy_s( TT_szExtSndFileName3, strText );

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

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_1_ED ) );
					_tcscpy_s( TT_szOpenFileLabel1, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_2_ED ) );
					_tcscpy_s( TT_szOpenFileLabel2, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_3_ED ) );
					_tcscpy_s( TT_szOpenFileLabel3, strText );

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

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_1_ED ) );
					_tcscpy_s( TT_szOpenFileName1, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_2_ED ) );
					_tcscpy_s( TT_szOpenFileName2, strText );

					strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_3_ED ) );
					_tcscpy_s( TT_szOpenFileName3, strText );

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

					::EndDialog( hwndDlg, nCommandId );
				}
				else ::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDOK ), MAKELPARAM( TRUE, 0 ) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( nCommandId == IDCANCEL )
			{
				if ( TT_bIsKeepWndOnTop != bIsKeepWndOnTop_Old )
				{
					TT_bIsKeepWndOnTop = bIsKeepWndOnTop_Old;
					::CheckDlgButton( ::GetParent( hwndDlg ), IDC_KEEP_WND_ON_TOP_CK, (TT_bIsKeepWndOnTop ? BST_CHECKED : BST_UNCHECKED) );

					::SetWindowPos( ::GetParent( hwndDlg ), (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
										 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) );
					::SetWindowPos( hwndDlg, (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
										 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) );
				}

				if ( TT_bIsShowInTitleBar != bIsShowInTitleBar_Old )
				{
					TT_bIsShowInTitleBar = bIsShowInTitleBar_Old;

					TT_UpdateWindowTitle( ::GetParent( hwndDlg ), (!TT_bIsShowInTitleBar ||
						(!TT_bIsTimerStarted1 && !TT_bIsTimerStarted2 && !TT_bIsTimerStarted3)) );
				}

				TT_bIsFlashWndOnTimerUp	  = bIsFlashWndOnTimerUp_Old;
				TT_bIsUseAltIconOnTimerUp = bIsUseAltIconOnTimerUp_Old;
				TT_bIsDisplaySmartCursors = bIsDisplaySmartCursors_Old;

				::EndDialog( hwndDlg, nCommandId );
				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == EN_KILLFOCUS) && ((nCommandId == IDC_TIMER_LABEL_1_ED) ||
						 (nCommandId == IDC_TIMER_LABEL_2_ED) || (nCommandId == IDC_TIMER_LABEL_3_ED)) )
			{
				int		nEditId, nDfltStrId;
				HWND		hwndEdit;
				TCHAR		szTimerLabel[TT_TimerLabel_MaxBufCnt];
				CString	strLabel;

				if ( nCommandId == IDC_TIMER_LABEL_1_ED )
				{
					nEditId	  = IDC_TIMER_LABEL_1_ED;
					nDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_1;
				}
				else if ( nCommandId == IDC_TIMER_LABEL_2_ED )
				{
					nEditId	  = IDC_TIMER_LABEL_2_ED;
					nDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_2;
				}
				else	//	if ( nCommandId == IDC_TIMER_LABEL_3_ED )
				{
					nEditId	  = IDC_TIMER_LABEL_3_ED;
					nDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_3;
				}

				hwndEdit = ::GetDlgItem( hwndDlg, nEditId );
				strLabel	= TT_GetWindowText( hwndEdit );
				strLabel.Trim();

				if ( strLabel.IsEmpty() ) strLabel.LoadString( nDfltStrId );

				_tcscpy_s( szTimerLabel, strLabel );
				::SetWindowText( hwndEdit, szTimerLabel );
				::SendMessage( hwndEdit, EM_SETSEL, 0, 0 );
			}

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

			else if ( (nNotifyCode == EN_KILLFOCUS) && ((nCommandId == IDC_EXT_SND_LABEL_1_ED) ||
						 (nCommandId == IDC_EXT_SND_LABEL_2_ED) || (nCommandId == IDC_EXT_SND_LABEL_3_ED)) )
			{
				int		nEditId, nDfltStrId;
				HWND		hwndEdit;
				TCHAR		szExtSndLabel[TT_ExtSndLabel_MaxBufCnt];
				CString	strLabel;

				if ( nCommandId == IDC_EXT_SND_LABEL_1_ED )
				{
					nEditId	  = IDC_EXT_SND_LABEL_1_ED;
					nDfltStrId = IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_1;
				}
				else if ( nCommandId == IDC_EXT_SND_LABEL_2_ED )
				{
					nEditId	  = IDC_EXT_SND_LABEL_2_ED;
					nDfltStrId = IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_2;
				}
				else	//	if ( nCommandId == IDC_EXT_SND_LABEL_3_ED )
				{
					nEditId	  = IDC_EXT_SND_LABEL_3_ED;
					nDfltStrId = IDS_TT_REG_VAL__ExtSnd_Label__DFLT_VALUE_3;
				}

				hwndEdit = ::GetDlgItem( hwndDlg, nEditId );
				strLabel	= TT_GetWindowText( hwndEdit );
				strLabel.Trim();

				if ( strLabel.IsEmpty() ) strLabel.LoadString( nDfltStrId );

				_tcscpy_s( szExtSndLabel, strLabel );
				::SetWindowText( hwndEdit, szExtSndLabel );
				::SendMessage( hwndEdit, EM_SETSEL, 0, 0 );
			}

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

			else if ( (nNotifyCode == EN_KILLFOCUS) &&
						 ((nCommandId == IDC_EXT_SND_1_ED) || (nCommandId == IDC_EXT_SND_2_ED) || (nCommandId == IDC_EXT_SND_3_ED)) )
			{
				int		nEditId  = nCommandId;
				HWND		hwndEdit = ::GetDlgItem( hwndDlg, nEditId );
				size_t	sztLength;
				TCHAR		szExtSndFileName[TT_ExtSndFileName_MaxBufCnt];
				CString	strText, strText_Ref;

				strText = strText_Ref = TT_GetWindowText( hwndEdit );
				strText.Trim();
				_tcscpy_s( szExtSndFileName, strText );
				TT_PathAddQuoteSpaces( szExtSndFileName, FALSE );

				if ( strText_Ref != szExtSndFileName )
				{
					::SetWindowText( hwndEdit, szExtSndFileName );
					::SendMessage( hwndEdit, EM_SETSEL, (sztLength = _tcslen( szExtSndFileName )), sztLength );
				}
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && ((nCommandId == IDC_EXT_SND_PLAY_1_BT) ||
						 (nCommandId == IDC_EXT_SND_PLAY_2_BT) || (nCommandId == IDC_EXT_SND_PLAY_3_BT)) )
			{
				int		nEditId;
				TCHAR		szExtSndFileName[TT_ExtSndFileName_MaxBufCnt];
				CString	strText;

				if		  ( nCommandId == IDC_EXT_SND_PLAY_1_BT ) nEditId = IDC_EXT_SND_1_ED;
				else if ( nCommandId == IDC_EXT_SND_PLAY_2_BT ) nEditId = IDC_EXT_SND_2_ED;
				else															nEditId = IDC_EXT_SND_3_ED;

				strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, nEditId ) );
				_tcscpy_s( szExtSndFileName, strText );
				::PathUnquoteSpaces( szExtSndFileName );

				// Checking if file exists	to avoid 'PlaySound()' searching in other folders.
				if ( ::PathFileExists( szExtSndFileName ) && !::PathIsDirectory( szExtSndFileName ) )
				{
					::PlaySound( szExtSndFileName, TT_hInst, (SND_ASYNC | SND_FILENAME | SND_NODEFAULT) );
				}

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && ((nCommandId == IDC_EXT_SND_STOP_1_BT) ||
						 (nCommandId == IDC_EXT_SND_STOP_2_BT) || (nCommandId == IDC_EXT_SND_STOP_3_BT)) )
			{
				::PlaySound( 0, 0, 0 );			//	Stop any currently played sound.
				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && ((nCommandId == IDC_EXT_SND_BROWSER_1_BT) ||
						 (nCommandId == IDC_EXT_SND_BROWSER_2_BT) || (nCommandId == IDC_EXT_SND_BROWSER_3_BT)) )
			{
				bool								bStatus = FALSE;
				int								nEditId;
				unsigned int					unMinBufferLength, unCharWritten;
				size_t							sztLength;
				struct TT_AskFile_Params	askfileparam;
				OPENFILENAME					ofn;
				TCHAR								szExtSndFileName[TT_ExtSndFileName_MaxBufCnt];
				TCHAR								szWaveFileName[MAX_PATH], szWaveFileFolder[MAX_PATH];
				CString							strWaveFileName, strCurDir, strFilter, strTitle, strDefExt;

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

				::PlaySound( 0, 0, 0 );		// Just to be sure that no sound is played anymore.

				if		  ( nCommandId == IDC_EXT_SND_BROWSER_1_BT ) nEditId = IDC_EXT_SND_1_ED;
				else if ( nCommandId == IDC_EXT_SND_BROWSER_2_BT ) nEditId = IDC_EXT_SND_2_ED;
				else																nEditId = IDC_EXT_SND_3_ED;

				strWaveFileName = TT_GetWindowText( ::GetDlgItem( hwndDlg, nEditId ) );
				_tcscpy_s( szExtSndFileName, strWaveFileName );
				::PathUnquoteSpaces( szExtSndFileName );
				_tcscpy_s( szWaveFileName, ::PathFindFileName( szExtSndFileName ) );
				_tcscpy_s( szWaveFileFolder, szExtSndFileName );
				::PathRemoveFileSpec( szWaveFileFolder );

				//------------------------------------------------
					
				memset( &ofn, 0, sizeof( OPENFILENAME ) );

				strTitle.LoadString( IDS_ASKWAVEFILE_TITLE );

				strFilter.LoadString( IDS_ASKWAVEFILE_WAV_FILTER );
				strFilter += _T('\0');					// Next string please
				strFilter += _T("*")TT_EXTENSION__wav;
				strFilter += _T('\0');					// Last string

				strDefExt = TT_EXTENSION__wav;
				strDefExt = strDefExt.Right( 3 );	//	Remove the dot.

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

				ofn.lStructSize		 = sizeof( OPENFILENAME );
				ofn.hwndOwner			 = hwndDlg;
				ofn.hInstance			 = TT_hInst;
				ofn.lpstrFilter		 = strFilter;
				ofn.nFilterIndex		 = 1;
				ofn.lpstrFile			 = szWaveFileName;
				ofn.nMaxFile			 = _countof( szWaveFileName );
				ofn.lpstrInitialDir	 = szWaveFileFolder;
				ofn.lpstrTitle			 = strTitle;
				ofn.Flags				 = (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_EXPLORER |
												 OFN_ENABLESIZING | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE);
				ofn.lpstrDefExt		 = strDefExt;
				ofn.lCustData			 = (LPARAM)&askfileparam;
				ofn.lpfnHook			 = TT_AskWaveFile_HookProc;
				ofn.lpTemplateName	 = MAKEINTRESOURCE( IDD_CUSTOMLOADWAVE );

				//------------------------------------------------
				//	Since OFN_NOCHANGEDIR is not supported in Windows NT 4.0/2000/XP, we need to do the job manually.

				unMinBufferLength = ::GetCurrentDirectory( 0, 0 );
				unCharWritten = ::GetCurrentDirectory( unMinBufferLength, strCurDir.GetBuffer( (unMinBufferLength - EOS_CHAR_COUNT) ) );
				strCurDir.ReleaseBuffer();

				if ( (unCharWritten > 0) && (unCharWritten < unMinBufferLength) )
				{
					bStatus = (::GetOpenFileName( &ofn ) != 0);

					if ( !bStatus && (::CommDlgExtendedError() == FNERR_INVALIDFILENAME) )
					{
						_tcsEmpty( szWaveFileName );
						bStatus = (::GetOpenFileName( &ofn ) != 0);	// Retry it with no file name this time.
					}

					if ( !bStatus && (::CommDlgExtendedError() != TT_CDERR_USER_CANCEL) ) ::MessageBeep( MB_ICONHAND );

					::SetCurrentDirectory( strCurDir );
				}

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

				if ( bStatus )
				{
					TT_PathAddQuoteSpaces( ofn.lpstrFile, FALSE );

					if ( strWaveFileName != ofn.lpstrFile )
					{
						::SetWindowText( ::GetDlgItem( hwndDlg, nEditId ), ofn.lpstrFile );
						::SendMessage( ::GetDlgItem( hwndDlg, nEditId ), EM_SETSEL, (sztLength = _tcslen( ofn.lpstrFile )), sztLength );
					}
				}

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

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == EN_KILLFOCUS) && ((nCommandId == IDC_OPEN_FILE_LABEL_1_ED) ||
						 (nCommandId == IDC_OPEN_FILE_LABEL_2_ED) || (nCommandId == IDC_OPEN_FILE_LABEL_3_ED)) )
			{
				int		nEditId, nDfltStrId;
				HWND		hwndEdit;
				TCHAR		szOpenFileLabel[TT_OpenFileLabel_MaxBufCnt];
				CString	strLabel;

				if ( nCommandId == IDC_OPEN_FILE_LABEL_1_ED )
				{
					nEditId	  = IDC_OPEN_FILE_LABEL_1_ED;
					nDfltStrId = IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_1;
				}
				else if ( nCommandId == IDC_OPEN_FILE_LABEL_2_ED )
				{
					nEditId	  = IDC_OPEN_FILE_LABEL_2_ED;
					nDfltStrId = IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_2;
				}
				else	//	if ( nCommandId == IDC_OPEN_FILE_LABEL_3_ED )
				{
					nEditId	  = IDC_OPEN_FILE_LABEL_3_ED;
					nDfltStrId = IDS_TT_REG_VAL__OpenFile_Label__DFLT_VALUE_3;
				}

				hwndEdit = ::GetDlgItem( hwndDlg, nEditId );
				strLabel	= TT_GetWindowText( hwndEdit );
				strLabel.Trim();

				if ( strLabel.IsEmpty() ) strLabel.LoadString( nDfltStrId );

				_tcscpy_s( szOpenFileLabel, strLabel );
				::SetWindowText( hwndEdit, szOpenFileLabel );
				::SendMessage( hwndEdit, EM_SETSEL, 0, 0 );
			}

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

			else if ( (nNotifyCode == EN_KILLFOCUS) &&
						 ((nCommandId == IDC_OPEN_FILE_1_ED) || (nCommandId == IDC_OPEN_FILE_2_ED) || (nCommandId == IDC_OPEN_FILE_3_ED)) )
			{
				int		nEditId  = nCommandId;
				HWND		hwndEdit = ::GetDlgItem( hwndDlg, nEditId );
				size_t	sztLength;
				TCHAR		szOpenFileName[TT_OpenFileName_MaxBufCnt];
				CString	strText, strText_Ref;

				strText = strText_Ref = TT_GetWindowText( hwndEdit );
				strText.Trim();

				//	We enclose in quotation marks only if we are sure that we are not in a case of an application followed
				//	by some parameters.  There is no way to make a stronger analysis than checking for a space character.
				//	Ironically, if we end up with an enclosed string, that string normally does not require to be enclosed.
				if ( strText.FindOneOf( _T(" ") ) == -1 )
				{
					_tcscpy_s( szOpenFileName, strText );
					TT_PathAddQuoteSpaces( szOpenFileName, FALSE );

					if ( strText_Ref != szOpenFileName )
					{
						::SetWindowText( hwndEdit, szOpenFileName );
						::SendMessage( hwndEdit, EM_SETSEL, (sztLength = _tcslen( szOpenFileName )), sztLength );
					}
				}
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && ((nCommandId == IDC_OPEN_FILE_LAUNCH_1_BT) ||
						 (nCommandId == IDC_OPEN_FILE_LAUNCH_2_BT) || (nCommandId == IDC_OPEN_FILE_LAUNCH_3_BT)) )
			{
				int		nEditId;
				CString	strText;

				if		  ( nCommandId == IDC_OPEN_FILE_LAUNCH_1_BT ) nEditId = IDC_OPEN_FILE_1_ED;
				else if ( nCommandId == IDC_OPEN_FILE_LAUNCH_2_BT ) nEditId = IDC_OPEN_FILE_2_ED;
				else																 nEditId = IDC_OPEN_FILE_3_ED;

				strText = TT_GetWindowText( ::GetDlgItem( hwndDlg, nEditId ) );
				TT_ExecuteOpenFile( strText );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && ((nCommandId == IDC_OPEN_FILE_BROWSER_1_BT) ||
						 (nCommandId == IDC_OPEN_FILE_BROWSER_2_BT) || (nCommandId == IDC_OPEN_FILE_BROWSER_3_BT)) )
			{
				bool								bStatus = TRUE;
				int								nEditId, nCharPos;
				unsigned int					unMinBufferLength, unCharWritten;
				size_t							sztLength;
				struct TT_AskFile_Params	askfileparam;
				OPENFILENAME					ofn;
				TCHAR								szOpenFileName[MAX_PATH];
				TCHAR								szFileName[MAX_PATH], szFileFolder[MAX_PATH];
				CString							strOpenFileName, strAppFile, strParameters, strCurDir, strFilter, strTitle, strDefExt;

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

				::PlaySound( 0, 0, 0 );		// Just to be sure that no sound is played anymore.

				if		  ( nCommandId == IDC_OPEN_FILE_BROWSER_1_BT ) nEditId = IDC_OPEN_FILE_1_ED;
				else if ( nCommandId == IDC_OPEN_FILE_BROWSER_2_BT ) nEditId = IDC_OPEN_FILE_2_ED;
				else																  nEditId = IDC_OPEN_FILE_3_ED;

				strOpenFileName = TT_GetWindowText( ::GetDlgItem( hwndDlg, nEditId ) );

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

				if ( !strOpenFileName.IsEmpty() )
				{
					strAppFile = strOpenFileName;

					if ( strAppFile[0] == _T('\"') )
					{
						if ( (nCharPos = strAppFile.Find( _T('\"'), 1 )) != -1 )
						{
							strParameters = strAppFile.Mid( (nCharPos + 1) );

							if ( (strParameters.GetLength() == 0) || strParameters[0] == _T(' ') )
							{
								strParameters.Trim();
								strAppFile = strAppFile.Mid( 1, (nCharPos - 1) );
								strAppFile.Trim();		//	Just in case.
							}
							else bStatus = FALSE;		//	Syntax error.
						}
						else bStatus = FALSE;			//	Syntax error.
					}
					else
					{
						if ( (nCharPos = strAppFile.Find( _T(' '), 1 )) != -1 )
						{
							strParameters = strAppFile.Mid( (nCharPos + 1) );
							strParameters.Trim();	//	Just in case.
							strAppFile = strAppFile.Mid( 0, nCharPos );
						}
					}

					if ( bStatus )
					{
						if ( (strAppFile.GetLength() >= MAX_PATH) || ::PathIsRelative( strAppFile ) ) bStatus = FALSE;	//	Syntax error.
					}
				}
				else bStatus = FALSE;

				if ( !bStatus ) strAppFile.Empty();

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

				_tcscpy_s( szOpenFileName, strAppFile );
				_tcscpy_s( szFileName, ::PathFindFileName( szOpenFileName ) );
				_tcscpy_s( szFileFolder, szOpenFileName );
				::PathRemoveFileSpec( szFileFolder );

				//------------------------------------------------
					
				memset( &ofn, 0, sizeof( OPENFILENAME ) );

				strTitle.LoadString( IDS_ASKOPENFILE_TITLE );

				strFilter.LoadString( IDS_ASKOPENFILE_ALL_FILTER );
				strFilter += _T('\0');					// Next string please
				strFilter += _T("*.*");
				strFilter += _T('\0');					// Last string

				strDefExt = TT_EXTENSION__exe;
				strDefExt = strDefExt.Right( 3 );	//	Remove the dot.

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

				ofn.lStructSize		 = sizeof( OPENFILENAME );
				ofn.hwndOwner			 = hwndDlg;
				ofn.hInstance			 = TT_hInst;
				ofn.lpstrFilter		 = strFilter;
				ofn.nFilterIndex		 = 1;
				ofn.lpstrFile			 = szFileName;
				ofn.nMaxFile			 = _countof( szFileName );
				ofn.lpstrInitialDir	 = szFileFolder;
				ofn.lpstrTitle			 = strTitle;
				ofn.Flags				 = (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_EXPLORER |
												 OFN_ENABLESIZING | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE);
				ofn.lpstrDefExt		 = strDefExt;
				ofn.lCustData			 = (LPARAM)&askfileparam;
				ofn.lpfnHook			 = TT_AskOpenFile_HookProc;
				ofn.lpTemplateName	 = MAKEINTRESOURCE( IDD_CUSTOMOPENFILE );

				//------------------------------------------------
				//	Since OFN_NOCHANGEDIR is not supported in Windows NT 4.0/2000/XP, we need to do the job manually.

				unMinBufferLength = ::GetCurrentDirectory( 0, 0 );
				unCharWritten = ::GetCurrentDirectory( unMinBufferLength, strCurDir.GetBuffer( (unMinBufferLength - EOS_CHAR_COUNT) ) );
				strCurDir.ReleaseBuffer();

				if ( (unCharWritten > 0) && (unCharWritten < unMinBufferLength) )
				{
					bStatus = (::GetOpenFileName( &ofn ) != 0);

					if ( !bStatus && (::CommDlgExtendedError() == FNERR_INVALIDFILENAME) )
					{
						_tcsEmpty( szFileName );
						bStatus = (::GetOpenFileName( &ofn ) != 0);	// Retry it with no file name this time.
					}

					if ( !bStatus && (::CommDlgExtendedError() != TT_CDERR_USER_CANCEL) ) ::MessageBeep( MB_ICONHAND );

					::SetCurrentDirectory( strCurDir );
				}

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

				if ( bStatus )
				{
					TT_PathAddQuoteSpaces( ofn.lpstrFile, FALSE );

					if ( strOpenFileName != ofn.lpstrFile )
					{
						::SetWindowText( ::GetDlgItem( hwndDlg, nEditId ), ofn.lpstrFile );
						::SendMessage( ::GetDlgItem( hwndDlg, nEditId ), EM_SETSEL, (sztLength = _tcslen( ofn.lpstrFile )), sztLength );
					}
				}

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

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_KEEP_WND_ON_TOP_CK) )
			{
				TT_bIsKeepWndOnTop = (::IsDlgButtonChecked( hwndDlg, IDC_KEEP_WND_ON_TOP_CK ) == BST_CHECKED);
				::CheckDlgButton( ::GetParent( hwndDlg ), IDC_KEEP_WND_ON_TOP_CK, (TT_bIsKeepWndOnTop ? BST_CHECKED : BST_UNCHECKED) );

				::SetWindowPos( ::GetParent( hwndDlg ), (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
									 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) );
				::SetWindowPos( hwndDlg, (TT_bIsKeepWndOnTop ? HWND_TOPMOST : HWND_NOTOPMOST),
									 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE) );

				::PlaySound( MAKEINTRESOURCE( (TT_bIsKeepWndOnTop ? IDR_CHECKBOX_CHECKED_WAVE :
								 IDR_CHECKBOX_UNCHECKED_WAVE) ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_SHOW_TIMERS_IN_TITLEBAR_CK) )
			{
				TT_bIsShowInTitleBar = (::IsDlgButtonChecked( hwndDlg, IDC_SHOW_TIMERS_IN_TITLEBAR_CK ) == BST_CHECKED);
				
				TT_UpdateWindowTitle( ::GetParent( hwndDlg ), (!TT_bIsShowInTitleBar ||
					(!TT_bIsTimerStarted1 && !TT_bIsTimerStarted2 && !TT_bIsTimerStarted3)) );

				::PlaySound( MAKEINTRESOURCE( (TT_bIsShowInTitleBar ? IDR_CHECKBOX_CHECKED_WAVE :
								 IDR_CHECKBOX_UNCHECKED_WAVE) ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_FLASH_WINDOW_ON_TIMER_UP_CK) )
			{
				TT_bIsFlashWndOnTimerUp = (::IsDlgButtonChecked( hwndDlg, IDC_FLASH_WINDOW_ON_TIMER_UP_CK ) == BST_CHECKED);

				::PlaySound( MAKEINTRESOURCE( (TT_bIsFlashWndOnTimerUp ? IDR_CHECKBOX_CHECKED_WAVE :
								 IDR_CHECKBOX_UNCHECKED_WAVE) ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_SHOW_ALT_ICON_ON_TIMER_UP_CK) )
			{
				TT_bIsUseAltIconOnTimerUp = (::IsDlgButtonChecked( hwndDlg, IDC_SHOW_ALT_ICON_ON_TIMER_UP_CK ) == BST_CHECKED);

				::PlaySound( MAKEINTRESOURCE( (TT_bIsUseAltIconOnTimerUp ? IDR_CHECKBOX_CHECKED_WAVE :
								 IDR_CHECKBOX_UNCHECKED_WAVE) ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_DISPLAY_SMART_CURSORS_CK) )
			{
				TT_bIsDisplaySmartCursors = (::IsDlgButtonChecked( hwndDlg, IDC_DISPLAY_SMART_CURSORS_CK ) == BST_CHECKED);

				::PlaySound( MAKEINTRESOURCE( (TT_bIsDisplaySmartCursors ? IDR_CHECKBOX_CHECKED_WAVE :
								 IDR_CHECKBOX_UNCHECKED_WAVE) ), TT_hInst, (SND_ASYNC | SND_RESOURCE | SND_NODEFAULT) );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			else if ( (nNotifyCode == BN_CLICKED) && (nCommandId == IDC_ADV_OPTIONS_BT) )
			{
				//	This condition guarantees that all edit controls have been processed.
				if ( ::GetFocus() != ::GetDlgItem( hwndDlg, IDC_ADV_OPTIONS_BT ) )
					::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDC_ADV_OPTIONS_BT ), MAKELPARAM( TRUE, 0 ) );

				TT_ProcessPopupMenu_AdvOptions( hwndDlg );

				npRtnValue = (INT_PTR)TRUE;
			}

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

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_DESTROY:
		{
			HICON		hiconTmp;

			if ( hbrushEditTxtBg != 0 )
			{
				::DeleteObject( hbrushEditTxtBg );
				hbrushEditTxtBg = 0;
			}

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_PLAY_1_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_PLAY_2_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_PLAY_3_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_STOP_1_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_STOP_2_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_EXT_SND_STOP_3_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LAUNCH_1_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LAUNCH_2_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LAUNCH_3_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDC_ADV_OPTIONS_BT ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDOK ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDCANCEL ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( hwndDlg, WM_GETICON, ICON_SMALL, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			::PlaySound( 0, 0, 0 );		// Just to be sure that no sound is played anymore.

			npRtnValue = (INT_PTR)TRUE;
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_CTLCOLOREDIT:
		{
			HDC	hdcCtl  = (HDC)wParam;
			HWND	hwndCtl = (HWND)lParam;

			if ( (hwndCtl == ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_1_ED )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_2_ED )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_TIMER_LABEL_3_ED )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_1_ED   )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_2_ED   )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_EXT_SND_LABEL_3_ED   )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_1_ED )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_2_ED )) ||
				  (hwndCtl == ::GetDlgItem( hwndDlg, IDC_OPEN_FILE_LABEL_3_ED )) )
			{
				::SetTextColor( hdcCtl, ::GetSysColor( COLOR_WINDOWTEXT ) );
//				::SetBkColor( hdcCtl, ::GetSysColor( COLOR_3DFACE ) );
				::SetBkColor( hdcCtl, clrEditTxtBg );
				::SetBkMode( hdcCtl, OPAQUE );
//				npRtnValue = (INT_PTR)GetSysColorBrush( COLOR_3DFACE );
				npRtnValue = (INT_PTR)hbrushEditTxtBg;
			}
			else npRtnValue = 0;

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hwndDlg, WM_CTLCOLOREDIT, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	}

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

	return( npRtnValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-03-16©  Modified: 2016-08-08©	//
//																																	//
//	Purpose:	Message handler for the 'IDD_ABOUT' dialog box.														//
//																																	//
//	Result:																														//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

INT_PTR CALLBACK DlgAboutProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	INT_PTR	npRtnValue = FALSE;	// Set to "message not processed" by default.

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

	switch( uMsg )
	{

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_INITDIALOG:
		{
			TCHAR		szFileVersion[TT_MINSTRBUF__VERSION];
			CString	strText;

			TT_SHCreateVersionNumber( szFileVersion, TT_un64AppFileVersion );
			strText.Format( IDS_FMT_ABOUT_VERSION, szFileVersion );
			::SetWindowText( ::GetDlgItem( hwndDlg, IDC_NAME_AND_VERSION_TX ), (LPCTSTR)strText );

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

			::SendMessage( ::GetDlgItem( hwndDlg, IDOK ), BM_SETIMAGE, IMAGE_ICON, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_CLOSE ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR ) );

			::SendMessage( hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)::LoadImage( TT_hInst,
								MAKEINTRESOURCE( IDI_ABOUT ), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ) );

			TT_CenterWindow( hwndDlg, ::GetParent( hwndDlg ) );
			::SendMessage( hwndDlg, WM_NEXTDLGCTL, (WPARAM)::GetDlgItem( hwndDlg, IDOK ), MAKELPARAM( TRUE, 0 ) );
			npRtnValue = (INT_PTR)FALSE;	//	Focus has been set manually.
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_COMMAND:
		{
			int	nCommandId	= LOWORD( wParam );
			int	nNotifyCode	= HIWORD( wParam );

			if ( (nCommandId == IDOK) || (nCommandId == IDCANCEL) )
			{
				::EndDialog( hwndDlg, nCommandId );
				npRtnValue = (INT_PTR)TRUE;
			}
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_DESTROY:
		{
			HICON		hiconTmp;

			if ( (hiconTmp = (HICON)::SendMessage( ::GetDlgItem( hwndDlg, IDOK ), BM_GETIMAGE, IMAGE_ICON, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			if ( (hiconTmp = (HICON)::SendMessage( hwndDlg, WM_GETICON, ICON_SMALL, 0 )) != 0 )
				::DestroyIcon( hiconTmp );

			npRtnValue = (INT_PTR)TRUE;
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_NOTIFY:
		{
			LRESULT	npResult = 0;
			LPNMHDR	pNMHdr	= (LPNMHDR)lParam;

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

			if ( ((pNMHdr->code == NM_RETURN) || (pNMHdr->code == NM_CLICK)) && 
				  (((pNMHdr->hwndFrom == ::GetDlgItem( hwndDlg, IDC_WEBSITE_SL1 )) && (pNMHdr->idFrom == IDC_WEBSITE_SL1)) ||
				   ((pNMHdr->hwndFrom == ::GetDlgItem( hwndDlg, IDC_WEBSITE_SL2 )) && (pNMHdr->idFrom == IDC_WEBSITE_SL2)) ||
				   ((pNMHdr->hwndFrom == ::GetDlgItem( hwndDlg, IDC_WEBSITE_SL3 )) && (pNMHdr->idFrom == IDC_WEBSITE_SL3))) )
			{
				PNMLINK	pNMLink = (PNMLINK)pNMHdr;
				char		szUrl[L_MAX_URL_LENGTH];

				if ( WideCharToMultiByte( CP_ACP, 0, pNMLink->item.szUrl, -1, szUrl, _countof( szUrl ), 0, 0 ) != 0 )
					TT_BrowseWebpageLink( szUrl, hwndDlg );

				npRtnValue = SetDlgMsgResult( hwndDlg, WM_NOTIFY, npResult );
			}

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	}

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

	return( npRtnValue );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-06-27©  Modified: 2016-06-28©	//
//																																	//
//	Purpose:	Register our unique class name that we wish to use.												//
//																																	//
//	Note: Internal function called by 'TT_AskModifyTimerLabel()'.												//
//																																	//
//	Result: Returns FALSE only if an error occurred.																//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_RegisterClass_ThreeTimers_ModifyTimerLabelTinyWnd( HINSTANCE hInstance )
{
	static bool	bIsClassRegistered = FALSE;

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

	if ( !bIsClassRegistered )
	{
		bool			bStatus;
		WNDCLASSEX	wcex;

		memset( &wcex, 0, sizeof( WNDCLASSEX ) );

		wcex.cbSize			 = sizeof( WNDCLASSEX ); 	
		wcex.style			 = (CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE);
		wcex.lpfnWndProc   = TT_ModifyTimerLabelTinyWndProc;
		wcex.hInstance	    = hInstance;
		wcex.lpszClassName = TT_cpcszUniqueClassName_ThreeTimers_ModifyTimerLabelTinyWnd;

		bStatus = (::RegisterClassEx( &wcex ) != 0);
		bIsClassRegistered = bStatus;
	}

	return( bIsClassRegistered );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-06-27©  Modified: 2016-06-28©	//
//																																	//
//	Purpose:																														//
//																																	//
//	'cunMsgUsedToUpdate': Possible values are 'TT_WM_USER__TimerLabelChanged1',							//
//								 'TT_WM_USER__TimerLabelChanged2' 'TT_WM_USER__TimerLabelChanged3'.			//
//																																	//
//	Result: Returns FALSE only if an error occurred.																//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool TT_AskModifyTimerLabel( HWND hwndDlg, const unsigned int cunMsgUsedToUpdate )
{
	bool		bStatus = FALSE;
	HWND		hWndTmp, hwndGroup, hwndBtn;
	CRect		rectGroup, rectBtn, rectFloatingEdit;

	struct TT_ModifyTimerLabelTinyWnd  *pMTLTW = NULL;

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

	if ( TT_RegisterClass_ThreeTimers_ModifyTimerLabelTinyWnd( TT_hInst ) )
	{
		if ( (pMTLTW = new struct TT_ModifyTimerLabelTinyWnd) != NULL )
		{
			pMTLTW->m_hwndDialogBox = hwndDlg;

			if ( cunMsgUsedToUpdate == TT_WM_USER__TimerLabelChanged1 )
			{
				pMTLTW->m_nTimerGroupId			 = IDC_TIMER_1_GR;
				pMTLTW->m_nTimerStartStopBtnId = IDC_START_STOP_1_BT;
				pMTLTW->m_nTimerValueEditId	 = IDC_TIMER_VALUE_1_ED;
				pMTLTW->m_nTimerLabelDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_1;
				pMTLTW->m_pszTimerLabel			 = &TT_szTimerLabel1;
				pMTLTW->m_unMsgUsedToUpdate	 = TT_WM_USER__TimerLabelChanged1;
			}
			else if ( cunMsgUsedToUpdate == TT_WM_USER__TimerLabelChanged2 )
			{
				pMTLTW->m_nTimerGroupId			 = IDC_TIMER_2_GR;
				pMTLTW->m_nTimerStartStopBtnId = IDC_START_STOP_2_BT;
				pMTLTW->m_nTimerValueEditId	 = IDC_TIMER_VALUE_2_ED;
				pMTLTW->m_nTimerLabelDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_2;
				pMTLTW->m_pszTimerLabel			 = &TT_szTimerLabel2;
				pMTLTW->m_unMsgUsedToUpdate	 = TT_WM_USER__TimerLabelChanged2;
			}
			else	//	if ( cunMsgUsedToUpdate == TT_WM_USER__TimerLabelChanged3 )
			{
				pMTLTW->m_nTimerGroupId			 = IDC_TIMER_3_GR;
				pMTLTW->m_nTimerStartStopBtnId = IDC_START_STOP_3_BT;
				pMTLTW->m_nTimerValueEditId	 = IDC_TIMER_VALUE_3_ED;
				pMTLTW->m_nTimerLabelDfltStrId = IDS_TT_REG_VAL__Timer_Label__DFLT_VALUE_3;
				pMTLTW->m_pszTimerLabel			 = &TT_szTimerLabel3;
				pMTLTW->m_unMsgUsedToUpdate	 = TT_WM_USER__TimerLabelChanged3;
			}

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

			hwndGroup = ::GetDlgItem( hwndDlg, pMTLTW->m_nTimerGroupId );
			hwndBtn	 = ::GetDlgItem( hwndDlg, pMTLTW->m_nTimerStartStopBtnId );

			::GetWindowRect( hwndGroup, &rectGroup );
			::ScreenToClient( hwndDlg,  (LPPOINT)&rectGroup		  );
			::ScreenToClient( hwndDlg, ((LPPOINT)&rectGroup) + 1 );

			::GetWindowRect( hwndBtn, &rectBtn );
			::ScreenToClient( hwndDlg,  (LPPOINT)&rectBtn		);
			::ScreenToClient( hwndDlg, ((LPPOINT)&rectBtn) + 1 );

			rectFloatingEdit.left	= rectBtn.left;
			rectFloatingEdit.top		= rectGroup.top;
			rectFloatingEdit.right	= (rectGroup.right - (rectBtn.left - rectGroup.left));
			rectFloatingEdit.bottom = (rectBtn.top - 1);		//	That leaves a 1 pixel free space.
			rectFloatingEdit.NormalizeRect();

			::ClientToScreen( hwndDlg,  (LPPOINT)&rectFloatingEdit		);
			::ClientToScreen( hwndDlg, ((LPPOINT)&rectFloatingEdit) + 1 );

			//	The parent must be the dialog box in order for it to receive the 'TT_WM_USER__TimerLabelChanged#' message.
			bStatus = ((hWndTmp = ::CreateWindowEx( 0, TT_cpcszUniqueClassName_ThreeTimers_ModifyTimerLabelTinyWnd, _T(""),
							WS_POPUP, rectFloatingEdit.left, rectFloatingEdit.top, rectFloatingEdit.Width(),
							rectFloatingEdit.Height(), hwndDlg, 0, TT_hInst, pMTLTW )) != 0);

			hWndTmp = 0;		//	The created 'hWndTmp' will destroy itself when it will lost the focus.
			pMTLTW  = NULL;	//	The created 'hWndTmp' will delete 'pMTLTW' when it will lost the focus.  The only possible leak of
		}							//	 memory is if the 'WM_NCCREATE' message is never processed, and that is not supposed to happen.
	}

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

	return( bStatus );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-06-27©  Modified: 2016-06-28©	//
//																																	//
//	Purpose: Used by 'TT_AskModifyTimerLabel()'.																		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

LRESULT CALLBACK TT_ModifyTimerLabelTinyWndProc_HookProc_EditCtrl( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	if ( (uMsg == WM_KEYDOWN) || (uMsg == WM_SYSKEYDOWN) )
	{
		if ( (wParam == VK_RETURN) || (wParam == VK_ESCAPE) )
		{
			if		  ( wParam == VK_RETURN ) ::SendMessage( ::GetParent( hWnd ), TT_WM_USER__USER_HAS_PRESSED_THE_ENTER_KEY, 0, 0 );
			else if ( wParam == VK_ESCAPE ) ::SendMessage( ::GetParent( hWnd ), TT_WM_USER__RESTORE_INITIAL_TIMER_LABEL	  , 0, 0 );

			::SetFocus( GetParent( hWnd ) );	//	That will send to the parent a 'WM_COMMAND' with 'TT_IDC_MTLTW_TIMER_LABEL_ED' + 'EN_KILLFOCUS'.
			return( 0 );
		}
	}
	return( ::CallWindowProc( (WNDPROC)::GetWindowLongPtr( hWnd, GWLP_USERDATA ), hWnd, uMsg, wParam, lParam ) );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
//																																	//
//	Coded by www.decotechpro.com, all rights reserved.  Created: 2016-06-27©  Modified: 2016-06-28©	//
//																																	//
//	Purpose: Used by 'TT_AskModifyTimerLabel()'.																		//
//																																	//
/////////////////////////////////////////////////////////////////////////////////////////////////////

LRESULT CALLBACK TT_ModifyTimerLabelTinyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	struct TT_ModifyTimerLabelTinyWnd  *pMTLTW = (struct TT_ModifyTimerLabelTinyWnd *)::GetWindowLongPtr( hWnd, GWLP_USERDATA );

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

	if ( pMTLTW == NULL )
	{
		if ( uMsg == WM_NCCREATE )
		{
			LPCREATESTRUCT	pCS	 = (LPCREATESTRUCT)lParam;
			bool				bError = FALSE;

			if ( (pMTLTW = (struct TT_ModifyTimerLabelTinyWnd *)pCS->lpCreateParams) != NULL )
			{
				::SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)pMTLTW );
				pMTLTW->m_hwndEditControl	  = 0;
				pMTLTW->m_hfontEditControl	  = 0;
				pMTLTW->m_bIsEnterKeyPressed = FALSE;
			}
			else bError = TRUE;

			if ( bError ) return( FALSE );
		}

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

		else	// Process messages received before WM_NCCREATE (Normally only WM_GETMINMAXINFO),
		{		// and also process messages received after WM_NCDESTROY (Normally none).
			return( ::DefWindowProc( hWnd, uMsg, wParam, lParam ) );
		}
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////
	
	switch( uMsg )
	{
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
		
	case WM_COMMAND:
		{
			int	nCommandId	= LOWORD( wParam );
			int	nNotifyCode	= HIWORD( wParam );
		
			switch( nCommandId )
			{

//===================================================================================================

			case IDOK:
				{
					CString	strTimerLabel;

					strTimerLabel = TT_GetWindowText( pMTLTW->m_hwndEditControl );
					strTimerLabel.Trim();

					if ( strTimerLabel.IsEmpty() ) strTimerLabel.LoadString( pMTLTW->m_nTimerLabelDfltStrId );

					_tcscpy_s( *(pMTLTW->m_pszTimerLabel), TT_TimerLabel_MaxBufCnt, strTimerLabel );

					::SendMessage( pMTLTW->m_hwndDialogBox, pMTLTW->m_unMsgUsedToUpdate, 0, (LPARAM)pMTLTW );

					::DestroyWindow( hWnd );
					return( 0 );
					break;
				}

//===================================================================================================
				
			case TT_IDC_MTLTW_TIMER_LABEL_ED:
				{
					if ( nNotifyCode == EN_SETFOCUS )
					{
						::SendMessage( pMTLTW->m_hwndEditControl, EM_SETSEL, 0, -1 );
					}
					else if ( nNotifyCode == EN_KILLFOCUS )	//	The lost of focus does the same as accepting the timer label.
					{
						::SendMessage( hWnd, WM_COMMAND, MAKEWPARAM( IDOK, 0 ), 0 );
						return( 0 );
					}

					break;
				}

//===================================================================================================
				
			}

			break;
		}
		
/////////////////////////////////////////////////////////////////////////////////////////////////////
			
	case WM_CREATE:
		{
			bool	bStatus = TRUE;

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

			if ( bStatus )		//	Creates the font used by the edit control.
			{
				HDC		hdcWnd;
				LOGFONT	lfCtl;

				if ( (hdcWnd = ::GetDC( hWnd )) != 0 )
				{
					memset( &lfCtl, 0, sizeof( LOGFONT ) );
					lfCtl.lfHeight  = -MulDiv( 8, ::GetDeviceCaps( hdcWnd, LOGPIXELSY ), 72 );
					lfCtl.lfWeight  = FW_NORMAL;
					lfCtl.lfQuality = CLEARTYPE_QUALITY;
					_tcscpy_s( lfCtl.lfFaceName, TT_FONT_NAME__Segoe_UI );

					if ( (pMTLTW->m_hfontEditControl = ::CreateFontIndirect( &lfCtl )) == 0 ) bStatus = FALSE;

					::ReleaseDC( hWnd, hdcWnd );
					hdcWnd = 0;
				}
				else bStatus = FALSE;
			}

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

			if ( bStatus )		//	Creates the edit control.
			{
				bStatus = ((pMTLTW->m_hwndEditControl = ::CreateWindowEx( 0, WC_EDIT, *(pMTLTW->m_pszTimerLabel),
								(ES_AUTOHSCROLL | WS_CHILD | WS_GROUP | WS_TABSTOP | WS_VISIBLE), 0, 0, 1, 1, hWnd, 0, TT_hInst, 0 )) != 0);

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

				if ( bStatus )
				{
					::SetWindowLongPtr( pMTLTW->m_hwndEditControl, GWLP_ID, TT_IDC_MTLTW_TIMER_LABEL_ED );
					::SetWindowLongPtr( pMTLTW->m_hwndEditControl, GWLP_USERDATA, ::SetWindowLongPtr( pMTLTW->m_hwndEditControl, 
												GWLP_WNDPROC, (LONG_PTR)TT_ModifyTimerLabelTinyWndProc_HookProc_EditCtrl ) );

					::SendMessage( pMTLTW->m_hwndEditControl, WM_SETFONT, (WPARAM)pMTLTW->m_hfontEditControl, MAKELPARAM( FALSE, 0 ) );
					::SendMessage( pMTLTW->m_hwndEditControl, EM_SETLIMITTEXT, (TT_TimerLabel_MaxBufCnt - EOS_CHAR_COUNT), 0 );

				}
			}

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

			if ( bStatus )		//	Adjusts the size and position of the edit control and its parent window.
			{
				HFONT			hfontEditCtl, hfontOld;
				HDC			hdcEditCtl;
				TEXTMETRIC	tmEditCtl;
				CRect			rectWindow, rectEditCtrl;

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

				::GetWindowRect( hWnd, &rectWindow );

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

				if ( ((hfontEditCtl = (HFONT)::SendMessage( pMTLTW->m_hwndEditControl, WM_GETFONT, 0, 0 )) != 0) &&
					  ((hdcEditCtl = ::GetWindowDC( pMTLTW->m_hwndEditControl )) != 0) )
				{
					hfontOld = (HFONT)::SelectObject( hdcEditCtl, hfontEditCtl );	//	Save old font and set new font.

					if ( ::GetTextMetrics( hdcEditCtl, &tmEditCtl ) ) rectWindow.bottom = (rectWindow.top + tmEditCtl.tmHeight);
					else															  bStatus = FALSE;

					::SelectObject( hdcEditCtl, hfontOld );	//	Restore old font.
					::ReleaseDC( pMTLTW->m_hwndEditControl, hdcEditCtl );
				}
				else bStatus = FALSE;

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

				if ( bStatus )
				{
					::SendMessage( pMTLTW->m_hwndEditControl, EM_SETMARGINS, (EC_LEFTMARGIN | EC_RIGHTMARGIN),
										MAKELPARAM( (tmEditCtl.tmAveCharWidth / 2), (tmEditCtl.tmAveCharWidth / 2) ) );

					rectEditCtrl = rectWindow;
					rectWindow.InflateRect( 2, 2 );

					::SetWindowPos( hWnd, HWND_TOPMOST, rectWindow.left, rectWindow.top, rectWindow.Width(),
										 rectWindow.Height(), (SWP_NOACTIVATE | SWP_NOOWNERZORDER) );

					::SetWindowPos( pMTLTW->m_hwndEditControl, 0, 2, 2, rectEditCtrl.Width(), rectEditCtrl.Height(),
										 (SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER) );
				}
			}

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

			if ( bStatus )
			{
				//	We clear the text in the 'pMTLTW->m_nTimerGroupId' group control to be sure it can only be seen in the edit
				//	control.  The text will be restored during the processing of any 'TT_WM_USER__TimerLabelChanged#' messages.
				::SetWindowText( ::GetDlgItem( pMTLTW->m_hwndDialogBox, pMTLTW->m_nTimerGroupId ), _T("") );
				::ShowWindow( hWnd, SW_SHOW );
				::SetFocus( pMTLTW->m_hwndEditControl );
			}

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

			return( (bStatus ? 0 : -1) );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//	Just as a reminder, we are not in a dialog box here even if the code looks like that.

	case WM_CTLCOLOREDIT:
		{
			HDC 		hdcCtl	  = (HDC)wParam;
			HWND		hwndCtl	  = (HWND)lParam;
			INT_PTR	npRtnValue = 0;	

			if ( hwndCtl == pMTLTW->m_hwndEditControl )
			{
				::SetTextColor( hdcCtl, ::GetSysColor( COLOR_WINDOWTEXT ) );
				::SetBkColor( hdcCtl, ::GetSysColor( COLOR_WINDOW ) );
				::SetBkMode( hdcCtl, OPAQUE );
				npRtnValue = (INT_PTR)GetSysColorBrush( COLOR_WINDOW );
			}

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

			if ( npRtnValue != 0 ) return( SetDlgMsgResult( hWnd, WM_CTLCOLOREDIT, npRtnValue ) );
			else						  return( FALSE );	//	Required because SetDlgMsgResult() always returns TRUE here.

			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
			
	case WM_NCDESTROY:
		{
			if ( pMTLTW->m_hfontEditControl != 0 )
			{
				::DeleteObject( pMTLTW->m_hfontEditControl );
				pMTLTW->m_hfontEditControl = 0;
			}

			::SetWindowLongPtr( hWnd, GWLP_USERDATA, 0 );
			delete pMTLTW;
			pMTLTW = NULL;

			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	case WM_PAINT:
		{
			PAINTSTRUCT	psTmp;
			HDC			hdcTmp = ::BeginPaint( hWnd, &psTmp );
			HPEN			hpenNew, hpenOld;
			CRect			rectClient;

			::GetClientRect( hWnd, &rectClient );

			if ( (hpenNew = ::CreatePen( PS_SOLID, 1, ::GetSysColor( COLOR_WINDOWTEXT ) )) != 0 )
			{
				hpenOld = (HPEN)::SelectObject( hdcTmp, hpenNew );

				::MoveToEx( hdcTmp, (rectClient.left 	  ), (rectClient.top			), 0 );
				::LineTo( hdcTmp	, (rectClient.right - 1), (rectClient.top			) );
				::LineTo( hdcTmp	, (rectClient.right - 1), (rectClient.bottom - 1) );
				::LineTo( hdcTmp	, (rectClient.left	  ), (rectClient.bottom - 1) );
				::LineTo( hdcTmp	, (rectClient.left	  ), (rectClient.top			) );

				::SelectObject( hdcTmp, hpenOld );
				::DeleteObject( hpenNew );
			}

			rectClient.DeflateRect( 1, 1 );
			::FillRect( hdcTmp, rectClient, ::GetSysColorBrush( COLOR_3DFACE ) );

			::EndPaint( hWnd, &psTmp );
			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
			
	case TT_WM_USER__USER_HAS_PRESSED_THE_ENTER_KEY:
		{
			pMTLTW->m_bIsEnterKeyPressed = TRUE;
			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////
			
	case TT_WM_USER__RESTORE_INITIAL_TIMER_LABEL:
		{
			::SetWindowText( pMTLTW->m_hwndEditControl, *(pMTLTW->m_pszTimerLabel) );
			return( 0 );
			break;
		}

/////////////////////////////////////////////////////////////////////////////////////////////////////

	}

	return( ::DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
