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

  File: print.c

  Purpose:  To manage CDTEST's print dialog box.


  Functions:

    DoPrintDlg()            -- Creates CDTEST's print dialog box.

    PrintProc()             -- Callback function for CDTEST's print dialog box.

    DevnamesProc()          -- Callback function for CDTESTS Devnames dlg box.

    DevmodeProc()           -- Callback function for CDTESTS Devmode dlg box.

    InitPrintStruct()       -- Fills a PRINTDLG struct with some default values.

    FillPrintDlg()          -- Fills CDTEST's print dialog with contents of a
                               PRINTDLG structure.

    GetPrintDlg()           -- Retrieves the users edits from CDTEST's print dlg.

    FillDevnamesDlg()       -- Fills CDTEST's Devnames dialog with the contents
                               of a DEVNAMES structure.

    GetDevnamesDlg()        -- Retrieves the user's edits from CDTEST's devnames dlg.

    FillDevmodeDlg()        -- Fills CDTEST's devmode dialog with the contents of
                               a DEVMODE structure.

    GetDevmodeDlg()         -- Retrieves the user's edits from CDTEST's devmode dlg.

    GetPrintDlgHandle()     -- Loads and returns a handle to a Print dlg custom template.

    GetSetupDlgHandle()     -- Loads and returns a handle to a Setup dlg custom template.

    PrintHookProc()         -- Callback function for PRINTDLG->lpfnPrintHook and
                               for PRINTDLG->lpfnSetupHook

    PrintMultiProc1()       -- Starting address for multithread option thread 1

    PrintMultiProc2()       -- Starting address for multithread option thread 2

    MultiThreadPrintDlg()   -- Creates two threads which each call PrintDlg()

    EnablePrintControls()   -- Enables or disables CDTEST's print dlg controls.

    DoPrintDlgStuff()       -- Calls PrintDlg()

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


#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#include <winnls.h>
#include "cdtest.h"
#include "print.h"
#include "devnames.h"
#include "devmode.h"
#include "dlgs.h"



/* Externs, prototypes, variable declarations for print.c */

extern UINT uMode ;
extern LONG MyAtol(LPTSTR, BOOL, LPBOOL) ;
UINT APIENTRY PrintHookProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam) ;
void InitPrintStruct(HWND, LPPRINTDLG) ;
void FillPrintDlg(HWND, LPPRINTDLG) ;
void GetPrintDlg(HWND, LPPRINTDLG) ;
void FillDevnamesDlg(HWND, LPPRINTDLG) ;
void GetDevnamesDlg(HWND, LPPRINTDLG) ;
void FillDevmodeDlg(HWND, LPPRINTDLG) ;
void GetDevmodeDlg(HWND, LPPRINTDLG) ;
HANDLE GetPrintDlgHandle(void) ;
HANDLE GetSetupDlgHandle(void) ;
void DoPrintDlgStuff(HWND, LPPRINTDLG) ;

HANDLE hResPrint ;
HANDLE hDialogPrint ;
PRINTDLG pd ;
HANDLE hDevNames ;
HANDLE hDevMode ;

TCHAR szDriverOffset[100] ;
TCHAR szDeviceOffset[100] ;
TCHAR szOutputOffset[100] ;
TCHAR szPrintTempName[40] ;
TCHAR szSetupTempName[40] ;


/* Multithreading function declarations, variables */

DWORD PrintMultiProc1(LPDWORD) ;
DWORD PrintMultiProc2(LPDWORD) ;
void MultiThreadPrintDlg(void) ;
void EnablePrintControls(HWND, BOOL) ;

HANDLE hPrintThread1 ;
HANDLE hPrintThread2 ;
DWORD dwPrintThreadID1 ;
DWORD dwPrintThreadID2 ;
DWORD dwPrintThreadParm1 ;
DWORD dwPrintThreadParm2 ;
PRINTDLG pdThread1 ;
PRINTDLG pdThread2 ;
HWND hwndMainPrint ;
int nOpenDialogCount ;

HBRUSH hBrushDlg ;
HBRUSH hBrushEdit ;    //brush handles for new colors done with hook proc
HBRUSH hBrushButton ;





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

  Function: DoPrintDialog(HWND)

  Purpose:  Creates CDTEST's print dialog box.

  Returns:  Nothing.

  Comments: There is only one dialog for both Print Setup and Print Print.
            The Print Print dialog is the default.  To create the Print
            Setup dialog, enter the value for PD_PRINTSETUP into the
            "Flags" edit box and click OK.

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

