/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = config.c
 *
 * DESCRIPTIVE NAME = Contains printer configuration routines.
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS  - DeviceModes
 *            -
 *            -
 *            -
 *            -
 *            -
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define  INCL_WINHELP        
#define  INCL_DOSPROCESS     
#define  INCL_WINHOOKS       
#define  INCL_DOSMODULEMGR   
#define  INCL_DOSMISC
#define  INCL_DOSFILEMGR
#define  INCL_DEV
#define  INCL_WIN
#define  INCL_PM
#define  INCL_DOSRESOURCES
#define  INCL_SPLFSE  /*            */
#include <os2.h>
#define  INCL_TKTP
#include <os2p.h>
#include <bseerr.h>
#include <pmwinx.h>
#include <string.h>
#include <stdlib.h>
#include "inc\ppdialog.h"
#include "inc\config.h"
#include "inc\dlgproc.h"
#include "inc\pspagtun.h"              /* V2.174057   Page Tuning */
#define  INCL_GENPLIB_ERROR
#define  INCL_GENPLIB_MEMORY
#include <genplib.h>

#ifdef   NOT_YET
   #include <comsub.h>
#endif

extern PBYTE StringTable[MAX_STRINGS];
extern PVOID pProcessHeap;
extern LONG DefaultFontCount( PDESPPD );  /*            */
/*            */
extern LONG ProfileAllocStringQuery( HINI, PSZ, PSZ, PSZ, PPVOID );
extern INT  _Optlink CompareRealNames( PSZ, PSZ ); /*            */

#if      DEBUG
  extern VOID   PerformRip(PSZ pszErrorText);
  #define  RIP(Text)     PerformRip((PSZ) Text)
#else
   #define  RIP(Text)
#endif

#define  DPDM_USERPROPERTIES 3
CHAR szErr[80] = " ";        /* string in which to get err code             */
PCHAR rgchIn[MAX_INPUT] =
{
  NULL
} ;
                             /* input file names pointer list               */

/*
**  Keywords defined for retrieving information from os2.ini and writing
**  information to os2.ini
*/

/*
** default printer name to be used if nothing else specified in os2.ini
*/
CHAR szDefPrinter[MAX_FNAMESIZE] = "init";

/*
**  the keyword under which printer name is stored
*/
CHAR szKeyPrintName[] = "PRINTER";

/*
**  the keyword under which orientation is stored
*/
CHAR szKeyOrientName[] = "ORIENTATION";

/*
**  the keyword under which papertype is stored
*/
CHAR szKeyPaperName[] = "PAPERTYPE";
CHAR szKeyFormName[] = "PAPERSOURCE";/* the input paper tray keyword        */

/*
**  a keyword defined to lay down user defined forms mapping
*/
CHAR szKeyUserformName[] = "USERFORMS";
CHAR szKeyFontName[] = "FONTNAME";/* the font name keyword                  */
CHAR szKeyOrder[] = "OUTPUTORDER";/* the order name keyword                 */

/*
**  output printing effects stored under this word
*/
CHAR szKeyEffects[] = "EFFECTS";

/*
**           
*/
CHAR szFontMemPS1[] = "%!PS\nsave /s 20 string def /Courier findfont 12 "
                      "scalefont setfont 72 600 moveto \n(";
                     /*Available Font Memory (bytes)*/
CHAR szFontMemPS2[] = " = ) show \nvmstatus exch sub dup s cvs show "
                      "72 550 moveto (";
                    /*Suggested fonts*/
CHAR szFontMemPS3[] = ": ) show \n100000 sub 80000 div round cvi s cvs show "
                      "showpage pop restore \x04";

/*
** OSDD DCR 1476 - Integrate 1.2 Help Manager
*/
/*
** Integrate 1.2 Help Manager
*/

#define  VQMAXMSGSTRING 256  /* Maximum msg box string length               */
#define  RES_FLAG      0xFFFF0000
#define  HELPFILENAME  "\\PSCRIPT.HLP"
BOOL HelpStubHookIsSet = FALSE;/* for new help                              */
HWND hwndHelp;
BOOL HelpAlreadyInitialized = FALSE;/* for new help                         */
CHAR szHelpTitle[VQMAXMSGSTRING+1];
HWND hwndMain = 0;

/*
** HELPINIT -- help manager initialization structure
*/
HELPINIT hi;

#define  DEFAULT_QUEUE_SIZE 512
ULONG EXPENTRY PrinterPropDialog(HWND,SHORT,MPARAM,MPARAM);
ULONG EXPENTRY JobPropDialog(HWND,SHORT,MPARAM,MPARAM);
ULONG EXPENTRY SetupProc(HWND,SHORT,MPARAM,MPARAM);
ULONG PostMsgBox(HMODULE,SHORT,SHORT,SHORT);
ULONG EXPENTRY OptionsDialog(HWND,SHORT,MPARAM,MPARAM);
BOOL   sznIsEqual(PSZ,PSZ);
VOID   szNewCopy(PSZ,PSZ,SHORT);
SHORT   szDlmCopy(PSZ,PSZ,SHORT);
BOOL LoadPrintSegment(HWND,PB  *,PSIGNATURE,PCHAR,PVOID,SHORT);
BOOL CheckNumeric(HWND,PSZ);
BOOL ValidFilename(PSZ);
VOID ReadPaperName(HWND,SHORT,PCNFDATA);
VOID QueryUserForm(PCNFDATA);
SHORT DialogDispatch(PB  *);
VOID FreeAll(PB  *apResources);
MRESULT EXPENTRY SFDialog(HWND,SHORT,MPARAM,MPARAM);

/*
** OSDD DCR 1476 - Integrate 1.2 Help Manager
*/
/*
** Integrate 1.2 Help Manager
*/
VOID EXPENTRY InitializeHelp(VOID);
BOOL EXPENTRY SetHelpStubHook(VOID);
VOID EXPENTRY ReleaseHelpStubHook(VOID);
VOID EXPENTRY CleanUpHelpStubHook(SHORT);
INT EXPENTRY HelpStubHook(HAB,SHORT,SHORT,SHORT,PRECTL);
PSZ  get_module_dir(PSZ);
BOOL  HelpErrorFilter(ULONG,PSZ);

PFNDHI  pfnWinDestroyHelpInstance;
PFNAHI  pfnWinAssociateHelpInstance;
PFNCHI  pfnWinCreateHelpInstance;
/* BOOL(APIENTRY *pfnWinDestroyHelpInstance)(HWND hwndHelpInstance)
  = NULL;
  HWND(APIENTRY *pfnWinCreateHelpInstance)(HAB hab,PHELPINIT
                                            phinitHMInitStructure)
  = NULL;
  BOOL(APIENTRY *pfnWinAssociateHelpInstance)(HWND hwndHelpInstance,HWND
                                               hwndApp)
  = NULL; */

BOOL LoadInfoSegment(PB  *);
extern void CxDiToPtr(CHAR  *);
extern HMODULE pscript_module;       /* memory.c                                    */
VOID PrintFontMem (PCNFDATA);

/***************************************************************************
 *
 * FUNCTION NAME = DeviceModes
 *
 * DESCRIPTION   = This routine is called from OS2_PM_DRV_DEVMODE to open
 *                 printer descriptor resources, display dialog boxes and
 *                 other related things.
 *
 * INPUT         = pszDevice -  primary key or device name
 *                 pcnfData  -  Pointer to printer configuration data
 *                 uOptions  -  The action tobe taken flags
 *
 * OUTPUT        = SHORT
 *
 * RETURN-NORMAL = ?? SUCCESS
 * RETURN-ERROR  = DPDM_ERROR
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

VOID SaveLocalCallDlg( HWND hWnd, PFNWP DlgProc, SHORT DlgID, PCH DlgData );
SHORT DeviceModes( PSZ pszDevice, PCNFDATA pcnfData, SHORT uOptions)
  /*
  **  PSZ pszDevice;      - primary key or device name
  **  PCNFDATA pcnfData;  - Pointer to printer configuration data
  **  SHORT uOptions;    - The action tobe taken flags
  */
{
  SHORT   i;
  CNFDATA cnfLocal;

  /*
  **  array of pointers to store process context items. The last element
  **  contains pointer to a local instance of configuration data.
  */
  PB apResources[IMAXRES + 1];

  /*
  ** initialize the array to NULL
  */
  for (i = 0; i < IMAXRES; i++)
  {
    apResources[i] = NULL;
  }
  apResources[LCLRES] = (PB) &cnfLocal;
  pcnfData->lGetPtr = 0;
  apResources[CNFRES] = (PB) pcnfData;

  /*
  **  call off to the dialog dispatcher, which decides which dialogs to
  **  display.
  */
  if ((i = DialogDispatch( apResources )) == DPDM_ERROR)
  {
    RIP( "DeviceModes:  Can't create dialog boxes" );
    goto DM_error;
  }

  /*
  **  free the memory.
  */
  FreeAll( apResources );
  return ( i );

DM_error:

  GplErrSetError(  PMERR_BASE_ERROR );
  return( (SHORT) DPDM_ERROR );
}

/***************************************************************************
 *
 * FUNCTION NAME = DialogDispatch
 *
 * DESCRIPTION   = Initializes dialog interface code and opens the first
 *                 dialog box whereby the printer info segment is chosen.
 *
 * INPUT         = PB  *apResources -pointer to list of printer resources
 *
 * OUTPUT        = SHORT ( pcnfData->uSaveOptions )
 *
 * RETURN-NORMAL = TRUE if         initialization is successful otherwise FALSE.
 * RETURN-ERROR  = DEV_OK
 *                                                                    
 *
 ****************************************************************************/

SHORT DialogDispatch( PB *apResources )
  /*
  **  PB  *    apResources;         pointer to list of printer resources
  */
{
  /*
  **  pointer to printer configuration data
  */
  PCNFDATA pcnfData;
  HWND     hWnd, hWndTop;
  HENUM    henum;
  /*
  **  pass three global structures to the dialogs
  */
  PVOID avp[5];

  /*
  **  get a local pointer to configuration data.
  */
  pcnfData = (PCNFDATA) apResources[CNFRES];

  /*
  ** get the handle of the topmost window so application modal behaviour is
  ** maintained.
  */
  hWndTop = HWND_DESKTOP;
  henum = WinBeginEnumWindows( HWND_DESKTOP );

  if (hWnd = WinGetNextWindow( henum))
  {
    hWndTop = hWnd;
  }

  WinEndEnumWindows( henum );

  /*
  **  initialize the default printer if it has not yet been done.
  */
  if (sznIsEqual((PSZ)szDefPrinter, (PSZ)"init"))
  {
    szNewCopy( (PSZ) szDefPrinter, (PSZ)StringTable[IDS_Generic-STRING_BASE],
               (SHORT) sizeof(szDefPrinter) );
  }

  /*
  ** depending on which options are set, dispatch off to the
  ** print properties dialog box, the job properties dialog box, or
  ** just retrieve the configuration data from the resources and
  ** return.
  */
  avp[0] = apResources;

  if (pcnfData->uSaveOptions == DPDM_CHANGEPROP)
  {
    hwndMain = (HWND) WinLoadDlg( HWND_DESKTOP, hWndTop,
               (PFNWP) PrinterPropDialog, (HMODULE)pcnfData->hmod, DLG_PRCONFIG, (PCH)avp );
    WinProcessDlg( hwndMain );
    WinDestroyWindow( hwndMain );
  }
  else if (pcnfData->uSaveOptions == DPDM_POSTJOBPROP || pcnfData->uSaveOptions
           == DPDM_USERPROPERTIES)
  {
    hwndMain = (HWND)WinLoadDlg( HWND_DESKTOP, hWndTop, (PFNWP) JobPropDialog,
               (HMODULE) pcnfData->hmod, DLG_JOBPROP, (PCH)avp );
    WinProcessDlg( hwndMain );
    WinDestroyWindow( hwndMain );
  }
  else
  {
    /*           
    ** Load the ppd data first
    */
    pcnfData->lGetPtr = 0;  /* Get the printer stuff                   */
    LoadInfoSegment( (PB *)apResources );

    ReadProfile( apResources );

    /*
    **  Only to read from os2.ini and return this info
    */
    return( DEV_OK );
  }

  /*
  ** in either of the cases where we dispatched off to dialog boxes,
  ** pcnfData->uSaveOptions returns whether the user pressed OK or Cancel.
  */

  return( pcnfData->uSaveOptions );
}

