/************************************************************************

  File: colors.c

  Purpose:

    This file contains all the code necessary for the colors dialog.


  Functions:

    DoColorsDialog()          -- Starts off the creation of the main colors dlg

    ColorsProc()              -- Callback function for the colors dialog

    InitColorStruct()         -- Initializes default CHOOSECOLOR strucure

    FillColorDlg()            -- Fills the colors dialog with the current
                                 CHOOSECOLOR structure values.

    GetColorDlg()             -- Retrieves users edits and puts them in
                                 the appropriate CHOOSECOLOR structure.

    ColorsHookProc()          -- Callback hook function if the ChooseColor()
                                 function is called with CC_ENABLEHOOK

    GetColorsResHandle()      -- Loads a custom template from the EXE
                                 and returns a handle to it

    DoChooseColorStuff()      -- Calls the ChooseColor() function.

    ColorThreadProc1()        -- Starting address for the first thread

    ColorThreadProc2()        -- Starting address for the second thread

    MultiThreadColorDlg()     -- Creates two threads in this process
                                 which each create ChooseColor() dialogs.

    EnableColorButtons()      -- Enables or disables buttons in the colors
                                 dialog.  Necessary for the multithreading.


************************************************************************/


#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#include <winnls.h>
#include "cdtest.h"
#include "colors.h"


/* Function prototypes */
void InitColorStruct(HWND hwnd, LPCHOOSECOLOR) ;
void FillColorDlg(HWND hwnd, LPCHOOSECOLOR) ;
void GetColorDlg(HWND hwnd, LPCHOOSECOLOR) ;
void DoChooseColorStuff(HWND, LPCHOOSECOLOR) ;
UINT APIENTRY ColorsHookProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam) ;


/* Variables and external declarations */

CHOOSECOLOR cc ;
DWORD dwCustColors[16] ;
DWORD dwColor ;
HANDLE hDialogColors, hResColors ;
HANDLE GetColorsResHandle(void) ;
TCHAR szTemplateNameC[50] ;
extern UINT uMode ;
extern LONG MyAtol(LPTSTR, BOOL, LPBOOL) ;


/* Multithreading stuff */

DWORD dwColorThreadID1 ;
DWORD dwColorThreadID2 ;
DWORD dwColorThreadParm1 ;
DWORD dwColorThreadParm2 ;
DWORD ColorThreadProc1(LPDWORD) ;
DWORD ColorThreadProc2(LPDWORD) ;
void MultiThreadColorDlg(void) ;
void EnableColorButtons(HWND, BOOL) ;
HANDLE hColorThread1 ;
HANDLE hColorThread2 ;
HWND hwndMainColor ;
int nOpenColorDlgCount ;
CHOOSECOLOR ccThread1 ;
CHOOSECOLOR ccThread2 ;




/************************************************************************

  Function: DoColorsDialog(HWND)

  Purpose: To create the ChooseColor() common dialog creation dialog.

  Returns: Nothing.

  Comments:

************************************************************************/

void DoColorsDialog(HWND hwnd)
{


  DialogBox(hInst, MAKEINTRESOURCE(ID_COLORSDIALOG),
            hwnd, ColorsProc) ;

}







/************************************************************************

  Function: ColorsProc(HWND, UINT, UINT, LONG)

  Purpose: The callback function for the main colors dialog.

  Returns: TRUE or FALSE depending on the situation.

  Comments:

************************************************************************/