void DoPrintDialog(HWND hwnd)
{


  DialogBox(hInst, MAKEINTRESOURCE(ID_PRINTDIALOG),
            hwnd, PrintProc) ;

}







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

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

  Purpose:  Callback function for CDTEST's print dialog box.

  Returns:  TRUE or FALSE depending on the situation/message.

  Comments:

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

BOOL APIENTRY PrintProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
  switch (msg)
  {
    case WM_INITDIALOG:

        InitPrintStruct(hwnd, &pd) ;
        FillPrintDlg(hwnd, &pd) ;

        *(&pdThread1) = *(&pdThread2) = *(&pd) ;

        hwndMainPrint = hwnd ;

        nOpenDialogCount = 0 ;

        SetFocus(GetDlgItem(hwnd, ID_STRUCTSIZEP)) ;

        break ;


    case UMSG_DECREMENTDLGCOUNT: //user defined message that is send when
                                 //each thread created when multithreading ends
        nOpenDialogCount-- ;

        if (nOpenDialogCount == 0)               //once both multitheading dlgs
            EnablePrintControls(hwnd, TRUE) ;   //are done, enable the controls again

        break ;


    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
          case IDOK:
            GetPrintDlg(hwnd, &pd) ;
            DoPrintDlgStuff(hwnd, &pd) ;
            break ;

          case IDCANCEL:

            if (pd.hDC)
              ReleaseDC(hwnd, pd.hDC) ;

            EndDialog(hwnd, FALSE) ;
            break ;

          case ID_RESETPRINT:
            SetFocus(GetDlgItem(hwnd, ID_STRUCTSIZEP)) ;
            InitPrintStruct(hwnd, &pd) ;
            FillPrintDlg(hwnd, &pd) ;
            SendDlgItemMessage(hwnd, ID_PRESETUPP,   BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;
            SendDlgItemMessage(hwnd, ID_PREPRINTP,   BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;
            SendDlgItemMessage(hwnd, ID_NULLSTRUCTP, BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;
            break ;

          case ID_EDITDEVNAMES:
            DialogBox(hInst, MAKEINTRESOURCE(ID_DEVNAMESDIALOG),
                      hwnd, DevnamesProc) ;
            break ;

          case ID_EDITDEVMODE:
            DialogBox(hInst, MAKEINTRESOURCE(ID_DEVMODEDIALOG),
                      hwnd, DevmodeProc) ;
            break ;

          case ID_MULTITHREADPRINT:
            nOpenDialogCount = 2 ;
            EnablePrintControls(hwnd, FALSE) ;
            MultiThreadPrintDlg() ;
            break ;

          default: break ;
        }
    }

    default:

      /* If the help button is pressed in the PrintDlg() dialog box,
         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("Print Help Button"), MB_OK | MB_APPLMODAL) ;
      break ;
  }

  return FALSE ;
}








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

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

  Purpose:  Callback function for the Devnames dialog box

  Returns:  TRUE or FALSE depending on situation / message

  Comments:

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

BOOL APIENTRY DevnamesProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
  switch (msg)
  {
    case WM_INITDIALOG:
        FillDevnamesDlg(hwnd, &pd) ;
        break ;

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
          case IDOK:
            GetDevnamesDlg(hwnd, &pd) ;
            EndDialog(hwnd, TRUE) ;
            break ;

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

          default: break ;
        }
    }

    default: break ;
  }

  return FALSE ;
}






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

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

  Purpose:  Callback function for the Devmode dialog box

  Returns:  TRUE or FALSE depending on situation / message

  Comments:

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

BOOL APIENTRY DevmodeProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
  switch (msg)
  {
    case WM_INITDIALOG:
        FillDevmodeDlg(hwnd, &pd) ;
        break ;

    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
          case IDOK:
            GetDevmodeDlg(hwnd, &pd) ;
            EndDialog(hwnd, TRUE) ;
            break ;

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

          default: break ;
        }
    }

    default: break ;
  }

  return FALSE ;
}








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

  Function: InitPrintStruct(HWND, LPPRINTDLG)

  Purpose:  Fills a PRINTDLG structure with some default values.

  Returns:  Nothing.

  Comments:

    In order to fill in the hDevMode and hDevNames PRINTDLG structure
    elements, a call to PrintDlg() must be made with the
    (PD_RETURNDEFAULT | PD_RETURNDC) flag bits set.

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

void InitPrintStruct(HWND hwnd, LPPRINTDLG ppd)
{
  DWORD dwTempFlags = 0 ;

  ppd->lStructSize = sizeof(PRINTDLG) ;
  ppd->hwndOwner = hwnd ;
  ppd->hDevMode = (HANDLE) 0 ;
  ppd->hDevNames = (HANDLE) 0 ;
  ppd->hDC = (HDC) 0 ;
  ppd->Flags = PD_RETURNDC | PD_COLLATE | PD_SHOWHELP | PD_PAGENUMS ;
  ppd->nFromPage = 1 ;
  ppd->nToPage = 10 ;
  ppd->nMinPage = 0 ;
  ppd->nMaxPage = 9 ;
  ppd->nCopies = 1000 ;
  ppd->hInstance = (HANDLE) hInst ;
  ppd->lCustData = 0L ;

  ppd->lpfnPrintHook = PrintHookProc ;
  ppd->lpfnSetupHook = PrintHookProc ;

  lstrcpy(szPrintTempName, TEXT("prtemp1")) ;
  ppd->lpPrintTemplateName = szPrintTempName ;

  lstrcpy(szSetupTempName, TEXT("prtemp2")) ;
  ppd->lpSetupTemplateName = szSetupTempName ;

  ppd->hPrintTemplate = (HANDLE) 0 ;   //these are unknown right now
  ppd->hSetupTemplate = (HANDLE) 0 ;


  /* Let's fill the hDevMode and hDevNames structures. */
  /* This call should just return handles to structures of this */
  /* type filled with the info for the default printer */

  dwTempFlags = ppd->Flags ;
  ppd->Flags = PD_RETURNDEFAULT | PD_RETURNDC ;
  PrintDlg(ppd) ;

  ppd->Flags = dwTempFlags ;
}







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

  Function: FillPrintDlg(HWND, LPPRINTDLG)

  Purpose:  Fills CDTEST's print dialog with the contents of a
            PRINTDLG structure.

  Returns:  Nothing.

  Comments:

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


void FillPrintDlg(HWND hwnd, LPPRINTDLG ppd)
{
  wsprintf(szTemp, szLongFilter, ppd->lStructSize) ;
  SetDlgItemText(hwnd, ID_STRUCTSIZEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hwndOwner) ;
  SetDlgItemText(hwnd, ID_HWNDOWNERP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hDevMode) ;
  SetDlgItemText(hwnd, ID_HDEVMODEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hDevNames) ;
  SetDlgItemText(hwnd, ID_HDEVNAMESP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hDC) ;
  SetDlgItemText(hwnd, ID_HDCP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->Flags) ;
  SetDlgItemText(hwnd, ID_FLAGSP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->nFromPage) ;
  SetDlgItemText(hwnd, ID_FROMPAGEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->nToPage) ;
  SetDlgItemText(hwnd, ID_TOPAGEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->nMinPage) ;
  SetDlgItemText(hwnd, ID_MINPAGEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->nMaxPage) ;
  SetDlgItemText(hwnd, ID_MAXPAGEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->nCopies) ;
  SetDlgItemText(hwnd, ID_COPIESP, szTemp) ;

  wsprintf(szTemp, szLongFilter, ppd->hInstance) ;
  SetDlgItemText(hwnd, ID_HINSTANCEP, szTemp) ;

  wsprintf(szTemp, szLongFilter, ppd->lCustData) ;
  SetDlgItemText(hwnd, ID_CUSTDATAP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->lpfnPrintHook) ;
  SetDlgItemText(hwnd, ID_PRINTHOOKP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->lpfnSetupHook) ;
  SetDlgItemText(hwnd, ID_SETUPHOOKP, szTemp) ;

  SetDlgItemText(hwnd, ID_LPPRINTTEMPP, ppd->lpPrintTemplateName) ;

  SetDlgItemText(hwnd, ID_LPSETUPTEMPP, ppd->lpSetupTemplateName) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hPrintTemplate) ;
  SetDlgItemText(hwnd, ID_HPRINTTEMPP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hSetupTemplate) ;
  SetDlgItemText(hwnd, ID_HSETUPTEMPP, szTemp) ;
}









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

  Function: GetPrintDlg(HWND, LPPRINTDLG)

  Purpose:  Fills a PRINTDLG structure with the users choices in CDTEST's
            print dialog box.

  Returns:  Nothing.

  Comments:

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

