//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=-
//
//   Demonstration code to show how to make a window using Windows(tm) and VC++
//   Created 12-SEP-2008               Richard B. Johnson
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=-

#include "EasyWindows.h"

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=-
//
//  I am not using constructors/destructors. Just let the compiler initialize these as
//  in the regular C language.
//
EASY        EASY::Easy;
const char  EASY::CopyRight[]   = "Copyright \xa9 2008 Richard B. Johnson";
const char  EASY::appName[]     = "EasyWindow";
const char  EASY::Static[]      = "Static";
const char  EASY::Okay[]        = "Okay";
const char  EASY::Button[]      = "Button";
const char  EASY::AboutClass[]  = "About:)";
const char  EASY::Info[]        = "Information";
const char  EASY::Error[]       = "Error";
const char  EASY::Clicked[]     = "Clicked on";
const char  EASY::LoDigit[]     = "low digit";
const char  EASY::HiDigit[]     = "high digit";
const int   EASY::Times[]       = {
        12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
        12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
const long  EASY::Digits[]= {
    IDB_BITMAP4,    IDB_BITMAP5,    IDB_BITMAP6,    IDB_BITMAP7,    IDB_BITMAP8,
    IDB_BITMAP9,    IDB_BITMAP10,   IDB_BITMAP11,   IDB_BITMAP12,   IDB_BITMAP13};
const long  EASY::DigitsA[]= {
    IDB_BITMAP15,   IDB_BITMAP16,   IDB_BITMAP17,   IDB_BITMAP18,   IDB_BITMAP19,
    IDB_BITMAP20,   IDB_BITMAP21,   IDB_BITMAP22,   IDB_BITMAP23,   IDB_BITMAP24};
const long  EASY::DigitsP[]= {
    IDB_BITMAP25,   IDB_BITMAP26,   IDB_BITMAP27,   IDB_BITMAP28,   IDB_BITMAP29,
    IDB_BITMAP30,   IDB_BITMAP31,   IDB_BITMAP32,   IDB_BITMAP33,   IDB_BITMAP34};
const long  EASY::DigitsM[]= {
    IDB_BITMAP35,   IDB_BITMAP36,   IDB_BITMAP37,   IDB_BITMAP38,   IDB_BITMAP39,
    IDB_BITMAP40,   IDB_BITMAP41,   IDB_BITMAP42,   IDB_BITMAP43,   IDB_BITMAP44};

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=-
//
//  Using the special Windows entry point. Windows doesn't use main() like the rest of the universe.
//  It needs to be global and I want to encapsulate everything in a class, so I make it global
//  and have it call the class code.
//
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    return EASY::ClassMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=-
//
//  This is the real entry point. A smart compiler will get rid of the previous code and call
//  this directly as the entry point.
//
int EASY::ClassMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    UNREFERENCED(lpCmdLine);
    UNREFERENCED(hPrevInstance);

	Easy.Exepath= new char [MAX_PATH];
    (void)GetModuleFileName(0, Easy.Exepath, MAX_PATH);
	*LastChar(Easy.Exepath, '\\') = (char) 0x00;

//
//  Create a title for the title-bar on the window.
//
    Easy.Heading = new char [0x100];
    sprintf(Easy.Heading, "Easy Windows V%d.%d   %s   Library version %d.%d     %s",
        VERS_MAJOR, VERS_MINOR, __DATE__, LOWORD(_MSC_VER), HIWORD(_MSC_VER), CopyRight);
//
//   Step 1: Register the main window class
//
    memset(&Easy.wc, 0x00, sizeof(Easy.wc));
    Easy.wc.style           = CS_HREDRAW | CS_VREDRAW;
    Easy.wc.lpfnWndProc     = Easy.WndProc;
    Easy.wc.hInstance       = hInstance;
    Easy.wc.hIcon           = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    Easy.wc.lpszMenuName    = MAKEINTRESOURCE(IDB_BITMAP1);
    Easy.wc.lpszMenuName    = MAKEINTRESOURCE(IDR_MENU1);
    Easy.wc.lpszClassName   = Easy.appName;
    Easy.wc.hbrBackground   = (HBRUSH)GetStockObject(GRAY_BRUSH);
    Easy.wc.hCursor         = LoadCursor(NULL, IDC_ARROW);

    if(!RegisterClass(&Easy.wc))
    {
          MessageBox(NULL, "Window Registration Failed!", Easy.Error,
               MB_ICONERROR | MB_OK);
          delete[] Easy.Heading;
		  delete[] Easy.Exepath;
          return FAILURE;
     }
//
//  Step 2: Register the "about" window class
//
    Easy.wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
    Easy.wc.lpszMenuName  = NULL;
    Easy.wc.lpszClassName = AboutClass;
    Easy.wc.lpfnWndProc   = (WNDPROC) Easy.AboutWindowProc;
    (void)RegisterClass(&Easy.wc);
//
//   Step 3: Create the background window and the "About" window
//
    Easy.mainwin = CreateWindow(Easy.appName, Easy.Heading, WS_OVERLAPPEDWINDOW,
          X_START, Y_START, WIN_WIDTH, WIN_HEIGHT, NULL, NULL, hInstance, NULL);
    Easy.aboutwin = CreateWindow(Easy.AboutClass,"About Easy Windows", WS_OVERLAPPED | WS_SYSMENU |WS_MINIMIZEBOX,
        ABOUT_X_START, ABOUT_Y_START, ABOUT_WINDOW_WIDTH, ABOUT_WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

    (void)ShowWindow(Easy.mainwin, nCmdShow);
    (void)UpdateWindow(Easy.mainwin);
//
//   Step 4: The Message Loop
//
    while(GetMessage(&Easy.Msg, NULL, 0, 0) > 0)
    {
          TranslateMessage(&Easy.Msg);
          DispatchMessage(&Easy.Msg);
          UpdateRand();
    }
    delete[] Easy.Heading;
	delete[] Easy.Exepath;
    return int(Easy.Msg.wParam);
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=-
//
//   Step 5: The window procedure, executed as a thread. Note that this is "spinning," executed thousands
//   of times per second! You can't write debugging information to a message box because it will be
//   overloaded!
//
LRESULT CALLBACK EASY::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT Ret = SUCCESS;
    UpdateRand();

    switch(msg)
    {
    case WM_CREATE:
//
//      Create the child windows. A Windows ** BUG ** makes it necessary to create these
//      windows in the reverse order of their usage or else the ID sent during a mouse-click
//      is wrong or to not have any interaction with the main window as shown here.
//      Note that simplifying macros are in the header file.
//
        Easy.mi = MAKE_WINDOW_QUIET(0, 0, 0, 0, ID_IM);
        Easy.ck = MAKE_WINDOW(CLICK4_X_START, CLICK4_Y_START, CLICK4_WIDTH,  CLICK4_HEIGHT,  ID_CK);
        Easy.hh = MAKE_WINDOW(CLK_HH_X_START, CLK_HH_Y_START, CLK_NUM_WIDTH, CLK_NUM_HEIGHT, ID_HH);
        Easy.hl = MAKE_WINDOW(CLK_HL_X_START, CLK_HL_Y_START, CLK_NUM_WIDTH, CLK_NUM_HEIGHT, ID_HL);
        Easy.mh = MAKE_WINDOW(CLK_MH_X_START, CLK_MH_Y_START, CLK_NUM_WIDTH, CLK_NUM_HEIGHT, ID_MH);
        Easy.ml = MAKE_WINDOW(CLK_ML_X_START, CLK_ML_Y_START, CLK_NUM_WIDTH, CLK_NUM_HEIGHT, ID_ML);
        Easy.sh = MAKE_WINDOW(CLK_SH_X_START, CLK_SH_Y_START, CLK_NUM_WIDTH, CLK_NUM_HEIGHT, ID_SH);
        Easy.sl = MAKE_WINDOW(CLK_SL_X_START, CLK_SL_Y_START, CLK_NUM_WIDTH, CLK_NUM_HEIGHT, ID_SL);
        Easy.sp = MAKE_WINDOW(CLK_SP_X_START, CLK_SP_Y_START, CLK_SP_WIDTH,  CLK_SP_HEIGHT,  ID_SP);
//
//      Upload the bit-maps and start the clock. Do this in a separate thread so other things can
//      start as well.
//
        START_THREAD(NULL, 0, (LPTHREAD_START_ROUTINE) Easy.UploadAllBitmaps, NULL, (DWORD)0, Easy.ThreadId);
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_COMMAND:
        {
//
//          Child notification messages
//
            onmenu(wParam);
            switch(HIWORD(wParam))
            {
            case STN_CLICKED:
                {
                    switch(LOWORD(wParam))
                    {
                    case ID_IM:
                         DisplayMessage("%s the main window", Clicked);
                         break;
                    case ID_HH:
                         DisplayMessage("%s hours %s! (0x%08x)",   Clicked, HiDigit, wParam);
                         break;
                    case ID_HL:
                         DisplayMessage("%s hours %s! (0x%08x)",   Clicked, LoDigit, wParam);
                         break;
                    case ID_MH:
                         DisplayMessage("%s minutes %s! (0x%08x)", Clicked, HiDigit, wParam);
                         break;
                    case ID_ML:
                        DisplayMessage("%s minutes %s! (0x%08x)",  Clicked, LoDigit, wParam);
                        break;
                    case ID_SH:
                        DisplayMessage("%s seconds %s! (0x%08x)",  Clicked, HiDigit, wParam);
                        break;
                    case ID_SL:
                        DisplayMessage("%s seconds %s! (0x%08x)",  Clicked, LoDigit, wParam);
                        break;
                    case ID_SP:
                        ShowJackpot();
                        break;
                    case ID_CK:
                        ChangeClock(TRUE);      // Change 24/12 hour format
                        break;
                    default:
                    break;
                    }
                }
                break;
            case LBN_DBLCLK:
                {
                    switch(LOWORD(wParam))
                    {
                    case ID_IM:
                         break;
                    default:
                    break;
                    }
                }
                break;
            case EN_CHANGE:
                {
                    switch(LOWORD(wParam))
                    {
                    case 0:
                    default:
                    break;
                    }
                }
                break;
            }
        }
        break;
    default:
        Ret = DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return Ret;
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
// The menu commands for the about window. It is broken out because the whole word
// of wParam is used.
//
void EASY::onmenu(WPARAM wParam)
{
    switch(wParam)
    {
    case ID_FILE_EXIT:
            SendMessage(Easy.mainwin, WM_CLOSE, 0, 0);
        break;
    case ID_FILE_MSGABOUT:
            MessageBox(Easy.mi, Easy.Heading, Okay, MB_OK|MB_ICONINFORMATION);
        break;
    case ID_FILE_WINDOWABOUT:
        Align2UpperLeft(Easy.aboutwin);
        LocalSound("Chimes.wav");
        ShowWindow(Easy.aboutwin, SW_SHOW);
        break;
    }
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
// The "about" window
//
LRESULT EASY::AboutWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT Ret = SUCCESS;
 
    switch(msg)
    {
    case WM_CLOSE:
        ShowWindow(hwnd, SW_HIDE);
        LocalSound("Chimes.wav");
        break;
    case WM_CREATE:
        Easy.abouthan = MAKE_WINDOW_QUIET(ABOUT_X_START, ABOUT_Y_START, ABOUT_WIDTH, ABOUT_HEIGHT, 0);
        Easy.buttnhan = MAKE_BUTTON(ABOUT_BUT_X_START, ABOUT_BUT_Y_START, BUTTON_WIDTH, BUTTON_HEIGHT, ID_AB);
        PAINT_WINDOW(Easy.abouthan, IDB_BITMAP2);
        break;
    case WM_COMMAND:
        {
            switch(HIWORD(wParam))
            {
                case BN_CLICKED:
                {
                    switch(LOWORD(wParam))
                    {
                        case ID_AB:
                        SendMessage(hwnd,WM_CLOSE,0,0);
                        break;
                    }
                }
                break;
                case BN_DBLCLK:
                {
                    switch(LOWORD(wParam))
                    {
                    case ID_AB:
                        SendMessage(hwnd,WM_CLOSE,0,0);
                        break;
                    default:
                    break;
                    }
                }
                break;
            }
        }
        break;
    default: 
        Ret = DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return Ret;
}

//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//   This returns the address of character following the last instance of a particular character in a string. 
//
char *EASY::LastChar(char *str, int character)
{
	char *last;
	while(str)
	{
		last = str++;
	    str = strchr(str, character);
	}
    return ++last;
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//   This plays sounds that exist in the "Sound" directory under where the executable file is located. 
//
void EASY::LocalSound(const char *fname)
{
    char *buf = new char [MAX_PATH];
	sprintf(buf,"%s\\Sound\\%s", Easy.Exepath, fname);
	PlaySound(buf, 0, SND_ASYNC);
	delete[] buf;
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//   This writes a variable-length formatted string to a message box and waits for a response. 
//
void EASY::DisplayMessage(const char *msg,...)
{
	char *buf = new char [MSG_BUF];
	va_list args;
	va_start(args, msg);
	vsprintf(buf, msg, args);
	va_end(args);
	MessageBox(Easy.mainwin, buf, Easy.Info, MB_OK);
	delete[] buf;
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//    Align the specified window to the upper left-hand corner of the main window.
//
void EASY::Align2UpperLeft(HWND hwnd)
{
    RECT rcWindow, rcClient;
    INT width, height;
    GetWindowRect(hwnd, &rcClient);
    GetWindowRect(Easy.mainwin, &rcWindow);
    height = rcClient.bottom - rcClient.top;
    width  = rcClient.right  - rcClient.left;
    MoveWindow(hwnd, rcWindow.left, rcWindow.top, width, height, TRUE);
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  This acquires exclusive use of the random number generator.
//
void EASY::AcquireDevice()
{
    while(InterlockedExchange((PLONG)&Easy.SharedDevice, TRUE) == TRUE)
        Sleep(10);
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  This releases use of the random number generator
//
void EASY::ReleaseDevice()
{
     (void)InterlockedExchange((PLONG)&Easy.SharedDevice, FALSE);
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//   Update the randon number variable. This first acquires a lock, writes the variable,
//   then releases the lock
//
void EASY::UpdateRand()
{
    AcquireDevice();
    Easy.Rand = rand();
    ReleaseDevice();
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  Read the random number variable. This first acquires a lock, reads the variable, then
//  releases the lock.
//
int EASY::GetRand()
{
    int rnd;
    AcquireDevice();
    rnd = Easy.Rand;
    ReleaseDevice();
    return rnd;
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  This gets a random number and goes back to sleep. The amount of time to sleep has some
//  deliberate jitter added. This executes as a separate thread and any pointer passed to
//  this is not guaranteed to have a lifetime that makes it useful because the task that
//  created this thread may no longer exist!
//
LRESULT EASY::MakeRandom(void *worthless)
{
    UNREFERENCED(worthless);
    for(;;)
    {
        UpdateRand();
        Sleep(100 + (Easy.Rand & 7));
    }
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  This writes the fire-sevens into the boxes, showing a "Jackpot." 
//
void EASY::ShowJackpot()
{
        PAINT_WINDOW(Easy.hh, IDB_BITMAP14);
        PAINT_WINDOW(Easy.hl, IDB_BITMAP14);
        PAINT_WINDOW(Easy.mh, IDB_BITMAP14);
        PAINT_WINDOW(Easy.ml, IDB_BITMAP14);
        PAINT_WINDOW(Easy.sh, IDB_BITMAP14);
        PAINT_WINDOW(Easy.sl, IDB_BITMAP14);
		LocalSound("Tada.wav");
        Sleep(1000);
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  This updates the bit-mapped boxes with the current time-digits. 
//
void EASY::ShowDigit(enum DIGIT loc, int dec)
{
    int hig_nib;
    int low_nib;
    hig_nib = dec / 10;
    low_nib = dec % 10;
    switch(loc)
    {
    case HRS:
        PAINT_WINDOW(Easy.hh, Easy.Digits[hig_nib]);
        PAINT_WINDOW(Easy.hl, Easy.Digits[low_nib]);
        break;
    case MIN:
        PAINT_WINDOW(Easy.mh, Easy.Digits[hig_nib]);
        PAINT_WINDOW(Easy.ml, Easy.Digits[low_nib]);
        break;
    case MINAM:
        PAINT_WINDOW(Easy.mh, Easy.DigitsA[hig_nib]);
        PAINT_WINDOW(Easy.ml, Easy.DigitsM[low_nib]);
        break;
    case MINPM:
        PAINT_WINDOW(Easy.mh, Easy.DigitsP[hig_nib]);
        PAINT_WINDOW(Easy.ml, Easy.DigitsM[low_nib]);
        break;
    case SEC:
        PAINT_WINDOW(Easy.sh, Easy.Digits[hig_nib]);
        PAINT_WINDOW(Easy.sl, Easy.Digits[low_nib]);
        break;
    default:
        MessageBox(NULL, "Coding error in ShowDigit!", Error,
               MB_ICONERROR | MB_OK);
        exit(EXIT_FAILURE);
    }
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  In the event that a separately-generated random number, when ANDed with a mask, equals that
//  mask, i.e.,all specified bits are set, a "jackpot" of fire-sevens is written to the window instead
//  of the usual time.
//
LRESULT EASY::Display(void *unused)
{
    UNREFERENCED(unused);

    for(;;)
    {
        ((GetRand() & JACKPOT) == JACKPOT) ? ShowJackpot() : DoTime();
        Sleep(1000);
    }
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  Display the time. The format is different depending upon the setting of the "Easy.12hr" variable.
//
void EASY::DoTime()
{
    struct tm *tp;
    time_t tim;

    (void)time(&tim);
    tp = localtime(&tim);
    ShowDigit(SEC, tp->tm_sec);
    if(Easy.hr12 == TRUE)
    {
        ShowDigit((tp->tm_hour > 11) ? MINPM : MINAM, tp->tm_min);
        ShowDigit(HRS, Times[tp->tm_hour]);
    }
    else
    {
        ShowDigit(MIN, tp->tm_min);
        ShowDigit(HRS, tp->tm_hour);
    }
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//  Switch the clock format from 12 hour to 24 hours and back again. If the input parameter is TRUE,
//  a sound is generated. Otherwise, it is quiet. Immediately update the time any time the display
//  format is changed.
//
void EASY::ChangeClock(BOOL sound)
{
    Easy.hr12 ^= TRUE;      // Change 24/12 hour format
    PAINT_WINDOW(Easy.ck, (Easy.hr12 == TRUE) ? IDB_BITMAP45 : IDB_BITMAP46);
    if(sound)
        LocalSound("Exclamation.wav");
    DoTime();
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//
//   Upload all the bit-maps and then start the clock. Simplifying macros are in the header file.
//   This executes as a separate thread and any pointer passed to this is not guaranteed to have
//   a lifetime that makes it useful because the task that created this thread may no longer exist!
//
LRESULT EASY::UploadAllBitmaps(void *worthless)
{
    UNREFERENCED(worthless);
    srand((UINT)time(NULL));
    PAINT_WINDOW(Easy.mi, IDB_BITMAP1);
    PAINT_WINDOW(Easy.sp, IDB_BITMAP47);
    ChangeClock(FALSE);
    Easy.Clock = START_THREAD(NULL, 0, (LPTHREAD_START_ROUTINE) Easy.Display, NULL, (DWORD)0, Easy.ThreadId);
    (void) START_THREAD(NULL, 0, (LPTHREAD_START_ROUTINE) Easy.MakeRandom, NULL, (DWORD)0, Easy.ThreadId);
    return 0;
}
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
//=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=