/***************************************************************************
 *
 * FUNCTION NAME = SaveLocalCallDlg
 *
 * DESCRIPTION   = This routine assists the PostScript Printer Properities
 *                 dialog box.  This routine will cause the display of the
 *                 Job Properties dialog and it's main purpose if to keep the
 *                 stack of PrinterPropDialog small the CNFDATA data structure
 *                 we need to make a copy of here is fairly large, so I placed
 *                 it in here as opposed to the auto stack of
 *                 PrinterPropDialog.  Now it's only used if needed, what a
 *                 bonus it would be to have a smarter compiler so this
 *                 wouldn't be necessary.
 *
 * INPUT         =HWND hWnd
 *                PFNWP DlgProc
 *                SHORT DlgID
 *                PCH DlgData
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *                                                                    
 *
 ****************************************************************************/

VOID SaveLocalCallDlg( HWND hWnd, PFNWP DlgProc, SHORT DlgID, PCH DlgData )
{
  PVOID    *avp;
  /*
  **  list of ptrs to printer configure resources
  */
  PB       *apResources;
  PCNFDATA  pcnfData;         /* pointer to printer configuration            */
  PCNFDATA  pcnfLocal;        /* pointer to printer configuration            */
  CNFDATA   cfnTempCfg;        /* copy of printer configuration               */

  avp = (PVOID) WinQueryWindowULong( hWnd, QWL_USER );
  apResources = avp[0];
  pcnfData = (PCNFDATA) apResources[CNFRES];
  pcnfLocal = (PCNFDATA) apResources[LCLRES];

  /*
  **  transfer to local copy.
  */
  cfnTempCfg = *(PCNFDATA) pcnfLocal;
  WinDlgBox( HWND_DESKTOP, hWnd, (PFNWP) DlgProc, (HMODULE) pcnfData->hmod, DlgID,
             (PCH) DlgData );

  /*
  **  restore local copy
  */
  *pcnfLocal = cfnTempCfg;
}

/***************************************************************************
 *
 * FUNCTION NAME = PrinterPropDialog
 *
 * DESCRIPTION   = This routine accompanies the PostScript Printer
 *                 Properities dialog box.  This routine displays list boxes
 *                 with the printer models, paper trays, and form types.
 *                 It also allows access to the job properties dialog box.
 *
 * INPUT         = HWND hWnd
 *                 SHORT  uMsg
 *                 MPARAM  mp1, mp2
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *                                                                
 *                                                                
 *                                                                
 *
 ****************************************************************************/