void GetPrintDlg(HWND hwnd, LPPRINTDLG ppd)
{
  BOOL b ;
  TCHAR szNum[20] ;

  #define WMAX 20

  GetDlgItemText(hwnd, ID_STRUCTSIZEP, szNum, WMAX) ;
  ppd->lStructSize = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HWNDOWNERP, szNum, WMAX) ;
  ppd->hwndOwner = (HWND) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HDEVMODEP, szNum, WMAX) ;
  ppd->hDevMode = (HANDLE) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HDEVNAMESP, szNum, WMAX) ;
  ppd->hDevNames = (HANDLE) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HDCP, szNum, WMAX) ;
  ppd->hDC = (HDC) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_FLAGSP, szNum, WMAX) ;
  ppd->Flags = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_FROMPAGEP, szNum, WMAX) ;
  ppd->nFromPage = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_TOPAGEP, szNum, WMAX) ;
  ppd->nToPage = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_MINPAGEP, szNum, WMAX) ;
  ppd->nMinPage = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_MAXPAGEP, szNum, WMAX) ;
  ppd->nMaxPage = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_COPIESP, szNum, WMAX) ;
  ppd->nCopies = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HINSTANCEP, szNum, WMAX) ;
  ppd->hInstance = (HANDLE) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_CUSTDATAP, szNum, WMAX) ;
  ppd->lCustData = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_PRINTHOOKP, szNum, WMAX) ;
  ppd->lpfnPrintHook = (LPPRINTHOOKPROC) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_SETUPHOOKP, szNum, WMAX) ;
  ppd->lpfnSetupHook = (LPSETUPHOOKPROC) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_LPPRINTTEMPP, szPrintTempName, 100) ;

  GetDlgItemText(hwnd, ID_LPSETUPTEMPP, szSetupTempName, 100) ;

  GetDlgItemText(hwnd, ID_HPRINTTEMPP, szNum, WMAX) ;
  ppd->hPrintTemplate = (HANDLE) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_HSETUPTEMPP, szNum, WMAX) ;
  ppd->hSetupTemplate = (HANDLE) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

}








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

  Function: FillDevnamesDlg(HWND, LPPRINTDLG)

  Purpose:  Fills CDTEST's devnames dialog box with the values in
            The hDevNames structure member of a PRINTDLG structure.

  Returns:  Nothing.

  Comments:

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