BOOL APIENTRY ColorsProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
  BOOL bRet = FALSE ;

  switch (msg)
  {

    case WM_INITDIALOG:

       InitColorStruct(hwnd, &cc) ;  //initialize the CHOOSECOLOR structure
       FillColorDlg(hwnd, &cc) ;  //and fill the colors dialog.

       nOpenColorDlgCount = 0 ;

       hwndMainColor = hwnd ;

       *(&ccThread1) = *(&ccThread2) = *(&cc) ;

       SetFocus(GetDlgItem(hwnd, ID_STRUCTSIZEC)) ;

       break ;


     case UMSG_DECREMENTDLGCOUNT:  //user defined message indicating
                                   //the closure of a multithreaded dialog

       /* Keep the main colors dialog buttons disabled until the last
          multithreaded dialog function has returned. */

       nOpenColorDlgCount-- ;

       if (nOpenColorDlgCount == 0)
         EnableColorButtons(hwnd, TRUE) ;

       break ;


     case WM_COMMAND:

        switch (LOWORD(wParam))
        {
          case IDOK:

            GetColorDlg(hwnd, &cc) ;            //get user's choices

            DoChooseColorStuff(hwnd, &cc) ;     //do the dialog

            break ;


          case ID_RESETC:

            SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_RESETCONTENT,
              (WPARAM) 0, (LPARAM) 0) ;

            InitColorStruct(hwnd, &cc) ;
            FillColorDlg(hwnd, &cc) ;

            SendDlgItemMessage(hwnd, ID_NULLSTRUCTCOLOR, BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;
            SendDlgItemMessage(hwnd, ID_PRELOADEDCOLORS, BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;

            SetFocus(GetDlgItem(hwnd, ID_STRUCTSIZEC)) ;

            break ;


          case IDCANCEL:
            EndDialog(hwnd, FALSE) ;
            break ;


          case ID_ADD1C:
            GetDlgItemText(hwnd, ID_CUSTCOLORSC, szTemp, 100) ;

            if (*szTemp)
              SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_ADDSTRING,
                                 (WPARAM) 0, (LPARAM) (LPTSTR) szTemp) ;
            break ;

          case ID_CLEAR1C:
            SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_RESETCONTENT,
                               (WPARAM) 0, (LPARAM) 0) ;
            break ;

          case ID_MULTITHREADCOLORS:

            /* Start the dialog count off at 2, disable the main dialog's
               buttons, and multithread */

            nOpenColorDlgCount = 2 ;

            EnableColorButtons(hwnd, FALSE) ;

            MultiThreadColorDlg() ;

            break ;


          default: break ;
        }

    default:


      /* If the help button is pressed in the ChooseColor()
         dialog, it will send a message Registered with RegisterWindowMessage()
         to the parent window.  The message nHelpMessage was registered
         at application startup */

      if (msg == nHelpMessage)
        MessageBox(GetForegroundWindow(), TEXT("Hello from the help button"),
                   TEXT("Colors Help Button"), MB_OK | MB_APPLMODAL) ;

      break ;
  }

  return FALSE ;
}







/************************************************************************

  Function: InitColorStruct(HWND, LPCHOOSECOLOR)

  Purpose: Fills the default CHOOSECOLOR structure with some default
           values.

  Returns: Nothing.

  Comments:

************************************************************************/


void InitColorStruct(HWND hwnd, LPCHOOSECOLOR pcc)
{
  int i ;

  pcc->lStructSize  = sizeof(CHOOSECOLOR) ;
  pcc->hwndOwner    = hwnd ;
  pcc->hInstance    = (HANDLE) hInst ;

  dwColor = RGB(0, 0, 0) ;
  pcc->rgbResult    = dwColor ;

  for (i=0; i<16; i++)
    dwCustColors[i] = (RGB(255-i*10, i, i*10)) ;

  pcc->lpCustColors = (LPDWORD) dwCustColors ;

  pcc->Flags     = CC_FULLOPEN | CC_SHOWHELP | CC_RGBINIT ;

  pcc->lCustData = 0 ;

  pcc->lpfnHook = ColorsHookProc ;

  lstrcpy(szTemplateNameC, TEXT("clrtemp")) ;         //name of custom template

  pcc->lpTemplateName = (LPTSTR) szTemplateNameC ;

  return ;
}








/************************************************************************

  Function: FillColorDlg(HWND, LPCHOOSECOLOR)

  Purpose: Fills the colors dialog with the current contents of the
           CHOOSECOLOR structure passed in as the second parameter.

  Returns: Nothing.

  Comments:

************************************************************************/

void FillColorDlg(HWND hwnd, LPCHOOSECOLOR pcc)
{
  int i ;

  wsprintf(szTemp, szLongFilter, pcc->lStructSize) ;
  SetDlgItemText(hwnd, ID_STRUCTSIZEC, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) pcc->hwndOwner) ;
  SetDlgItemText(hwnd, ID_HWNDOWNERC, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) pcc->hInstance) ;
  SetDlgItemText(hwnd, ID_HINSTANCEC, szTemp) ;

  wsprintf(szTemp, szLongFilter, pcc->rgbResult) ;
  SetDlgItemText(hwnd, ID_RGBRESULTC, szTemp) ;

  SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_RESETCONTENT,
                     (WPARAM) 0, (LPARAM) 0) ;

  for (i=0; i<16; i++)
  {
    wsprintf(szTemp, szLongFilter, dwCustColors[i]) ;
    SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_ADDSTRING,
                       (WPARAM) 0, (LPARAM) (LPTSTR) szTemp) ;
  }

  SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_SETCURSEL,
                     (WPARAM) 0 , (LPARAM) 0) ;

  wsprintf(szTemp, szLongFilter, pcc->Flags) ;
  SetDlgItemText(hwnd, ID_FLAGSC, szTemp) ;

  wsprintf(szTemp, szLongFilter, pcc->lCustData) ;
  SetDlgItemText(hwnd, ID_CUSTDATAC, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) pcc->lpfnHook) ;
  SetDlgItemText(hwnd, ID_HOOKC, szTemp) ;

  SetDlgItemText(hwnd, ID_TEMPLATEC, (LPTSTR) pcc->lpTemplateName) ;
}