ULONG EXPENTRY PrinterPropDialog( HWND hWnd, SHORT uMsg, MPARAM mp1, MPARAM mp2 )
{
  SHORT     i, shItems;
  /*
  ** list of ptrs to printer config resources
  */
  PB       *apResources;
  PCNFDATA  pcnfData;         /* pointer to printer configuration            */
  PCNFDATA  pcnfLocal;        /* pointer to printer configuration            */
  /*
  ** A temp variable to get child window handle
  */
  HWND      hWnd1;
  SHORT     mi,mi2;
  SHORT     idTemp;
  CHAR      szBuffer[MAX_PSIZE];  /* a scratch buffer to read edit fields     */
  CHAR      szLocalForm[MAX_PSIZE];
  ULONG     ulReturn;
  PVOID    *avp;
  LONG      spareLONG;
  PDESPPD   pdesPpd;           /*            */

  switch (uMsg)
  {
  /*            */
  case WM_CLOSE:
       /*
       ** The OK button ID already contains code to save the current data.
       ** Rather than duplicate the code, simply call MBID_OK since the
       ** processing for both messages is the same.
       */
       WinSendMsg( hWnd, WM_COMMAND, (MPARAM) MBID_OK, (MPARAM) 0 );
       break;

  case WM_COMMAND:
       /*
       ** retrieve the address of our resources, so we can get
       ** access to our configuration data.
       */
       avp = (PVOID) WinQueryWindowULong( hWnd, QWL_USER );
       apResources = avp[0];
       pcnfData = (PCNFDATA) apResources[CNFRES];
       pcnfLocal = (PCNFDATA) apResources[LCLRES];

       /*
       ** mp1 tells what option the user selected in the printer
       ** properties dialog box.
       */
       switch (LOUSHORT( mp1 ))
       {
       case PUSH_FORMS:
            /*
            ** the user has selected the Define Forms button.  pop up
            ** the define forms dialog box, allow the user to set
            ** whatever options he wants, then save them.
            */
            SaveLocalCallDlg( hWnd, (PFNWP) SetupProc, DLG_FORMS,
                              (PCH) apResources );

            /*
            **  WinDlgBox(HWND_DESKTOP,hWnd,(PFNWP)SetupProc,
            **            (HMODULE)pcnfData->hmod,DLG_FORMS,
            **            (PCH)apResources);
            */
            /*
            **  save the user's options.
            */
            FillPaperList( hWnd, (PB *) apResources );
            break;

       case PUSH_DELETE:
            /*
            ** the user wishes to delete one of the user defined
            ** forms.  start off by getting the list of the
            ** currently defined forms.
            */
            /*
            **  get the sub window id.
            */
            hWnd1 = WinWindowFromID( hWnd, LIST_PAPER );

            /*
            **  get the index of the selected item.
            */
            mi2 = (SHORT) WinSendMsg( hWnd1, LM_QUERYSELECTION, (MPARAM) 0L,
                                      (MPARAM) 0L);

            /*
            ** get the form name and store it in the printer
            ** configuration data.
            */
            WinSendMsg( hWnd1, LM_QUERYITEMTEXT, MPFROM2SHORT( mi2, MAX_PSIZE ),
                        (MPARAM) szLocalForm );

            /*
            ** check the form name just selected by the user.  if it is the
            ** current default form, we should not let them delete it.
            */
            /*            */
            if ( ! CompareRealNames( (PSZ) pcnfData->jobProperties.szFormName,
                            (PSZ) szLocalForm ))
            {
              PostMsgBox( (HMODULE) pcnfData->hmod, (SHORT) 0, IDM_CantDelCurrent,
                          MB_OK | MB_ICONEXCLAMATION );
              break;
            }

            /*
            ** let's make sure the user really wants to delete
            ** this form.
            */
            ulReturn = PostMsgBox( (HMODULE) pcnfData->hmod, (SHORT) 0,
                                   IDM_VerifyDelForm, MB_YESNO | MB_ICONQUESTION);

            /*
            ** if the user does not want to delete the form,
            ** then we must leave now.
            */
            if (ulReturn == (LONG) MBID_NO)
            {
              break;
            }

            /*
            ** we have a valid form name.  copy it into the
            ** configuration data.
            */
            szNewCopy( (PSZ) pcnfData->jobProperties.szFormName, (PSZ) szLocalForm,
                       sizeof( pcnfData->jobProperties.szFormName ));

            /*
            ** remove this form name from the list of defined forms.
            ** this is done by passing NULL to AddToIni as the
            ** pszformsize parameter.   Then update the list of
            ** defined form names.
            */
            if (AddToIni( hWnd, (PSZ) pcnfData->jobProperties.szFormName,
                          (PSZ) NULL, (PCNFDATA) pcnfData))
            {
              FillPaperList(hWnd, (PB  *)apResources);
            }
            break;

       case PUSH_JOBPROP:

            /*
            ** the user has selected the Job Properties button.
            ** we must pop up the Job Properties dialog box so
            ** the user can select job specific properties.
            */
            SaveLocalCallDlg( hWnd, (PFNWP) JobPropDialog, DLG_JOBPROP, (PCH) avp);

            /*
            ** WinDlgBox(HWND_DESKTOP,hWnd,(PFNWP)JobPropDialog,
            **           (HMODULE)pcnfData->hmod,DLG_JOBPROP,(PCH)avp);
            */
            /*
            ** set the default back to the OK button, then put
            ** the focus there.  this is done for consistancy
            ** between dialog boxes.  basically, we want the user
            ** to be able to hit carriage returns to exit each
            ** dialog box, while saving any changes made.
            */
            WinSendDlgItemMsg( hWnd, PUSH_JOBPROP, BM_SETDEFAULT,
                               (MPARAM) MPFROMSHORT( FALSE ), (MPARAM) 0L);
            WinSendDlgItemMsg( hWnd, MBID_OK, BM_SETDEFAULT,
                               (MPARAM) MPFROMSHORT( TRUE ), (MPARAM) 0L);
            WinSetFocus( HWND_DESKTOP, WinWindowFromID( hWnd, MBID_OK ));
            break;

       case PUSH_SOFTFONT:
            /*
            ** the user has selected the Font Installer button.
            ** we must pop up the Font Installer dialog box so
            ** the user can add or delet fonts.
            */
            /*
            **           
            ** If under Ver 2.1 or greater the system will handle the fonts.
            */
            PostMsgBox( (HMODULE) pcnfData->hmod, (USHORT) 0, IDM_UseSystemFonts,
                        MB_OK | MB_NOICON );

            /*
            ** SaveLocalCallDlg not needed here since SFDialog
            ** doesn't use the pcfnLocal data
            */
            /*
            ******* WinDlgBox(HWND_DESKTOP, hWnd, (PFNWP)SFDialog, (HMODULE)
            */
            /*
            ********** pcnfData->hmod, DLG_SOFTFONT, 0L);
            */
            /*
            ** set the default back to the OK button, then put
            ** the focus there.  this is done for consistancy
            ** between dialog boxes.  basically, we want the user
            ** to be able to hit carriage returns to exit each
            ** dialog box, while saving any changes made.
            */
            WinSetFocus( HWND_DESKTOP, WinWindowFromID( hWnd, MBID_OK ));
            break;

       case PUSH_FONT_DEFAULT:
            /*            */
            /*
            ** If this button is pressed, set the current downloaded fonts
            ** to the default value.
            */
            pdesPpd = (PDESPPD) apResources[PPDRES];  /* point to ppd info */

            pcnfData->lFontCount = DefaultFontCount( pdesPpd );

            WinSendDlgItemMsg( hWnd, SPIN_MAX_FONTS, SPBM_SETCURRENTVALUE,
                               (MPARAM) pcnfData->lFontCount, (MPARAM) 0 );
            break;

       case IDP_PRINT_FONT_CAPACITY:
            PrintFontMem( pcnfData );
            break;

       case MBID_OK:
            /*            */
            /*
            ** Since OK was pressed, retrieve the value for the
            ** additional memory.  SPBQ_ALWAYSUPDATE means to to
            ** retrieve the value, even if ulAdditionalMem is equal
            ** to the value in the spin button.
            */
            WinSendDlgItemMsg( hWnd, SPIN_MAX_FONTS, SPBM_QUERYVALUE,
                               (MPARAM) &pcnfData->lFontCount,
                               MPFROM2SHORT( 0, SPBQ_ALWAYSUPDATE ));

            /*
            ** the user has selected the OK button.  it is now time
            ** to save all changes made to this point.
            */
            WrtQueryProfile( hWnd, (PB *) apResources );

            /*
            **  uSaveOptions is used as a return value holder.
            */
            pcnfData->uSaveOptions = DEV_OK;
            pcnfData->lVersion = DRIVERSION;

            /*
            **  destroy the help window if it exists.
            */
            /*
            **  DCR 1476          HlpDestroy((HHELP)pcnfData->uHelp);
            */
            /*
            **  if we have a help instance destroy it.  DCR 1476
            */
            WinAssociateHelpInstance( (HWND)NULL, WinQueryActiveWindow( HWND_DESKTOP ));

            ReleaseHelpStubHook( );     /* Release hook */
            if (HelpAlreadyInitialized)
            {
              WinDestroyHelpInstance( hwndHelp );
              hwndHelp = (HWND) NULL;
              HelpAlreadyInitialized = FALSE;
            }

            /*
            **  dismiss the dialog.
            */
            WinDismissDlg( hWnd, TRUE );
            break;

       case MBID_CANCEL:
            /*
            **  the user has selected the cancel button.  we do not
            **  want to save anything.  just return DPDM_NONE and
            **  destroy the help window if it exists.
            */
            /*
            **  transfer to local copy.
            */
            *pcnfData = *(PCNFDATA) pcnfLocal;

            /*
            ** this is done to make sure the ini get
            ** written just after an install scenario
            ** where the user installs, but hits ESC before
            ** any info makes it to the ini
            */
            WrtQueryProfile( hWnd, (PB *) apResources );
            pcnfData->uSaveOptions = DPDM_NONE;

            /*
            **  DCR 1476          HlpDestroy((HHELP)pcnfData->uHelp);
            */
            /*
            **  if we have a help instance destroy it.  DCR 1476
            */
            WinAssociateHelpInstance( (HWND) NULL, WinQueryActiveWindow( HWND_DESKTOP ));

            ReleaseHelpStubHook( );   /* Release hook */
            if (HelpAlreadyInitialized)
            {
              WinDestroyHelpInstance( hwndHelp );
              hwndHelp = (HWND) NULL;
              HelpAlreadyInitialized = FALSE;
            }

            /*
            **  dismiss the dialog.
            */
            WinDismissDlg( hWnd, TRUE );
            break;

       default:
            /*
            **  in case something went wrong, do nothing.
            */
            break;
       }
       break;                 /* WM_COMMAND.                                 */

  case WM_CONTROL:
       /*
       ** retrieve the address of our resources, so we can get
       ** access to our configuration data.
       */
       avp = (PVOID) WinQueryWindowULong( hWnd, QWL_USER );
       apResources = avp[0];
       pcnfData = (PCNFDATA) apResources[CNFRES];

       /*
       ** mp1 tells what option the user selected in the printer
       ** properties dialog box.
       */
       switch (LOUSHORT( mp1 ))
       {
       case LIST_TRAY:
            if (HIUSHORT(mp1) == LN_SELECT)
            {
              /*
              ** the user has selected one of the trays from the
              ** paper tray list box.
              */
              /*
              **  get the paper tray list box sub window id.
              */
              hWnd1 = WinWindowFromID( hWnd, LIST_TRAY );

              /*
              **  get the index of the selected paper tray.
              */
              mi = (SHORT) WinSendMsg( hWnd1, LM_QUERYSELECTION, (MPARAM) 0L,
                                       (MPARAM) 0L);

              /*
              ** highlight the selected paper tray, and get the
              ** name of the selected tray so the loaded paper
              ** name can be displayed.
              */
              WinSendMsg( hWnd1, LM_SELECTITEM, (MPARAM) mi, (MPARAM) TRUE );

              /*
              ** get the form name of the paper store in the
              ** selected paper tray.
              */
              hWnd1 = WinWindowFromID( hWnd, LIST_PAPER );
              ReadPaperName( hWnd1, (SHORT) mi, (PCNFDATA) pcnfData );
            }
            break;

       case LIST_PAPER:
            if (HIUSHORT(mp1) == LN_SELECT)
            {
              /*
              ** the user has selected one of the forms from the
              ** forms list box.
              */
              /*
              **  get the paper tray list box sub window id.
              */
              hWnd1 = WinWindowFromID( hWnd, LIST_TRAY );

              /*
              **  get the index of the currently selected tray.
              */
              mi = (SHORT) WinSendMsg( hWnd1, LM_QUERYSELECTION, (MPARAM) 0L,
                                       (MPARAM) 0L);
              WinSendMsg( hWnd1, LM_SELECTITEM, (MPARAM) mi, (MPARAM) TRUE );

              /*
              **  get the sub window id for the forms list box.
              */
              hWnd1 = WinWindowFromID( hWnd, LIST_PAPER );

              /*
              **  get the index of selected form.
              */
              mi2 = (SHORT) WinSendMsg( hWnd1, LM_QUERYSELECTION, (MPARAM) 0L,
                                        (MPARAM) 0L);

              /*
              ** get the paper name and associate it with the current
              ** paper tray.
              */
              WinSendMsg( hWnd1, LM_QUERYITEMTEXT, MPFROM2SHORT( mi2, MAX_PSIZE ),
                          (MPARAM) szBuffer );

              /*
              ** associate the selected form name with the currently
              ** selected paper tray.
              */
              szNewCopy( (PSZ) &(pcnfData->u.iv.pSourcePaper->szPaperName[mi][0]),
                         (PSZ) szBuffer, MAX_PSIZE );
            }
            break;

       case CHECK_MODESWITCH:
            /*
            **  set the state of the Auto Mode Switching
            */
            if (pcnfData->uPrinterPropFlags & MODESWITCH)
            {
              spareLONG = 0L;  /* Was on - turn off                           */
              pcnfData->uPrinterPropFlags &= ~MODESWITCH;
            }
            else
            {
              spareLONG = 1L;  /* Was off - turn on                           */
              pcnfData->uPrinterPropFlags |= MODESWITCH;
            }
            WinSendDlgItemMsg( hWnd, CHECK_MODESWITCH, BM_SETCHECK,
                               (MPARAM) spareLONG, (MPARAM) 0L);
            break;

       default:
            break;
       }
       break;

  case HM_QUERY_KEYS_HELP:    
       return (ULONG) IDH_KEYS;

  case WM_INITDLG:
       {
         BOOL bRC;

         /*
         ** in this case, we are passed in a pointer to out resources.
         ** from that, we can get out configuration data.
         */
         apResources = ((PVOID *) mp2)[0];
         pcnfData = (PCNFDATA) apResources[CNFRES];
         pcnfLocal = (PCNFDATA) apResources[LCLRES];

         /*
         **  store this data address so it can be retrieved elsewhere.
         */
         if (!WinSetWindowULong( hWnd, QWL_USER, (ULONG) mp2 ))
         {
           break;
         }

         /*
         **           
         ** These controls should be enabled for the system menu.  If these
         ** controls are disabled, there is really no need for a system
         ** menu.  However, remove those menu items that are permanently
         ** disabled.
         */
#if 0
//       /*
//       ** we want to initialize the dialog box such that the
//       ** menu items CLOSE and TASK MANAGER are disabled.
//       */
//       /*
//       **  get the system menu sub window id.
//       */
//       WinSendMsg( hWnd1, MM_SETITEMATTR, MPFROM2SHORT( SC_CLOSE, TRUE ),
//                   MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ));
//       WinSendMsg( hWnd1, MM_SETITEMATTR, MPFROM2SHORT( SC_TASKMANAGER, TRUE ),
//                   MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ));
#endif
         hWnd1 = WinWindowFromID( hWnd, FID_SYSMENU );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_RESTORE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_SIZE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_MINIMIZE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_MAXIMIZE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_HIDE, TRUE ),
                     (MPARAM) 0 );

         /*
         ** initialize high level help by calling HlpInit which is
         ** defined in pmtkt.dll.
         */
         #ifdef   DCR1476
           if ((pcnfData->uHelp = (ULONG)HlpInit((HAB)0L, (HMODULE)pcnfData->hmod,
                hWnd, (PSZ)StringTable[IDS_PostScriptPrn-STRING_BASE], NULL, 0L))
                != NULL)
           {
             HlpRegisterContext((HHELP)pcnfData->uHelp, (HMODULE)pcnfData->hmod,
                IDH_CONTEXT);
           }
         #endif

         /*
         **  get the current printer, as stored in os2sys.ini.
         */
         /*
         **  DCR1399.8 Don't get the key from ini since it is built in code
         **          PrfQueryProfileString(HINI_SYSTEMPROFILE,(PSZ)pcnfData->szKeyApp,
         **                                (PSZ)szKeyPrintName, (PSZ)"",
         **                                (PSZ)pcnfData->szSegName,
         **                                (ULONG)sizeof(pcnfData->szSegName));
         **          szNewCopy( (PSZ)pcnfData->szSegName, (PSZ)pcnfData->szKeyApp,
         **                     sizeof(pcnfData->szSegName) );
         */
         /*
         **  Make sure the memory for resource has been freed from
         **  last time
         */
         FreeAll( apResources );

         /*
         **  Get the printer resources
         */
         pcnfData->lGetPtr = 0;  /* Get the printer stuff                   */

         if ((bRC = LoadInfoSegment((PB  *)apResources)) == FALSE)
         {
           /*
           **  Failure to find printer try  'generic'.
           */
           szNewCopy( (PSZ)pcnfData->szSegName, szDefPrinter,
                      sizeof( pcnfData->szSegName ));

           if ((bRC = LoadInfoSegment((PB *) apResources)) == FALSE)
           {
             RIP( "PrinterPropDialog:  LoadPrintSegment failed." );
           }
         }

         /*
         ** fill in the printer model field.
         */
         WinSetDlgItemText( hWnd, DSPTXT_MODEL, (PSZ) pcnfData->szSegName );

         /*
         **  If loading the printer resource info was OK then read in the
         **  paper tray and form name information for the printer
         */
         if (bRC == TRUE)
         {
           /*
           **  read os2sys.ini and fill the configuration structure.
           **  then fill the paper tray and form name list boxes.
           */
           ReadProfile( (PB *) apResources );
           FillPaperList( hWnd, (PB *)apResources );
         }

         /*            start */
         /*
         ** Set the upper and lower limits of the downloaded fonts
         ** spin button.
         */
         WinSendDlgItemMsg( hWnd, SPIN_MAX_FONTS, SPBM_SETLIMITS,
                            (MPARAM) MAX_DOWN_FONT, (MPARAM) MIN_DOWN_FONT );

         /*
         ** Initialize the additionnal memory spin button to the value in
         ** ulAdditionalMem.
         */
         WinSendDlgItemMsg( hWnd, SPIN_MAX_FONTS, SPBM_SETCURRENTVALUE,
                            (MPARAM) pcnfData->lFontCount, (MPARAM) 0 );
         /*            end */

         /*
         **  get a local copy of configuration data.
         */
         *pcnfLocal = *(PCNFDATA) pcnfData;
       }

       /*
       ** DCR 1476
       ** Initialize help dummy hook - avoid doing WinCreateHelpInstance
       ** until the user presses F1, clicks on a help button or uses our
       ** help menu...
       */
       /*
       ** Initialize help dummy hook - avoid doing WinCreateHelpInstance
       ** until the user presses F1, clicks on a help button or uses our
       ** help menu...
       */
       SetHelpStubHook( );
       break;

  default:
       /*
       ** let the default dialog procedure handle any other action by
       ** the user.
       */
       return ((ULONG) WinDefDlgProc( hWnd, uMsg, mp1, mp2 ));
  }
  return (0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = JobPropDialog
 *
 * DESCRIPTION   = This routine accompanies the PostScript Job Properities
 *                 dialog box.  This routine displays a list boxes with the
 *                 paper form types. It also allows the user to select page
 *                 orientation, scaling, manual feed and color.
 *
 * INPUT         = HWND    hWnd
 *                 SHORT  uMsg
 *                 MPARAM  mp1
 *                 MPARAM  mp2
 *
 * OUTPUT        = ULONG
 *
 * RETURN-NORMAL = 0L,
 *                 (ULONG)WinDefDlgProc(),
 *                 IDH_KEYS
 * RETURN-ERROR  = 1L
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

ULONG EXPENTRY JobPropDialog(HWND hWnd,SHORT uMsg,MPARAM mp1,MPARAM mp2)
{
  SHORT     i, shItems, sScale;
  SHORT     usVersion;
  /*
  ** lst of ptrs to printer config resources
  */
  PB       *apResources;
  PCNFDATA  pcnfData;         /* pointer to printer configuration            */
  PCNFDATA  pcnfLocal;        /* pointer to printer configuration            */
  /*
  ** A temp variable to get child window handle
  */
  HWND      hWnd1;
  SHORT     mi;
  SHORT     idTemp;
  CHAR      szBuffer[MAX_PSIZE];  /* a scratch buffer to read edit fields     */
  PSZ       pszb;
  LONG      spareLONG;
  PVOID    *avp;
  SHORT     Selection;  /*            */


  switch (uMsg)
  {
  /*            */
  case WM_CLOSE:
       /*
       ** The OK button ID already contains code to save the current data.
       ** Rather than duplicate the code, simply call MBID_OK since the
       ** processing for both messages is the same.
       */
       WinSendMsg( hWnd, WM_COMMAND, (MPARAM) MBID_OK, (MPARAM) 0 );
       break;

  case WM_COMMAND:
       /*
       **  retrieve the address of our resources, so we can get
       **  access to our configuration data.
       */
       avp = (PVOID) WinQueryWindowULong( hWnd, QWL_USER );
       apResources = avp[0];
       pcnfData = (PCNFDATA) apResources[CNFRES];/* ptr to prn con data       */
       pcnfLocal = (PCNFDATA) apResources[LCLRES];

       /*
       ** mp1 tells what option the user selected in the job
       ** properties dialog box.
       */
       switch (LOUSHORT(mp1))
       {
       case PUSH_OPTIONS:
            /*
            **  the user has selected the Options button.  pop up
            **  the options dialog box, allow the user to set
            **  whatever options he wants, then save them.
            */
            SaveLocalCallDlg( hWnd, (PFNWP) OptionsDialog, DLG_OPTIONS,
                              (PCH) apResources );

            /*
            ** WinDlgBox(HWND_DESKTOP, hWnd ,(PFNWP)OptionsDialog,
            **          (HMODULE)pcnfData->hmod, DLG_OPTIONS,
            **          (PCH)apResources);
            */
            /*
            **  if output eps disable the landscape button.
            */
            if (pcnfData->iDestnType == ENCAPS)
            {
              /*
              **  disable this particular radio button
              */
              WinEnableWindow( WinWindowFromID( hWnd, RADIO_LAND ), FALSE );
            }
            else
            {
              WinEnableWindow( WinWindowFromID( hWnd, RADIO_LAND ), TRUE );
            }

            /*
            ** set the default back to the OK button, then put
            ** the focus there.
            */
            WinSendDlgItemMsg( hWnd, PUSH_OPTIONS, BM_SETDEFAULT,
                               (MPARAM) MPFROMSHORT( FALSE ), (MPARAM) 0L);
            WinSendDlgItemMsg( hWnd, MBID_OK, BM_SETDEFAULT,
                               (MPARAM) MPFROMSHORT( TRUE ), (MPARAM) 0L);
            WinSetFocus( HWND_DESKTOP, WinWindowFromID( hWnd, MBID_OK ));
            break;

       case MBID_OK:
            /*
            ** the user has selected OK.  this means we will be
            ** exiting the dialog box.  at this point we want to
            ** check the scaling factor for validity.
            */
            /*
            ** get the scaling factor and check to make sure it
            ** is a valid number.  ie all numeric and >= 0.
            */
            WinQueryDlgItemText( hWnd, EDIT_SCALE, sizeof( szBuffer ),
                                 (PSZ) szBuffer );
            pszb = szBuffer;
            sScale = cvi( (PB *) &pszb );

            if (!CheckNumeric(hWnd, (PSZ)szBuffer) || sScale <= 0)
            {
              /*
              **  let the user know the scale factor is bad.
              */
              PostMsgBox( (HMODULE) pcnfData->hmod, (SHORT) 0, IDM_BadScaleFactor,
                          MB_OK | MB_ICONEXCLAMATION );

              /*
              **  set the focus back on the scale edit field,
              */
              /*
              **  prompting the user to make it right.
              */
              WinSendDlgItemMsg( hWnd, EDIT_SCALE, EM_SETSEL,
                                 (MPARAM) MPFROM2SHORT( (SHORT) 0, (SHORT) 3 ),
                                 (MPARAM) 0L);
              ShowCursor( WinWindowFromID( hWnd, EDIT_SCALE ));
              break;
            }

            /*
            **  save the scaling factor in our configuration data.
            */
            pcnfData->jobProperties.uScale = sScale;

            /*
            **  save the return value in uSaveOptons.  destroy
            */
            /*
            ** the help dialog.  get ready to dismiss job
            ** properties dialog box.
            */
            if (pcnfData->uSaveOptions == DPDM_POSTJOBPROP ||
                pcnfData->uSaveOptions == DPDM_USERPROPERTIES )
            {
              /*
              **  DCR 1476              HlpDestroy((HHELP)pcnfData->uHelp);
              */
              /*
              ** if we have a help instance destroy it.  DCR 1476
              */
              WinAssociateHelpInstance( (HWND) NULL, WinQueryActiveWindow( HWND_DESKTOP ));

              ReleaseHelpStubHook( );   /* Release hook */
              if (HelpAlreadyInitialized)
              {
                WinDestroyHelpInstance( hwndHelp );
                hwndHelp = (HWND) NULL;
                HelpAlreadyInitialized = FALSE;
              }
              pcnfData->uSaveOptions = DEV_OK;
            }

            /*           
            ** Retrieve the newly-selected (if any) resolution and store
            ** it in the resolution buffer.  The resolution is stored as
            ** the handle in the drop-down list box.
            */
            if ((Selection = (SHORT) WinSendDlgItemMsg( hWnd, LIST_RESOLUTION,
                             LM_QUERYSELECTION, (MPARAM) LIT_FIRST,
                             (MPARAM) 0)) != LIT_NONE )
            {
               pcnfData->uResolution = (USHORT) WinSendDlgItemMsg (hWnd,
                                       LIST_RESOLUTION, LM_QUERYITEMHANDLE,
                                       (MPARAM) Selection, (MPARAM) 0);
            }

            /*
            ** save the driver version.
            ** then dismiss the dialog box.
            */
            pcnfData->lVersion = DRIVERSION;
            WinDismissDlg( hWnd, TRUE );
            break;

       case MBID_CANCEL:
            /*
            ** the user has selected cancel.  dismiss the dialog
            ** box without saving anything.
            */
            /*
            **  transfer to local copy.
            */
           *pcnfData = *(PCNFDATA) pcnfLocal;

           if (pcnfData->uSaveOptions == DPDM_POSTJOBPROP ||
              pcnfData->uSaveOptions == DPDM_USERPROPERTIES )
           {
             /*
             **  DCR 1476              HlpDestroy((HHELP)pcnfData->uHelp);
             */
             /*
             ** if we have a help instance destroy it.  DCR 1476
             */
             WinAssociateHelpInstance( (HWND) NULL, WinQueryActiveWindow( HWND_DESKTOP ));

             ReleaseHelpStubHook( );    /* Release hook */
             if (HelpAlreadyInitialized)
             {
               WinDestroyHelpInstance( hwndHelp );
               hwndHelp = (HWND) NULL;
               HelpAlreadyInitialized = FALSE;
             }
             pcnfData->uSaveOptions = DPDM_NONE;
           }
           WinDismissDlg( hWnd, TRUE );
           break;

       default:
           break;
       }
       break;                 /* WM_COMMAND.                                 */

  case WM_CONTROL:
       /*
       ** retrieve the address of our resources, so we can get
       ** access to our configuration data.
       */
       avp = (PVOID) WinQueryWindowULong( hWnd, QWL_USER );
       apResources = avp[0];
       pcnfData = (PCNFDATA) apResources[CNFRES];

       /*
       ** mp1 tells what option the user selected in the job
       ** properties dialog box.
       */
       switch (LOUSHORT( mp1 ))
       {
       case RADIO_PORTRAIT:
            /*
            **  the user has selected the PORTRAIT radio button.
            */
            if (HIUSHORT( mp1 ) != BN_CLICKED)
            {
              break;
            }

            /*
            ** if the orientation was LANDSCAPE, de-select the
            ** landscape radio button.
            */
            if (pcnfData->jobProperties.iOrient == LANDSCAPE)
            {
              WinSendDlgItemMsg( hWnd, RADIO_LAND, BM_SETCHECK, (MPARAM) 0L,
                                 (MPARAM) 0L);
            }

            /*
            ** set the orientation to PORTRAIT, and turn on the
            ** radio button.
            */
            pcnfData->jobProperties.iOrient = PORTRAIT;
            WinSendDlgItemMsg( hWnd, RADIO_PORTRAIT, BM_SETCHECK, (MPARAM) 1L,
                               (MPARAM) 0L);
            break;

       case RADIO_LAND:
            /*
            **  the user has selected the LANDSCAPE radio button.
            */
            if (HIUSHORT( mp1 ) != BN_CLICKED)
            {
              break;
            }

            /*
            ** if the orientation was PORTRAIT, de-select the
            ** portrait radio button.
            */
            if (pcnfData->jobProperties.iOrient == PORTRAIT)
            {
              WinSendDlgItemMsg( hWnd, RADIO_PORTRAIT, BM_SETCHECK, (MPARAM) 0L,
                                 (MPARAM) 0L);
            }

            /*
            ** set the orientation to LANDSCAPE, and turn on the
            ** lanscape radio button.
            */
            pcnfData->jobProperties.iOrient = LANDSCAPE;
            WinSendDlgItemMsg( hWnd, RADIO_LAND, BM_SETCHECK, (MPARAM) 1L,
                               (MPARAM) 0L );
            break;

            /*
            **  DCR 1462 add support for duplex option
            */
       case RADIO_ONE_SIDED:
            /*
            **  Make sure duplex_none does not go to duplex_false
            */
            if (pcnfData->sDuplexMode != DUPLEX_NONE)
            {
              pcnfData->sDuplexMode = DUPLEX_FALSE;
            }
            break;

       case RADIO_BOOK:
            pcnfData->sDuplexMode = DUPLEX_DUPLEXNOTUMBLE;
            break;

       case RADIO_FLIP:
            pcnfData->sDuplexMode = DUPLEX_DUPLEXTUMBLE;
            break;

       case LIST_FORMS:
            /*
            **  the user has selected one of the forms for the
            **  current print job.
            */
            if (HIUSHORT(mp1) == LN_SELECT)
            {
              /*
              **  get the sub window id of the forms list box.
              */
              hWnd1 = WinWindowFromID( hWnd, LIST_FORMS );

              /*
              **  get index of the selected form.
              */
              mi = (SHORT) WinSendMsg( hWnd1, LM_QUERYSELECTION, (MPARAM) 0L,
                                       (MPARAM) 0L );

              /*
              **  highlight the selected form in the list box.
              */
              WinSendMsg( hWnd1, LM_SELECTITEM, (MPARAM) mi, (MPARAM) TRUE );

              /*
              ** get the item name.  we now need to match it to
              ** a form size.  queryuserform will check the form
              ** name.  if it is a pre-define form, then the form
              ** size will be the same as the form name.  otherwise,
              ** it will search os2sys.ini for the form size.
              */
              WinSendMsg( hWnd1, LM_QUERYITEMTEXT, MPFROM2SHORT( mi,
                          MAX_FNAMESIZE), (MPARAM) pcnfData->jobProperties.szFormName );
              QueryUserForm( (PCNFDATA) pcnfData );
            }
            break;

       case CHECK_MANUAL:
            /*
            **  set the state of the manual feed check box.
            */
            if ((pcnfData->jobProperties.iManualfeed = 1 -
                 pcnfData->jobProperties.iManualfeed))
            {
              spareLONG = 1L;
            }
            else
            {
              spareLONG = 0L;
            }
            WinSendDlgItemMsg( hWnd, CHECK_MANUAL, BM_SETCHECK,
                               (MPARAM) spareLONG, (MPARAM) 0L);
            break;

       case CHECK_COLOR:
            /*
            **  set the state of the color check box.
            */
            if ((pcnfData->jobProperties.fIsColorDevice =
               !pcnfData->jobProperties.fIsColorDevice))
            {
              spareLONG = 1L;
            }
            else
            {
              spareLONG = 0L;
            }
            WinSendDlgItemMsg( hWnd, CHECK_COLOR, BM_SETCHECK, (MPARAM) spareLONG,
                               (MPARAM) 0L);
            break;

         default:
            break;
       }
       break;                 /* WM_CONTROL.                                 */

  case HM_QUERY_KEYS_HELP:   
       return (ULONG) IDH_KEYS;

  case WM_INITDLG:
       {
         /*
         **           
         ** Initially set to TRUE.
         */
         BOOL bRC = TRUE;

         /*
         ** in this case, we are passed in a pointer to our resources.
         ** from that, we can get out configuration data.
         */
         apResources = ((PVOID *) mp2)[0];
         pcnfData    = (PCNFDATA) apResources[CNFRES];
         pcnfLocal   = (PCNFDATA) apResources[LCLRES];

         /*
         **  store this data addess so it can be retrieved elsewhere.
         */
         if (!WinSetWindowULong( hWnd, QWL_USER, (ULONG) mp2))
         {
           break;
         }

         /*
         **  make a local copy of configuration data.
         */
         *pcnfLocal = *(PCNFDATA) pcnfData;

         /*
         **           
         ** These controls should be enabled for the system menu.  If these
         ** controls are disabled, there is really no need for a system
         ** menu.  However, remove those menu items that are permanently
         ** disabled.
         */
#if 0
//       /*
//       **  we want to initialize the dialog box such that the
//       **  menu items CLOSE and TASK MANAGER are disabled.
//       */
//       /*
//       **  get the system menu sub window id.
//       */
//       WinSendMsg( hWnd1, MM_SETITEMATTR, MPFROM2SHORT( SC_CLOSE, TRUE ),
//                   MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ));
//       WinSendMsg( hWnd1, MM_SETITEMATTR, MPFROM2SHORT( SC_TASKMANAGER, TRUE ),
//                   MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ));
#endif
         hWnd1 = WinWindowFromID( hWnd, FID_SYSMENU );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_RESTORE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_SIZE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_MINIMIZE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_MAXIMIZE, TRUE ),
                     (MPARAM) 0 );
         WinSendMsg( hWnd1, MM_DELETEITEM, MPFROM2SHORT( SC_HIDE, TRUE ),
                     (MPARAM) 0 );

         if (pcnfData->uSaveOptions == DPDM_POSTJOBPROP ||
             pcnfData->uSaveOptions == DPDM_USERPROPERTIES)
         {
           /*
           ** initialize high level help by calling HlpInit which is
           ** defined in pmtkt.dll.
           */
           #ifdef   DCR1476
             if ((pcnfData->uHelp = (ULONG)HlpInit((HAB)0L, (HMODULE)
                pcnfData->hmod, hWnd, (PSZ)StringTable[IDS_PostScriptPrn-
                STRING_BASE], NULL, 0L)) != NULL)
             {
               HlpRegisterContext((HHELP)pcnfData->uHelp, (HMODULE)pcnfData->hmod,
                    IDH_CONTEXT);
             }
           #endif

           /*
           ** DCR 1476
           **  Initialize help dummy hook - avoid doing
           **  WinCreateHelpInstance until the user presses F1, clicks
           **  on a help button or uses our help menu...
           */
           /*
           **  Initialize help dummy hook - avoid doing
           **  WinCreateHelpInstance until the user presses F1, clicks
           **  on a help button or uses our help menu...
           */
           if (HelpStubHookIsSet == FALSE)
           {
             SetHelpStubHook( );
           }

           /*
           **  get the current printer, as stored in os2sys.ini.
           */
           /*
           ** DCR1399.8 Don't get the key from ini since it is built in code
           **              PrfQueryProfileString(HINI_SYSTEMPROFILE,
           **                                    (PSZ)pcnfData->szKeyApp,
           **                                    (PSZ)szKeyPrintName, (PSZ)"",
           **                                    (PSZ)pcnfData->szSegName,
           **                                    (ULONG)sizeof(pcnfData->szSegName));
           **              szNewCopy( (PSZ)pcnfData->szSegName, (PSZ)pcnfData->szKeyApp,
           **                         sizeof(pcnfData->szSegName) );
           */
           /*
           **  Make sure the memory for resource has been freed from
           **  last time
           */
           FreeAll( apResources );

           /*
           **  Get the printer resources
           */
           pcnfData->lGetPtr = 0;   /* Get the printer stuff                */

           if ((bRC = LoadInfoSegment( (PB *)apResources )) == FALSE)
           {
             if (pcnfData->uSaveOptions == DPDM_POSTJOBPROP)
             {
               /*
               **  Failure to find printer try  'generic'.
               */
               szNewCopy( (PSZ) pcnfData->szSegName, szDefPrinter,
                          sizeof( pcnfData->szSegName ));

               if ((bRC = LoadInfoSegment( (PB *) apResources )) == FALSE)
               {
                 RIP( "PrinterPropDialog:  LoadPrintSegment failed." );
               }
             }
           }

           /*
           ** now read in the paper tray and form name information for the
           ** printer saved as the default printer in os2sys.ini.  if no
           ** printer is setup in os2sys.ini, default to 'generic'.
           */
           if (bRC == TRUE && pcnfData->uSaveOptions == DPDM_POSTJOBPROP)
           {
             ReadProfile( (PB *)apResources );
           }
         }

         if (pcnfData->uSaveOptions == DPDM_CHANGEPROP)   /* MFR             */
         {
           WinSetWindowText( hWnd, (PSZ) StringTable[IDS_PRINTER_DEFAULTS -
                             STRING_BASE] );
         }                    /* end if                                      */

         /*
         ** initialize a bunch of dialog box stuff.  it is confusing
         ** as to why filljoblist does all it does.
         */
         /*
         **           
         ** If LoadInfoSegment returns FALSE, this function will trap.
         ** Add a check to prevent this.
         */
         if (bRC == TRUE)
         {
           FillJobList( hWnd, (PB *)apResources );
         }

         if (pcnfData->uSaveOptions == DPDM_POSTJOBPROP)
         {
           *pcnfLocal = *(PCNFDATA)pcnfData;
         }
         return( 1L );       /* to retain the window focus                  */
         break;
       }

    default:
       /*
       ** let the default dialog procedure handle any other action by
       ** the user.
       */
       return ((ULONG) WinDefDlgProc( hWnd, uMsg, mp1, mp2 ));
  }
  return (0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = PostMsgBox
 *
 * DESCRIPTION   = This routine displays a message box of the specified style
 *                 with the specified message, and returns the value returned
 *                 by the message box.
 *
 * INPUT         = HMODULE hMod
 *                 SHORT usReserved
 *                 SHORT usMsgID
 *                 SHORT usStyle
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *                                                                    
 *
 ****************************************************************************/

ULONG PostMsgBox( HMODULE hMod, SHORT usReserved, SHORT usMsgID, SHORT usStyle )
{
  char szMsg[MAX_MESSAGE_SIZE];
  char szCaption[MAX_MESSAGE_SIZE];

  HAB     hAB = (HAB)NULL;
  HMQ     hMQ ;
  MQINFO  mQinfo ;
  ULONG   ulResponse;

  DosBeep( 1200, 80 );
  DosBeep( 700, 80 );

  /*           
  ** Make sure we have a message queue.
  */
  if ( WinQueryQueueInfo( HMQ_CURRENT, &mQinfo, sizeof(MQINFO) ) == FALSE )
  {
    if ( hAB = WinInitialize( 0 ) )
    {
       hMQ = WinCreateMsgQueue( hAB, 0) ;
       WinCancelShutdown( hMQ, TRUE );
    }
  }

  /*
  **  Get caption from message resources
  */
  WinLoadMessage( (HAB) NULL, hMod, (SHORT) IDM_MsgBoxCaption, sizeof( szCaption ),
                  szCaption );
  WinLoadMessage( (HAB) NULL, hMod, usMsgID, sizeof( szMsg ), szMsg );

  ulResponse = (ULONG)WinMessageBox( (HWND) HWND_DESKTOP, (HWND) HWND_DESKTOP,
                       (PSZ) szMsg, (PSZ) szCaption, (SHORT) NULL,
                       (SHORT) (usStyle | MB_SYSTEMMODAL));

  /*           
  ** If we needed to create a msg queue then remove it
  */
  if ( hAB )
  {
    WinDestroyMsgQueue (hMQ) ;
    WinTerminate (hAB) ;
  }

  return ulResponse;
}

/***************************************************************************
 *
 * FUNCTION NAME = FreeAll
 *
 * DESCRIPTION   = This routine frees all memory that has been allocated in
 *                 the course of displaying the dialog boxes.
 *
 * INPUT         = PB  *apResources
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *                                                                    
 *
 ****************************************************************************/

VOID FreeAll( PB  *apResources )
{
  CHAR *pch;

  /*
  ** check each of the pointers; if it is not NULL, free the
  ** segment.
  */
  pch = (PCHAR) apResources[RESBUF];  /* pointer to items buffer         */

  if (pch != NULL)
  {
    /*
    ** DosFreeMem( (PVOID) pch );
    */

    GplMemoryFree( (PVOID) pch );
  }
  pch = NULL;
  pch = (PCHAR) apResources[PPDRES];   /* pointer to items buffer        */

  if (pch != NULL)
  {
    /*
    ** DosFreeMem((PVOID)pch);
    */
    GplMemoryFree( (PVOID) pch );
  }
  pch = NULL;

  /*
  **  reset all the pointers.
  */
  apResources[RESBUF] = (CHAR *) NULL;
  apResources[PPDRES] = (CHAR *) NULL;
  return ;
}

/***************************************************************************
 *
 * FUNCTION NAME = sznIsEqual
 *
 * DESCRIPTION   = Compares two strings.
 *
 * INPUT         = register PSZ psz1
 *                 register PSZ psz2
 *
 *
 * OUTPUT        = TRUE if they are equal
 *                 FALSE if not equal
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *                                                                    
 *
 ****************************************************************************/

BOOL sznIsEqual( register PSZ psz1, register PSZ psz2 )
{
  register CHAR b;

  while ((b = *psz1++) == *psz2++)
  {
    if (!b)
    {
      return( TRUE );
    }
  }
  return( FALSE );
}

/***************************************************************************
 *
 * FUNCTION NAME = szNewCopy
 *
 * DESCRIPTION   = Copies a string from the source to the dest.  If the
 *                 string is null terminated, the copy stops when the
 *                 terminator is hit.  Otherwise, the copy continues for
 *                 the number of bytes passed in.
 *
 * INPUT         = register PSZ pszDst  - Ptr to the destination buffer
 *                 register PSZ pszSrc  - Ptr to the source string
 *                 register SHORT nbDst - Size of the destination buffer
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *                                                                    
 *
 ****************************************************************************/

VOID szNewCopy( register PSZ pszDst, register PSZ pszSrc,
                register SHORT nbDst )
  /*
  **  register PSZ pszDst  - Ptr to the destination buffer
  **  register PSZ pszSrc  - Ptr to the source string
  **  register SHORT nbDst - Size of the destination buffer
  */
{

  while (*pszDst++ = *pszSrc++)
  {
    if (--nbDst <= 0)
    {
      *--pszDst = 0;
      break;
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = szDlmCopy
 *
 * DESCRIPTION   = Copies a string from the source to the dest.  If the
 *                 string is null terminated, the copy stops when the
 *                 terminator is hit.  If the source string hits a semicolon,
 *                 the copy stops.  Otherwise the copy continues for the
 *                 number of bytes passed in.
 *
 * INPUT         = register PSZ pszDst  - Ptr to the destination buffer
 *                 register PSZ pszSrc  - Ptr to the source string
 *                 register SHORT nbDst - Size of the destination buffer
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *                                                                    
 *
 ****************************************************************************/

SHORT szDlmCopy( register PSZ pszDst, register PSZ pszSrc,
                 register SHORT nbDst )
  /*
  **  register PSZ pszDst  - Ptr to the destination buffer
  **  register PSZ pszSrc  - Ptr to the source string
  **  register SHORT nbDst - Size of the destination buffer
  */
{
  SHORT i;

  i = 0;

  while (*pszDst++ = *pszSrc++)
  {
    i++;

    if (nbDst-- <= 0 || *(pszSrc-1) == ';')
    {
      i--;
      *--pszDst = 0;
      break;
    }
  }
  return( i );
}

/***************************************************************************
 *
 * FUNCTION NAME = CheckNumeric
 *
 * DESCRIPTION   = Checks the string passed in.
 *
 * INPUT         = HWND    hWnd;
 *                 PSZ     pszBuffer;
 *
 * OUTPUT        = Returns TRUE if all characters are numeric,
 *                 returns FALSE otherwise.
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

BOOL CheckNumeric( HWND hWnd, PSZ pszBuffer )
{
  CHAR chr;
  BOOL fIsDotfound;

  fIsDotfound = FALSE;
  chr = *pszBuffer++;

  /*
  **  make sure we have something there.
  */
  if (!chr)
  {
    return( FALSE );
  }

  /*
  **  check the first character to see if it is a sign.  skip it if so.
  */
  if (chr == '+' || chr == '-')
  {
    chr = *pszBuffer++;
  }

  /*
  ** now check each character to see if it is numeric, or a decimal point.
  ** also, make sure there is only one decimal point.
  */
  while (chr)
  {
    if (chr >= '0' && chr <= '9')
    {
      chr = *pszBuffer++;
      continue;
    }
    else
    {
      if (!fIsDotfound && chr == '.')
      {
        chr = *pszBuffer++;
        fIsDotfound = TRUE;
        continue;
      }
      else
      {
        return( FALSE);
      }
    }
  }
  return( TRUE );
}

/***************************************************************************
 *
 * FUNCTION NAME = ValidFileName
 *
 * DESCRIPTION   = Checks whether filename specified in pszBuffer is valid
 *                 or not. The check is purely syntactic, no check is done
 *                 on existence of file.  If something is not caught here
 *                 it is caught later by the DosOpen and the user is then
 *                 told the file is invalid.
 *
 * INPUT         = PSZ     pszBuffer
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = DosQPathInfo()
 * RETURN-ERROR  = FALSE / 0
 *                                                                    
 *
 ****************************************************************************/

BOOL ValidFilename( PSZ pszBuffer )
{
  FILESTATUS fs;
  PCHAR      pch;
  ULONG      ulrc;

  /*
  ** check for reserved names which cause problems on down the line
  ** if they are used.
  */
  #ifdef   TRUE

    /*
    ** This is what you get when you don't
    ** write a case insensitive function!
    */
    if (sznIsEqual( pszBuffer, (PSZ) "con") || /* 000                           */
    sznIsEqual( pszBuffer, (PSZ)"coN") || /* 001                               */
    sznIsEqual( pszBuffer, (PSZ)"cOn") || /* 010                               */
    sznIsEqual( pszBuffer, (PSZ)"cON") || /* 011                               */
    sznIsEqual( pszBuffer, (PSZ)"Con") || /* 100                               */
    sznIsEqual( pszBuffer, (PSZ)"CoN") || /* 101                               */
    sznIsEqual( pszBuffer, (PSZ)"COn") || /* 110                               */
    sznIsEqual( pszBuffer, (PSZ)"CON") || /* 111                               */
    sznIsEqual( pszBuffer, (PSZ)"prn") || /* 000                               */
    sznIsEqual( pszBuffer, (PSZ)"prN") || /* 001                               */
    sznIsEqual( pszBuffer, (PSZ)"pRn") || /* 010                               */
    sznIsEqual( pszBuffer, (PSZ)"pRN") || /* 011                               */
    sznIsEqual( pszBuffer, (PSZ)"Prn") || /* 100                               */
    sznIsEqual( pszBuffer, (PSZ)"PrN") || /* 101                               */
    sznIsEqual( pszBuffer, (PSZ)"PRn") || /* 110                               */
    sznIsEqual( pszBuffer, (PSZ)"PRN"))/* 111                                  */
    {
      return( FALSE );
     }
  #else
    if (sznIsEqual( pszBuffer, (PSZ) "con") || sznIsEqual( pszBuffer, (PSZ)"CON" )
       || sznIsEqual( pszBuffer, (PSZ) "prn") || sznIsEqual( pszBuffer, (PSZ) "PRN" ) )
    {
      return( FALSE );
    }

    /*
    **  checked for named pipe info
    */
    {
      /*
      **  fix HM01007 - writing to named pipes
      */
      /*
      **  writing to named pipes
      */
      CHAR  szTestStr[20];
      PSZ   szTestBuf = szTestStr;
      SHORT i;

      for (i = 0; i < 6; i++)
      {
        szTestBuf[i] = pszBuffer[i];
      }
      szTestBuf[6] = '\0';

      if (com_strcmpi( szTestBuf, "\\PIPE\\" ))
      {
        return 0;
      }
      szTestBuf[2] = '\0';

      if (sznIsEqual(szTestBuf, "\\\\"))
      {
        return 0;
      }
    }
  #endif

  /*
  **  DosQPathInfo allows wild cards; check for them
  */
  pch = pszBuffer;

  while (*pch)
  {
    if (*pch == '?' || *pch == '*')
    {
      return( FALSE );
    }
    pch++;
  }

  /*
  **  Don't allow '?:.'
  */
  if (*(pch-1) == '.' && *(pch-2) == ':')
  {
    return( FALSE );
  }

  /*
  ** ask DOS if the file name is valid.  it will return zero, like all
  ** DOS calls, if it doesn't get upset and the path is valid
  */
  ulrc = DosQueryPathInfo( pszBuffer, FIL_STANDARD, (PBYTE) &fs, sizeof( fs ) );
  if ((ulrc == 2) || (!ulrc))
  {
    return( 1 );
  }
  else
  {
    return( 0 );
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ReadPaperName
 *
 * DESCRIPTION   = This routine is passed in an index for the appropriate
 *                 paper tray. It stores the given paper name in the indexed
 *                 element of the paper name structure.
 *
 * INPUT         = HWND        hWnd ;
 *                 SHORT       shTrayIndex ;
 *                 PCNFDATA    pcnfData ;
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

VOID ReadPaperName( HWND hWnd, SHORT shTrayIndex, PCNFDATA pcnfData )
{
  SHORT mi;
  PSZ   pszPaperName;

  /*
  ** get the paper name and set the entry in the dialog box.
  */
  pszPaperName = pcnfData->u.iv.pSourcePaper->szPaperName[shTrayIndex];

  if (pcnfData->u.iv.pSourcePaper->szPaperName[shTrayIndex][0] == '\0')
  {
    pszPaperName = (PSZ) StringTable[IDS_None - STRING_BASE];
  }
  mi = (SHORT) WinSendMsg( hWnd, LM_SEARCHSTRING,
               (MPARAM) (MPFROM2SHORT( 0, (SHORT) LIT_FIRST )),
               (MPARAM) pszPaperName );

  /*
  **  if an entry was found, highlight to show it has been selected.
  */
  if (mi != LIT_NONE)
  {
    WinSendMsg( hWnd, LM_SELECTITEM, (MPARAM)mi, (MPARAM) TRUE );
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryUserForm
 *
 * DESCRIPTION   = Query User Form
 *
 * INPUT         = PCNFDATA    pcnfData
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *                                                                    
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

VOID QueryUserForm( PCNFDATA pcnfData )
{
  SHORT iIndex,jIndex;
  ULONG lCount;
  PSZ   pszUserForms = NULL;
  CHAR  szBuffer[MAX_PSIZE];

  /*
  ** query to find how much memory is required to read in the form
  ** name.
  */
  if (!PrfQueryProfileSize( HINI_SYSTEMPROFILE, (PSZ) pcnfData->szKeyApp,
                            (PSZ) szKeyUserformName, (PULONG) &lCount ))
  {
    /*
    ** there are no user defined form names in os2sys.ini.  therefore,
    ** this must be a predefined form.  all predefined forms define
    ** their size to be the same as their name, so copy it over.
    */
    szNewCopy( (PSZ) pcnfData->jobProperties.szFormSize,
               (PSZ) pcnfData->jobProperties.szFormName,
               sizeof( pcnfData->jobProperties.szFormSize ));
    return ;
  }

  /*
  **  allocate the needed memory.
  */
  /*
  ** if (DosAllocMem((PPVOID)&pszUserForms, lCount, fPERM|PAG_COMMIT))
  */

  if ( !(pszUserForms = GplMemoryAlloc( pProcessHeap, lCount ) ))
  {
    return ;
  }

  /*
  ** we have found some user defined form names in os2sys.ini, so
  ** read them in.
  */
  PrfQueryProfileString( HINI_SYSTEMPROFILE, (PSZ) pcnfData->szKeyApp,
                         (PSZ) szKeyUserformName, (PSZ) "",
                         (PSZ) pszUserForms, (ULONG) lCount );

  /*
  ** in os2sys.ini the form names are stored in the following format:
  ** <form name>;<form size>;;<form name>;<form size> ...
  ** search through this list of form names, searching for a match.
  ** if it is found, copy the corresponding form size into our
  ** configuration data.
  */
  iIndex = 0;

  while (iIndex < (SHORT)(lCount-1))
  {
    szDlmCopy( (PSZ) szBuffer, (PSZ) (pszUserForms + iIndex), sizeof( szBuffer ));
    /*            */
    if ( ! CompareRealNames( (PSZ) szBuffer,
                             (PSZ) pcnfData->jobProperties.szFormName ))
    {
      /*
      **  skip over the form name, and copy the form size.
      */
      while (*(pszUserForms+iIndex++) != ';');
      szDlmCopy( (PSZ) pcnfData->jobProperties.szFormSize,
                 (PSZ) (pszUserForms + iIndex),
                 sizeof( pcnfData->jobProperties.szFormSize ));

      /*
      **  free up the memory.
      */
      /*
      ** DosFreeMem(pszUserForms);
      */
      GplMemoryFree( pszUserForms );
      pszUserForms = NULL;
      return ;
    }
    else
    {
      /*
      ** we did not find a match for the form name here, check the
      ** next form name for a match.  skip the form name.  skip the
      ** form size and skip the second semicolon.
      */
      while (*(pszUserForms + iIndex++) != ';');

      while (*(pszUserForms+iIndex++) != ';');
      iIndex++;
    }
  }

  /*
  ** if no matching form name was found, just copy the form name into
  ** the form size field.
  */
  szNewCopy( (PSZ) pcnfData->jobProperties.szFormSize,
             (PSZ) pcnfData->jobProperties.szFormName,
             sizeof( pcnfData->jobProperties.szFormSize ));

  /*
  **  free up the memory.
  */
  /*
  ** DosFreeMem(pszUserForms);
  */
  GplMemoryFree( pszUserForms );
  pszUserForms = NULL;
}

/***************************************************************************
 *
 * FUNCTION NAME = SetHelpStubHook()
 *
 * DESCRIPTION   = Add our stub HK_HELP hook to the hook chain. This lets us
 *                 get control the first time that the user presses PF1 or
 *                 clicks on a Help button.
 *
 * INPUT         = VOID
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

BOOL EXPENTRY SetHelpStubHook( )
{
  if (!HelpStubHookIsSet)
  {
    if (WinSetHook( (HAB) NULL, HMQ_CURRENT, HK_HELP, (PFN) HelpStubHook,
                    (HMODULE) NULL ))
    {
      HelpStubHookIsSet = TRUE;
      DosExitList( EXLST_ADD, (PFNEXITLIST) CleanUpHelpStubHook );
      return TRUE;
    }
  }
  return  FALSE;
}

/***************************************************************************
 *
 * FUNCTION NAME = InitializeHelp
 *
 * DESCRIPTION   = Initialize help. If we have already tried to create a
 *                 help instance, then return immediately.
 *
 * INPUT         = VOID
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

VOID EXPENTRY InitializeHelp( )
{
  HAB     hAB;
  CHAR    szHelpFile[CCHMAXPATH];
  HMODULE hmod;
  CHAR    achPath[CCHMAXPATH];
  BOOL    fError = TRUE;

  if (HelpAlreadyInitialized)
  {
    return ;
  }

  /*
  **  Initialize Help
  **  ---------------
  **
  **  Create an instance of the Help Manager, and associate it
  **  with the Frame.  If the Association fails, we handle it
  **  the same way as if the creation fails, ie hwndHelp
  **  (the Help Manager Object Window handle) is set to NULL.
  **  If we can't load the Module containing the Help Panel
  **  definitions, we forget Help altogether.
  */
  hAB = WinQueryAnchorBlock( hwndMain );
  WinLoadString( hAB, pscript_module, IDS_HELPTITLE, 256, (PSZ) szHelpTitle );

  hi.cb = sizeof( HELPINIT );
  hi.ulReturnCode = 0L;
  hi.pszTutorialName = (PSZ) NULL;
  hi.phtHelpTable = (PHELPTABLE) MAKEULONG( MAIN_HELPTABLE, 0xFFFF );
  hi.hmodHelpTableModule = pscript_module;
  hi.hmodAccelActionBarModule = NULLHANDLE;
  hi.idAccelTable = 0;
  hi.idActionBar  = 0;
  hi.pszHelpWindowTitle = (PSZ) szHelpTitle;
  hi.fShowPanelId = CMIC_HIDE_PANEL_ID; /* vary this to hide 77258 */
  strcpy((PSZ)get_module_dir( szHelpFile ), (PSZ) HELPFILENAME );
  hi.pszHelpLibraryName = (PSZ) szHelpFile;

  #if 0
    if (DosLoadModule(achPath, sizeof(achPath), "HELPMGR", &hmod));
                               /* No Help Manager                             */
    else if (DosQueryProcAddr(hmod, 0L,"WINCREATEHELPINSTANCE", (PFN  *)
         &pfnWinCreateHelpInstance));
                               /* No API                                      */
    else if (DosQueryProcAddr(hmod, 0L,"WINDESTROYHELPINSTANCE", (PFN  *)
         &pfnWinDestroyHelpInstance));
                             /* No API                                      */
    else if (DosQueryProcAddr(hmod, 0L,"WINASSOCIATEHELPINSTANCE", (PFN  *)
         &pfnWinAssociateHelpInstance));
                           /* No API                                      */
    else
      fError = FALSE;

    if (fError)
    {
      /*
      **  Should report error to user.  Requires MRI change.
      */
      ReleaseHelpStubHook( );
/**** SetHelpStubHook( );  Do not reset */
      return ;
    }

    do
    {
      hwndHelp = pfnWinCreateHelpInstance( hAB, &hmiHelpData );  /* my hab     */
    }

    while (HelpErrorFilter( hmiHelpData.ulReturnCode, (PSZ) szHelpFile ));
  #endif

  hwndHelp = WinCreateHelpInstance( hAB, &hi );

  if (hwndHelp != (HWND)NULL)
  {

    /*
    ** if (!pfnWinAssociateHelpInstance(hwndHelp, hwndMain))
    */

    if (!WinAssociateHelpInstance( hwndHelp, hwndMain ))  /* my frame        */
    {
      WinDestroyHelpInstance( hwndHelp );

      /*
      ** pfnWinDestroyHelpInstance(hwndHelp);
      */
      hwndHelp = (HWND) NULL;
    }                        /* END winassoc fail                           */
  }

  /*
  **  If help was initialized, get rid of our hook. Otherwise, we have
  **  to ensure that our stub hook is the FIRST hook in the HK_HELP
  **  hook chain, and show the "Out of Resource" dialog...
  */
  if (hwndHelp != (HWND)NULL)
  {
    HelpAlreadyInitialized = TRUE;
    ReleaseHelpStubHook( );
  }
  else
  {
    /*
    **  ShowOutOfResourceDlg();
    */
    ReleaseHelpStubHook( );
/** SetHelpStubHook( );    Do not reset */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ReleaseHelpStubHook
 *
 * DESCRIPTION   = Remove our stub HK_HELP hook from the hook chain, if it has
 *                 been successfully added via SetHelpStubHook()...
 *
 * INPUT         = VOID
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

VOID EXPENTRY ReleaseHelpStubHook( )
{

  if (HelpStubHookIsSet)
  {
    WinReleaseHook( (HAB) NULL, HMQ_CURRENT, HK_HELP, (PFN) HelpStubHook,
                    (HMODULE) NULL);
    DosExitList (EXLST_REMOVE, (PFNEXITLIST)CleanUpHelpStubHook);   // @MJH1
    HelpStubHookIsSet = FALSE;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = CleanUpHelpStubHook
 *
 * DESCRIPTION   = Exit list routine that will ensures we always remove our
 *                 stub HK_HELP hook before exiting.
 *
 * INPUT         = SHORT ExitType
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

VOID EXPENTRY CleanUpHelpStubHook( SHORT ExitType )
{
  ReleaseHelpStubHook( );
  DosExitList( EXLST_EXIT, (PFNEXITLIST) CleanUpHelpStubHook );
  ExitType;
}

/***************************************************************************
 *
 * FUNCTION NAME = HelpStubHook
 *
 * DESCRIPTION   = This hook is placed in the HK_HELP hook chain so that we
 *                 can catch the first time that the user presses PF1 or
 *                 clicks on a "Help" button. We then initialize our help
 *                 instance and get the user's help request passed back into
 *                 the HK_HELP chain again by making a call to the private
 *                 function WinCallHelpHook()...
 *
 * INPUT         = HAB    AppHAB
 *                 SHORT Context
 *                 SHORT IdTopic
 *                 SHORT IdSubTopic
 *                 PRECTL RectLPtr
 *
 * OUTPUT        = INT
 *
 * RETURN-NORMAL = FALSE
 * RETURN-ERROR  =
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

INT EXPENTRY HelpStubHook( HAB AppHAB, SHORT Context, SHORT IdTopic,
                           SHORT IdSubTopic, PRECTL RectLPtr )
{
  AppHAB;                    /* avoid compile warning                       */

  /*
  **  Initialize the help manager, so that it will be added to
  **  the HELP hook chain.
  */
  InitializeHelp( );

  /*
  **  Now call the HK_HELP
  */
  #ifdef   DCR1476
    if (hwndHelp != NULL)
    {
      WinCallHelpHook( Context, IdTopic, IdSubTopic, RectLPtr );
    }
  #endif
  if (hwndHelp != (HWND)NULL)
  {
     extern VOID _Far16 _Pascal Win16CallHelpHook (SHORT, SHORT, SHORT, PRECTL _Seg16);
     Win16CallHelpHook (Context, IdTopic, IdSubTopic, RectLPtr);
  }

  return FALSE;
}

/***************************************************************************
 *
 * FUNCTION NAME = get_module_dir
 *
 * DESCRIPTION   = Return size of the directory path
 *
 * INPUT         = register PSZ   pszStr
 *
 * OUTPUT        = PSZ
 *
 * RETURN-NORMAL = (PSZ) &pszStr[usSize]
 * RETURN-ERROR  =
 *                                                                    
 *
 ****************************************************************************/

PSZ get_module_dir( register PSZ pszStr )
{
  register SHORT usSize;
  register CHAR ch;

  DosQueryModuleName( pscript_module, 70, (PCH) pszStr );

  usSize = (SHORT) strlen( pszStr );

  while (usSize--)
  {
    if (((ch = pszStr[usSize]) == '\\') || (ch == ':'))
    {
      break;
    }
  }

  if (usSize < 0)
  {
    usSize = 0;
  }
  else
  {
    if (pszStr[usSize] == ':')
    {
      ++usSize;
    }
  }
  pszStr[usSize] = 0;
  return( (PSZ) &pszStr[usSize] );
}

/***************************************************************************
 *
 * FUNCTION NAME = HelpErrorFilter
 *
 * DESCRIPTION   = Checks for a recoverable help manager initialization error.
 *                 If a a recoverable error is detected we put up a message
 *                 box describing the error and ask the user if we should
 *                 retry.
 *
 * INPUT         = SHORT   sErrorID
 *                 CHAR    szMessage[HLP_MSG_MAX]
 *                 CHAR    szSrc[CCH_MAXRCSTRING]
 *                 PSZ     apsz[1]
 *                 SHORT  uRet
 *                 BOOL    fRetry=FALSE
 *
 * OUTPUT        = BOOL [(SHORT)WinMessageBox()]
 *
 * RETURN-NORMAL = TRUE: Retry
 * RETURN-ERROR  = FALSE: No error or do not retry   [NULL]
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

#define  HLP_MSG_MAX   500
#define  CCH_MAXRCSTRING 256
BOOL HelpErrorFilter( ULONG ulReturnCode, PSZ pszHelpFile )
{
  SHORT sErrorID;
  CHAR  szMessage[HLP_MSG_MAX];
  CHAR  szSrc[CCH_MAXRCSTRING];
  PSZ   apsz[1];
  ULONG uRet;
  BOOL  fRetry = FALSE;

  switch ((SHORT) ulReturnCode)
  {
  case HMERR_NO_MEMORY:
  case HMERR_ALLOCATE_SEGMENT:
       WinLoadString( (HAB) NULL, pscript_module, IDS_NoHelpMemory, CCH_MAXRCSTRING,
                      (PSZ) szSrc );
       fRetry = FALSE;
       break;

  case HMERR_INVALID_LIB_FILE:
  case HMERR_READ_LIB_FILE:
  case HMERR_OPEN_LIB_FILE:
       /*
       **  get message
       */
       WinLoadString( (HAB) NULL, pscript_module, IDS_NoHelpFile, CCH_MAXRCSTRING,
                      (PSZ) szSrc);

       /*
       **  insert help file name
       */
       apsz[0] = pszHelpFile;
       DosInsertMessage( apsz, 1L, szSrc, (ULONG) strlen( (PSZ) szSrc ), szMessage,
                         HLP_MSG_MAX , &uRet );
       szMessage[uRet] = 0;
       fRetry = TRUE;
       break;

  /*
  **  no error or can recover-Do not retry
  */
  default:
       return( 0 );
  }

  /*
  **  display error
  */
  return( (SHORT) WinMessageBox( (HWND) HWND_DESKTOP, (HWND) WinQueryActiveWindow
          (HWND_DESKTOP), fRetry ? (PSZ) szMessage : (PSZ) szSrc, (PSZ) NULL,
          (SHORT) NULL, (SHORT) (MB_ICONHAND | MB_MOVEABLE | ((fRetry) ? MB_RETRYCANCEL :
          MB_CANCEL))) == MBID_RETRY);
}


/***************************************************************************
 *
 * FUNCTION NAME = PrintFontMem
 *
 * DESCRIPTION   = Sends a queued PostScript job to printer which generates
 *                 a status page.  The sheet has the free vm and number of
 *                 suggested fonts for that much memory.
 *
 * INPUT         = PCNFDATA pcnfData
 *
 * OUTPUT        = Printer status page
 *
 * RETURN-NORMAL = N/A
 *
 * RETURN-ERROR  = N/A
 *
 ****************************************************************************/

VOID PrintFontMem( PCNFDATA pcnfData )
{
  /* CHAR           sPrinterBuff [255]; */
  PSZ            sPrinterBuff;              /*            */
  CHAR           sKeyString [16];
  USHORT         count;
  PSZ            pKeyPrinter;
  HFILE          hDevice = (HFILE)0;
  ULONG          uAction;
  register SHORT i;
  LDRIVDATA      lda;
  DEVOPENSTRUC   dop;
  HSPL           hspl;
  PSZ            pQueueName;

  /*
  ** Copy the PM_DD_xxxxxxxx
  */
  pKeyPrinter = pcnfData->szKeyApp + 6;  /* Point to printer name */

  i = 0;
  while ( ( sKeyString[i] = *pKeyPrinter )  != ',' )
  {
    i++;
    *pKeyPrinter++;
  }
  sKeyString[i] = 0;  /* set comma to NULL */

  /*
  ** go to deivce name
  */
  while ( *(pKeyPrinter++) != '.' );

  i = 0;
  while ( lda.szDeviceName[i] = *pKeyPrinter )
  {
    i++;
    *pKeyPrinter++;
  }
  lda.szDeviceName[i] = 0;

  /*            */
  if ( !ProfileAllocStringQuery( HINI_PROFILE, "PM_SPOOLER_PRINTER",
                                 (PSZ) sKeyString, NULL,
                                 (PPVOID) &sPrinterBuff ))
  {
    return;
  }

  i = 0;
  while( sPrinterBuff[i++] != ';' ) ;  /* go to end of ports list   */
  while( sPrinterBuff[i++] != ';' ) ;  /* go to end of devices list */
  pQueueName = (PSZ) &sPrinterBuff[i];

  /*
  ** find end of first queue name
  */
  while( sPrinterBuff[i] != ';' && sPrinterBuff[i] != ',' )
  {
    i++;
  }

  sPrinterBuff[i] = 0;

  lda.cb = 40 + sizeof( CNFDATA );
  lda.lVersion = 0;
  utl_memcopy( (PBYTE)&lda.cnfData, (PBYTE)pcnfData, sizeof( CNFDATA ) );

  dop.pszLogAddress = pQueueName;
  dop.pszDriverName = (PSZ) "PSCRIPT";
  dop.pdriv = (PDRIVDATA) &lda;
  dop.pszDataType = (PSZ) "PM_Q_RAW";
  dop.pszComment = NULL;
  dop.pszQueueProcName = NULL;
  dop.pszQueueProcParams = NULL;
  dop.pszSpoolerParams = NULL;
  dop.pszNetworkParams = NULL;

  if ( (hspl = SplQmOpen( (PSZ)"*", 4L, (PQMOPENDATA)&dop ) ) == SPL_ERROR )
  {
    /*            */
    GplMemoryFree( sPrinterBuff );

    return;
  }

  SplQmStartDoc( hspl, (PSZ)"Status Sheet" );

  SplQmWrite( hspl, (LONG)sizeof(szFontMemPS1)-1, (PBYTE)szFontMemPS1 );
  SplQmWrite( hspl, (LONG)strlen(StringTable[IDS_Avail_Mem-STRING_BASE]),
              (PBYTE)StringTable[IDS_Avail_Mem-STRING_BASE] );
  SplQmWrite( hspl, (LONG)sizeof(szFontMemPS2)-1, (PBYTE)szFontMemPS2 );
  SplQmWrite( hspl, (LONG)strlen(StringTable[IDS_Sug_Font-STRING_BASE]),
             (PBYTE)StringTable[IDS_Sug_Font-STRING_BASE] );
  SplQmWrite( hspl, (LONG)sizeof(szFontMemPS3)-1, (PBYTE)szFontMemPS3 );

  SplQmEndDoc( hspl );
  SplQmClose( hspl );


  /*
  ** Keep if needed for direct cases
  */
  #if 0
    /* open port */
    if ( PrtOpen (sPrinterBuff, &hDevice, &uAction, 0L, FILE_NORMAL,
             OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
             OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, 0L) )
    {
      return; /* we failled - give up */
    }

    /*
    ** print
    */
    PrtWrite( hDevice, (PVOID) szFontMemPS1, sizeof( szFontMemPS1 ) - 1, &uAction);
    PrtWrite( hDevice, (PSZ) StringTable[IDS_Avail_Mem-STRING_BASE],
              strlen( StringTable[IDS_Avail_Mem-STRING_BASE]), &uAction );
    PrtWrite( hDevice, (PVOID) szFontMemPS2, sizeof( szFontMemPS2 ) - 1, &uAction);
    PrtWrite( hDevice, (PSZ) StringTable[IDS_Avail_Mem-STRING_BASE],
              strlen( StringTable[IDS_Sug_Font-STRING_BASE] ), &uAction );
    PrtWrite( hDevice, (PVOID)szFontMemPS3, sizeof(szFontMemPS3)-1, &uAction);

    /*
    ** close port
    */
    PrtClose( hDevice );
  #endif

  /*            */
  GplMemoryFree( sPrinterBuff );
}