void FillDevnamesDlg(HWND hwnd, LPPRINTDLG ppd)
{
  LPDEVNAMES pn = (LPDEVNAMES) 0 ;

  if (ppd->hDevNames == (HANDLE) 0)
    return ;

  pn = (LPDEVNAMES) GlobalLock(ppd->hDevNames) ;
  if (pn == (LPDEVNAMES) NULL) return ;


  /* To find the strings in this block of memory, add the correct
     offset to the original pointer returned by GlobalLock() */

  SetDlgItemText(hwnd, ID_WDRIVEROFF, (LPTSTR) pn + pn->wDriverOffset) ;

  SetDlgItemText(hwnd, ID_WDEVICEOFF, (LPTSTR) pn + pn->wDeviceOffset) ;

  SetDlgItemText(hwnd, ID_WOUTPUTOFF, (LPTSTR) pn + pn->wOutputOffset) ;


  wsprintf(szTemp, szShortFilter, (int) pn->wDefault) ;
  SetDlgItemText(hwnd, ID_WDEFAULT, szTemp) ;


  GlobalUnlock(ppd->hDevNames) ;
}







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

  Function: GetDevnamesDlg(HWND, LPPRINTDLG)

  Purpose:  Retrieves the user's choices in CDTEST's devnames dialog box,
            Allocates some memory to hold a new DEVNAMES structure, fills
            the users choices into the new DEVNAMES structure, and sets
            the hDevNames member of a PRINTDLG structure to this new
            memory handle.


  Returns:  Nothing.

  Comments:

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