/************************************************************************

  Function: GetColorDlg(HWND, LPCHOOSECOLOR)

  Purpose: Retrieves the users entries in the colors dialog edit boxes
           and puts them in the appropriate CHOOSECOLOR structure
           members.

  Returns: Nothing.

  Comments:

************************************************************************/


void GetColorDlg(HWND hwnd, LPCHOOSECOLOR pcc)
{
  int i ;
  BOOL b ;
  TCHAR szNum[30] ;

  #define WSIZECC 30

  GetDlgItemText(hwnd, ID_STRUCTSIZEC, szNum, WSIZECC) ;
  pcc->lStructSize = MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HWNDOWNERC, szNum, WSIZECC) ;
  pcc->hwndOwner = (HWND) MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HINSTANCEC, szNum, WSIZECC) ;
  pcc->hInstance = (HANDLE) MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_RGBRESULTC, szNum, WSIZECC) ;
  pcc->rgbResult = MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  for (i=0; i<16; i++)
  {
    if (SendDlgItemMessage(hwnd, ID_CUSTCOLORSC, CB_GETLBTEXT,
                          (WPARAM) i, (LPARAM) (LPTSTR) szNum) != CB_ERR)

      dwCustColors[i] = MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

    else
      dwCustColors[i] = (DWORD) 0 ;

    *(pcc->lpCustColors + i) = dwCustColors[i] ;
  }

  GetDlgItemText(hwnd, ID_FLAGSC, szNum, WSIZECC) ;
  pcc->Flags = MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_CUSTDATAC, szNum, WSIZECC) ;
  pcc->lCustData = MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HOOKC, szNum, WSIZECC) ;
  pcc->lpfnHook = (LPCCHOOKPROC) MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_TEMPLATEC, (LPTSTR) pcc->lpTemplateName, 50) ;

  return ;
}







/************************************************************************

  Function: ColorsHookProc(HWND, UINT, UINT, LONG) ;

  Purpose:  This function will be called before the normal ChooseColor()
            logic is envoked.

  Returns: FALSE to instruct ChooseColor() to proceed with it's normal
           processing of the message.  TRUE to discard normal processing.

  Comments:

    To enable the hook, type the value for "CC_ENABLEHOOK" in the
    "Flags" edit box.

************************************************************************/

UINT APIENTRY ColorsHookProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
  LPCHOOSECOLOR pCc ;
  TCHAR szMsg[50] ;

  switch(msg)
  {
    case WM_INITDIALOG:

      /* During initialization of the ChooseColor() dialog, if there is a
         hook proc the ChooseColor() function will send a pointer to the
         current CHOOSECOLOR structure in the wParam parameter */

      pCc = (LPCHOOSECOLOR) lParam ;

      if (pCc->lCustData != 0L)
      {
        wsprintf(szMsg, TEXT("CHOOSECOLOR->lCustData is: %ld"), pCc->lCustData) ;
        MessageBox(hwnd, szMsg, TEXT("lCustData Sent!"), MB_OK | MB_APPLMODAL) ;
      }

      SetWindowText(hwnd, TEXT("Color Hook Proc Dialog")) ;

      break ;

    default:
      break ;
  }

  return FALSE ;   //send msg to the common dialog code
}







/************************************************************************

  Function: GetColorsResHandle(void)

  Purpose: Creates a handle to the custom template and returns it to the
           caller.

  Returns: HANDLE to a preloaded custom template

  Comments:

    To use this preloaded template, mark the "Preloaded Template" checkbox
    and enter CC_ENABLETEMPLATEHANDLE in the "Flags" edit box.

************************************************************************/

HANDLE GetColorsResHandle(void)
{

  hResColors = FindResource(hInst, TEXT("clrtemp"), RT_DIALOG) ;

  hDialogColors = LoadResource(hInst, hResColors) ;


  return hDialogColors ;
}







/************************************************************************

  Function:DoChooseColorStuff(HWND, LPCHOOSECOLOR)

  Purpose: Does the actual calling of the ChooseColor() function.


  Returns: Nothing.

  Comments:

************************************************************************/