void GetDevnamesDlg(HWND hwnd, LPPRINTDLG ppd)
{
  BOOL b ;
  TCHAR szNum[30] ;
  LPDEVNAMES pn ;
  TCHAR sz1[100] ;
  TCHAR sz2[100] ;
  TCHAR sz3[100] ;
  DWORD dwSize ;
  int n1, n2, n3 ;

  GetDlgItemText(hwnd, ID_WDRIVEROFF, sz1, 100) ;
  GetDlgItemText(hwnd, ID_WDEVICEOFF, sz2, 100) ;
  GetDlgItemText(hwnd, ID_WOUTPUTOFF, sz3, 100) ;

  n1 = lstrlen(sz1) ;
  n2 = lstrlen(sz2) ;
  n3 = lstrlen(sz3) ;

  if (hDevNames)
  {
    GlobalFree(hDevNames) ;
    hDevNames = (HANDLE) 0 ;
  }


  /* allocate size of everything + 5 extra bytes for zeroes */

  dwSize = sizeof(DEVNAMES) + ((n1+n2+n3+5) * sizeof(TCHAR)) ;


  /* Allocate the memory and lock it down */

  if (!(hDevNames = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize)))
  {
    MessageBox(hwnd, TEXT("Can't Alloc memory for hDevNames!"),
               TEXT("Fatal Error!"), MB_OK | MB_APPLMODAL) ;
    return ;
  }

  if (!(pn = (LPDEVNAMES) GlobalLock(hDevNames)))
  {
    MessageBox(hwnd, TEXT("Can't Lock New hDevNames memory!"),
               TEXT("Fatal Error"), MB_OK | MB_APPLMODAL) ;

    GlobalFree(hDevNames) ;

    hDevNames = (HANDLE) 0 ;

    return ;
  }


  /* skip over devnames and copy string 1 there.  Make sure to
     divide by sizeof(TCHAR) or the compiler will create a pointer
     that points too far if you compile as a UNICODE program */

  pn->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR) ;
  lstrcpy((LPTSTR) pn + pn->wDriverOffset, (LPTSTR) sz1) ;



  /* skip over string 1 and add string 1 with a zero between them */

  pn->wDeviceOffset = pn->wDriverOffset + n1 + 1 ;
  lstrcpy((LPTSTR) pn + pn->wDeviceOffset, (LPTSTR) sz2) ;



  /* skip over string 2 and put string 3 there with a zero between them */

  pn->wOutputOffset = pn->wDeviceOffset + n2 + 1 ;
  lstrcpy((LPTSTR) pn + pn->wOutputOffset, (LPTSTR) sz3) ;


  GetDlgItemText(hwnd, ID_WDEFAULT, szNum, 30) ;
  pn->wDefault = (WORD) MyAtol(szNum, uMode == IDM_HEXMODE, &b) ;

  GlobalUnlock(hDevNames) ;

  ppd->hDevNames = hDevNames ;

  wsprintf(szTemp, szLongFilter, ppd->hDevNames) ;
  SetDlgItemText(GetParent(hwnd), ID_HDEVNAMESP, szTemp) ;

}






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

  Function: FillDevmodeDlg(HWND, LPPRINTDLG)

  Purpose: Fills CDTEST's devmode dialog with the contents of the DEVMODE
           structure handle of a PRINTDLG structure.


  Returns:  Nothing.

  Comments:

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

void FillDevmodeDlg(HWND hwnd, LPPRINTDLG ppd)
{
  LPDEVMODE p ;

  if (ppd->hDevMode == (HANDLE) 0)
    return ;

  p = (LPDEVMODE) GlobalLock(ppd->hDevMode) ;
  if (p == (LPDEVMODE) NULL) return ;

  SetDlgItemText(hwnd, ID_DMDEVNAME, (LPTSTR) p->dmDeviceName) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmSpecVersion) ;
  SetDlgItemText(hwnd, ID_DMSPECVER, szTemp) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmDriverVersion) ;
  SetDlgItemText(hwnd, ID_DMDRIVERVER, szTemp) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmSize) ;
  SetDlgItemText(hwnd, ID_DMSIZEDEV, szTemp) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmDriverExtra) ;
  SetDlgItemText(hwnd, ID_DMDRIVEREXTRA, szTemp) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmFields) ;
  SetDlgItemText(hwnd, ID_DMFIELDS, szTemp) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmOrientation) ;
  SetDlgItemText(hwnd, ID_DMORIENTATION, szTemp) ;

  wsprintf(szTemp, szShortFilter, (int) p->dmPaperSize) ;
  SetDlgItemText(hwnd, ID_DMPAPERSIZE, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmPaperLength) ;
  SetDlgItemText(hwnd, ID_DMPAPERLENGTH, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmPaperWidth) ;
  SetDlgItemText(hwnd, ID_DMPAPERWIDTH, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmScale) ;
  SetDlgItemText(hwnd, ID_DMSCALE, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmCopies) ;
  SetDlgItemText(hwnd, ID_DMCOPIES, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmDefaultSource) ;
  SetDlgItemText(hwnd, ID_DMDEFAULTSOURCE, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmPrintQuality) ;
  SetDlgItemText(hwnd, ID_DMPRINTQUALITY, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmColor) ;
  SetDlgItemText(hwnd, ID_DMCOLOR, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmDuplex) ;
  SetDlgItemText(hwnd, ID_DMDUPLEX, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmCollate) ;
  SetDlgItemText(hwnd, ID_DMCOLLATE, szTemp) ;

  SetDlgItemText(hwnd, ID_DMFORMNAME, (LPTSTR) p->dmFormName) ;

  wsprintf(szTemp, szLongFilter, p->dmBitsPerPel) ;
  SetDlgItemText(hwnd, ID_DMBITSPERPEL, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmPelsWidth) ;
  SetDlgItemText(hwnd, ID_DMPELSWIDTH, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmPelsHeight) ;
  SetDlgItemText(hwnd, ID_DMPELSHEIGHT, szTemp) ;

  wsprintf(szTemp, szLongFilter, p->dmDisplayFrequency) ;
  SetDlgItemText(hwnd, ID_DMDISPLAYFREQ, szTemp) ;

  GlobalUnlock(ppd->hDevMode) ;
}









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

  Function: GetDevmodeDlg(HWND, LPPRINTDLG)

  Purpose:  Retrieves the user's edits in CDTEST's DEVMODE dialog box,
            allocates memory for a new DEVMODE structure, fills that
            memory with the user's edits, and puts a handle to that
            memory in the hDevMode member of a PRINTDLG structure.

  Returns:  Nothing.

  Comments:

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

void GetDevmodeDlg(HWND hwnd, LPPRINTDLG ppd)
{
  LPDEVMODE p ;
  BOOL b ;
  TCHAR szNum[30] ;

  #define WMAXDEV 30

  if (hDevMode)
  {
    GlobalFree(hDevMode) ;
    hDevMode = (HANDLE) 0 ;
  }

  if (!(hDevMode = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, sizeof(DEVMODE))))
  {
    MessageBox(hwnd, TEXT("Can't allocate memory for hDevMode"),
               TEXT("Fatal Error"), MB_OK | MB_APPLMODAL) ;
    return ;
  }

  if (!(p = (LPDEVMODE) GlobalLock(hDevMode)))
  {
    MessageBox(hwnd, TEXT("Can't lock memory for hDevMode"),
               TEXT("Fatal Error"), MB_OK | MB_APPLMODAL) ;

    GlobalFree(hDevMode) ;
    hDevMode = (HANDLE) 0 ;

    return ;
  }

  GetDlgItemText(hwnd, ID_DMDEVNAME, p->dmDeviceName, 32) ;

  GetDlgItemText(hwnd, ID_DMSPECVER, szNum, WMAXDEV) ;
  p->dmSpecVersion = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMDRIVERVER, szNum, WMAXDEV) ;
  p->dmDriverVersion = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMSIZEDEV, szNum, WMAXDEV) ;
  p->dmSize = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMDRIVEREXTRA, szNum, WMAXDEV) ;
  p->dmDriverExtra = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMFIELDS, szNum, WMAXDEV) ;
  p->dmFields = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMORIENTATION, szNum, WMAXDEV) ;
  p->dmOrientation = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMPAPERSIZE, szNum, WMAXDEV) ;
  p->dmPaperSize = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMPAPERLENGTH, szNum, WMAXDEV) ;
  p->dmPaperLength = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMPAPERWIDTH, szNum, WMAXDEV) ;
  p->dmPaperWidth = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMSCALE, szNum, WMAXDEV) ;
  p->dmScale = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMCOPIES, szNum, WMAXDEV) ;
  p->dmCopies = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMDEFAULTSOURCE, szNum, WMAXDEV) ;
  p->dmDefaultSource = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMPRINTQUALITY, szNum, WMAXDEV) ;
  p->dmPrintQuality = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMCOLOR, szNum, WMAXDEV) ;
  p->dmColor = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMDUPLEX, szNum, WMAXDEV) ;
  p->dmDuplex = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMCOLLATE, szNum, WMAXDEV) ;
  p->dmCollate = (short) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMFORMNAME, p->dmFormName, 32) ;

  GetDlgItemText(hwnd, ID_DMBITSPERPEL, szNum, WMAXDEV) ;
  p->dmBitsPerPel = (USHORT) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMPELSWIDTH, szNum, WMAXDEV) ;
  p->dmPelsWidth = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMPELSHEIGHT, szNum, WMAXDEV) ;
  p->dmPelsHeight = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GetDlgItemText(hwnd, ID_DMDISPLAYFREQ, szNum, WMAXDEV) ;
  p->dmDisplayFrequency = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

  GlobalUnlock(hDevMode) ;
  ppd->hDevMode = hDevMode ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hDevMode) ;
  SetDlgItemText(GetParent(hwnd), ID_HDEVMODEP, szTemp) ;
}






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

  Function: GetPrintDlgHandle(void)

  Purpose:  Finds the custom Print dialog template in the EXE, loads it
            into a handle, and returns the handle.

  Returns:  Nothing.

  Comments:

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