void DoChooseColorStuff(HWND hwnd, LPCHOOSECOLOR pcc)
{
  BOOL bRet ;

  /* If the "Preloaded template button is checked, load a handle for
     the custom template and put it in the hInstance member of the
     CHOOSECOLOR structure */

  if (IsDlgButtonChecked(hwnd, ID_PRELOADEDCOLORS) == 1)
    pcc->hInstance = GetColorsResHandle() ;


   /* If the "NULL Structure" box is checked, call ChooseColor() will
      a NULL pointer.  Otherwise call with the current CHOOSECOLOR pointer */

  if (IsDlgButtonChecked(hwnd, ID_NULLSTRUCTCOLOR) == 1)
    bRet = ChooseColor((LPCHOOSECOLOR) NULL) ;
  else
    bRet = ChooseColor(pcc) ;

  if (pcc->hInstance)
  {
    FreeResource(hDialogColors) ;
    hDialogColors = (HANDLE) 0 ;
    hResColors = (HANDLE) 0 ;
  }


  /* Fill the results into the main colors dialog */

  FillColorDlg(hwnd, pcc) ;

  wsprintf(szTemp, szShortFilter, bRet) ;
  SetDlgItemText(hwnd, ID_RETURNC, szTemp) ;

  wsprintf(szTemp, szLongFilter, CommDlgExtendedError()) ;
  SetDlgItemText(hwnd, ID_ERRORC, szTemp) ;

}






/************************************************************************

  Function:ColorThreadProc1(LPDWORD)

  Purpose: Starting address for first thread


  Returns: Any DWORD value.

  Comments:

************************************************************************/


DWORD ColorThreadProc1(LPDWORD pdw)
{
  GetColorDlg(hwndMainColor, &ccThread1) ;
  DoChooseColorStuff(hwndMainColor, &ccThread1) ;

  PostMessage(hwndMainColor, UMSG_DECREMENTDLGCOUNT, 0, 0L ) ;

  return 0L ;
}







/************************************************************************

  Function:ColorThreadProc2(LPDWORD)

  Purpose: Starting address for second thread


  Returns: Any DWORD value.

  Comments:

************************************************************************/

DWORD ColorThreadProc2(LPDWORD pdw)
{
  GetColorDlg(hwndMainColor, &ccThread2) ;
  DoChooseColorStuff(hwndMainColor, &ccThread2) ;

  PostMessage(hwndMainColor, UMSG_DECREMENTDLGCOUNT, 0, 0L ) ;

  return 0L ;
}







/************************************************************************

  Function:MultiThreadColorDlg(void)

  Purpose: Creates two threads which will each create a new ChooseColor()
           dialog.


  Returns: Nothing.

  Comments:

    Do not pass any parameters to this function that may be used by the
    ChooseColor dialog routines because this function will return before
    the new threads are finished.

************************************************************************/


void MultiThreadColorDlg(void)
{

  dwColorThreadParm1 = dwColorThreadParm2 = 0L ;

  if (!(hColorThread1 = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0,
                                     (LPTHREAD_START_ROUTINE) ColorThreadProc1,
                                     &dwColorThreadParm1, CREATE_SUSPENDED, &dwColorThreadID1)))

  {
    MessageBox(GetForegroundWindow(), TEXT("Error creating thread 1"), NULL,
               MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL) ;

    nOpenColorDlgCount = 0 ;

    EnableColorButtons(hwndMainColor, TRUE) ;

    return ;
  }


  if (!(hColorThread2 = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0,
                                     (LPTHREAD_START_ROUTINE) ColorThreadProc2,
                                     &dwColorThreadParm2, CREATE_SUSPENDED, &dwColorThreadID2)))
  {
    MessageBox(GetForegroundWindow(), TEXT("Error creating thread 2"), NULL,
               MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL) ;

    nOpenColorDlgCount = 0 ;

    EnableColorButtons(hwndMainColor, TRUE) ;

    return ;
  }

  ResumeThread(hColorThread1) ;

  ResumeThread(hColorThread2) ;

  return ;
}





/************************************************************************

  Function:EnableColorButtons(HWND, BOOL)

  Purpose: Enables or disables the buttons on the main colors dialog.
           Necessary when multithreading.

  Returns: Nothing.

  Comments:

************************************************************************/


void EnableColorButtons(HWND hwnd, BOOL bEnable)
{
  EnableWindow(GetDlgItem(hwnd, IDOK), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, IDCANCEL), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, ID_RESETC), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, ID_MULTITHREADCOLORS), bEnable) ;
}