HANDLE GetPrintDlgHandle(void)
{
  hResPrint = FindResource(hInst, TEXT("prtemp1"), RT_DIALOG) ;

  hDialogPrint = LoadResource(hInst, hResPrint) ;


  return hDialogPrint ;
}








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

  Function: GetSetupDlgHandle(void)

  Purpose:  Finds the custom Setup dialog template in the EXE, loads it
            into a handle, and returns the handle.

  Returns:  Nothing.

  Comments:

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

HANDLE GetSetupDlgHandle(void)
{
  hResPrint = FindResource(hInst, TEXT("prtemp2"), RT_DIALOG) ;

  hDialogPrint = LoadResource(hInst, hResPrint) ;

  return hDialogPrint ;
}








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

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

  Purpose:  A callback function that will receive messages intended for
            the PrintDlg() dialog boxes before the normal common dialog
            routine receives them.


  Returns:  FALSE to allow the common dialogs to process the message
            with its normal logic.  TRUE to discard the message.

  Comments:

     To enable this function for the Print dialog in CDTEST, enter the
     value for PD_ENABLEPRINTHOOK in the "Flags" edit box.

     To enable this function for the Setup dialog in CDTEST, enter the
     value for (PD_ENABLESETUPHOOK | PD_PRINTSETUP) in the "Flags" edit box.

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

UINT APIENTRY PrintHookProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
  LPPRINTDLG pPr ;
  TCHAR szMsg[50] ;

  switch(msg)
  {
    case WM_INITDIALOG:

      pPr = (LPPRINTDLG) lParam ;

      if (pPr->lCustData != 0)
      {
        wsprintf(szMsg, TEXT("PRINTDLG->lCustData is: %ld"), pPr->lCustData) ;

        MessageBox(hwnd, szMsg, TEXT("lCustData Sent!"), MB_OK | MB_APPLMODAL) ;
      }

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

      break ;

    /* use the WM_CTLCOLOR* messages to change the color of the Open
       dialog */

    case WM_CTLCOLORDLG:

        if (!hBrushDlg)
            hBrushDlg = GetStockObject(LTGRAY_BRUSH) ;

        return (UINT) hBrushDlg ;

        break ;


    case WM_CTLCOLORBTN:

        SetBkMode((HDC) wParam, TRANSPARENT) ;   //sets background color
                                                 //for push and check box
                                                 //buttons...

        if (!hBrushButton)
            hBrushButton = GetStockObject(LTGRAY_BRUSH) ;

        return (UINT) hBrushButton ;

        break ;


    case WM_CTLCOLORSTATIC:

        SetTextColor((HDC) wParam, RGB(0x00, 0xff, 0x00)) ;  //green
        SetBkMode((HDC) wParam, TRANSPARENT) ;               //transparent text

        if (!hBrushDlg)
            hBrushDlg = GetStockObject(LTGRAY_BRUSH) ;

        return (UINT) hBrushDlg ;

        break ;


    default:
      break ;
  }

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








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

  Function: PrintMultiProc1(LPDWORD)

  Purpose:  Is the starting address for the first new thread when
            multithreading.

  Returns:  Any DWORD value.

  Comments:
            The new thread will start executing here and will end when
            the PrintDlg() function returns and it has posted a message
            to the CDTEST's print dialog window saying that one of the
            two multithreading dialogs been terminated.

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

DWORD PrintMultiProc1(LPDWORD pdw)
{
  GetPrintDlg(hwndMainPrint, &pdThread1) ;

  DoPrintDlgStuff(hwndMainPrint, &pdThread1) ;

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

  return 0L ;
}









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

  Function: PrintMultiProc2(LPDWORD)

  Purpose:  Is the starting address for the second new thread when
            multithreading.

  Returns:  Any DWORD value.

  Comments:
            The new thread will start executing here and will end when
            the PrintDlg() function returns and it has posted a message
            to the CDTEST's print dialog window saying that one of the
            two multithreading dialogs been terminated.

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

DWORD PrintMultiProc2(LPDWORD pdw)
{
  GetPrintDlg(hwndMainPrint, &pdThread2) ;

  DoPrintDlgStuff(hwndMainPrint, &pdThread2) ;

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

  return 0L ;
}








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

  Function: MultiThreadPrintDlg(void)

  Purpose:  Is the starting address for the first new thread when
            multithreading.

  Returns:  Any DWORD value.

  Comments:
            The new thread will start executing here and will end when
            the PrintDlg() function returns and it has posted a message
            to the CDTEST's print dialog window saying that one of the
            two multithreading dialogs been terminated.

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

void MultiThreadPrintDlg(void)
{

  dwPrintThreadParm1 = dwPrintThreadParm2 = 0L ;

  if (!(hPrintThread1 = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0,
                                     (LPTHREAD_START_ROUTINE) PrintMultiProc1,
                                     &dwPrintThreadParm1, CREATE_SUSPENDED, &dwPrintThreadID1)))

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

    nOpenDialogCount = 0 ;

    EnablePrintControls(hwndMainPrint, TRUE) ;

    return ;
  }


  if (!(hPrintThread2 = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0,
                                     (LPTHREAD_START_ROUTINE) PrintMultiProc2,
                                     &dwPrintThreadParm2, CREATE_SUSPENDED, &dwPrintThreadID2)))
  {
    MessageBox(GetForegroundWindow(), TEXT("Error creating thread 2"), NULL,
               MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL) ;

    nOpenDialogCount = 0 ;

    EnablePrintControls(hwndMainPrint, TRUE) ;

    return ;
  }

  ResumeThread(hPrintThread1) ;

  ResumeThread(hPrintThread2) ;

  return ;
}







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

  Function: EnablePrintControls(HWND, BOOL)

  Purpose:  Enable or disable CDTEST's print dialog's controls.

  Returns:  Nothing.

  Comments: This is necessary when CDTEST is multithreading.

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

void EnablePrintControls(HWND hwnd, BOOL bEnable)
{
  EnableWindow(GetDlgItem(hwnd, IDOK), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, IDCANCEL), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, ID_RESETPRINT), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, ID_MULTITHREADPRINT), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, ID_EDITDEVMODE), bEnable) ;
  EnableWindow(GetDlgItem(hwnd, ID_EDITDEVNAMES), bEnable) ;
}






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

  Function: DoPrintDlgStuff(HWND, LPPRINTDLG)

  Purpose:  Calls PrintDlg() with the correct parameters.

  Returns:  Nothing.

  Comments:

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


void DoPrintDlgStuff(HWND hwnd, LPPRINTDLG ppd)
{
  BOOL bRet = FALSE ;


  /* Figure out how the user want's to call PrintDlg() */

  if (IsDlgButtonChecked(hwnd, ID_PREPRINTP) == 1)
    ppd->hPrintTemplate = GetPrintDlgHandle() ;

  if (IsDlgButtonChecked(hwnd, ID_PRESETUPP) == 1)
    ppd->hSetupTemplate = GetSetupDlgHandle() ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hPrintTemplate) ;
  SetDlgItemText(hwnd, ID_HPRINTTEMPP, szTemp) ;

  wsprintf(szTemp, szLongFilter, (DWORD) ppd->hSetupTemplate) ;
  SetDlgItemText(hwnd, ID_HSETUPTEMPP, szTemp) ;



  /* Call the function */

  if (IsDlgButtonChecked(hwnd, ID_NULLSTRUCTP) == 1)
    bRet = PrintDlg((LPPRINTDLG) NULL) ;
  else
    bRet = PrintDlg(ppd) ;



  /* Clean up and show results */

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

  SetDlgItemInt(hwnd, ID_RETURNP, bRet, TRUE) ;

  if (hDialogPrint)
  {
    FreeResource(hDialogPrint) ; //obsolete call, but
    hDialogPrint = (HANDLE) 0 ;  //it's possible that this
    hResPrint = (HANDLE) 0 ;    //might be recompiled for win 3.x
  }

  pd.hDevMode = ppd->hDevMode ;    //need to fix this so that FillDevnamesDlg()
  pd.hDevNames = ppd->hDevNames ;  //and FillDevmodeDlg() work...

  FillPrintDlg(hwnd, ppd) ;

  if (ppd->hDC)  //release the HDC after its value is
                 //returned to the test app
  {
    ReleaseDC(ppd->hwndOwner, ppd->hDC) ;
    ppd->hDC = (HDC) 0 ;
  }
}
