/************ GRAPHIC C Sample Program Source Code File (.C) *****************
 *
 * PROGRAM NAME: GRAPHIC
 * -------------
 *  Presentation Manager Non-Retained Graphics C Sample Program
 *
 * WHAT THIS PROGRAM DOES:
 * -----------------------
 *  This program displays a selected metafile.
 *  The current contents of the client area can also be printed.
 *  All drawing is performed by a lower-priority asynchronous
 *  thread, thus allowing the program to monitor its message queue
 *  at regular intervals. The program does not test every call for
 *  an error return code.
 *
 * WHAT THIS PROGRAM DEMONSTRATES:
 * -------------------------------
 *  This program demonstrates the use of the default viewing
 *  transformation, metafile loading and playing, the use of
 *  dialog boxes, and file manipulation through Standard Open dialog.
 *  It also demonstrates the use of an asynchronous drawing thread and
 *  print thread.
 *
 * API CALLS FEATURED:
 * -------------------
 *
 *  WinAddSwitchEntry			  DosReleaseMutexSem
 *  WinAssociateHelpInstance		  DosCloseMutexSem
 *  WinBeginPaint			  DosCloseEventSem
 *  WinCreateStdWindow			  DosWaitThread
 *  WinCreationFlags
 *  WinCreateHelpInstance		  DosResetEventSem
 *  WinCreateMsgQueue
 *  WinCreateWindow			  DosCreateThread
 *  WinDlgBox				  DosGetInfoBlocks
 *  WinDefFileDlgProc			  DosCreateMutexSem
 *  WinDestroyHelpInstance		  DosCreateEventSem
 *  WinDestroyMsgQueue
 *  WinDestroyWindow			  GpiCharStringAt
 *  WinDispatchMsg			  GpiSetColor
 *  WinDefDlgProc			  GpiQueryFontMetrics
 *  WinDefWindowProc			  GpiCreateRegion
 *  WinDismissDlg			  GpiCreatePS
 *  WinEndPaint				  GpiQueryCharBox
 *  WinFillRect				  GpiAssociate
 *  WinGetPS				  GpiDestroyPS
 *  WinGetMsg				  GpiDestroyRegion
 *  WinInitialize			  GpiLoadMetaFile
 *  WinInvalidateRegion			  GpiResetPS
 *  WinInvalidateRect			  GpiSetStopDraw
 *  WinLoadString
 *  WinMessageBox
 *  WinOpenWindowDC
 *  WinPostMsg
 *  WinPostQueueMsg
 *  WinQuerySysValue
 *  WinQuerySysPointer
 *  WinQueryWindowDC
 *  WinQueryWindowPos
 *  WinQueryWindowProcess
 *  WinQueryWindowPtr
 *  WinQueryWindowRect
 *  WinRegisterClass
 *  WinReleasePS
 *  WinRequestMutexSem
 *  WinSendDlgItemMsg
 *  WinSendMsg
 *  WinSetWindowPos
 *  WinSetWindowPtr
 *  WinSetWindowText
 *  WinTerminate
 *  WinWaitEventSem
 *  WinWindowFromID
 *
 * WHAT YOU NEED TO COMPILE THIS PROGRAM:
 * --------------------------------------
 *
 *  REQUIRED FILES:
 *  ---------------
 *
 *    GRAPHIC.C	    - Source code
 *    FILE.C	    - Source code (File Handling)
 *    GRAPHIC.MAK   - Make file for this program
 *    GRAPHIC.DEF   - Module definition file
 *    GRAPHIC.H	    - Application header file
 *    GRAPHIC.ICO   - Icon file
 *    GRAPHIC.LNK   - Linker automatic response file
 *    GRAPHIC.RC    - Resource file
 *
 *    OS2.H	     - Presentation Manager include file
 *    STDLIB.H	     - Miscellaneous function declarations
 *    STRING.H	     - String function declarations
 *
 * EXPECTED INPUT:
 * ---------------
 *  User activity with the mouse or the keyboard, the standard
 *  frame controls, menus, and dialog boxes.
 *
 * EXPECTED OUTPUT:
 * ----------------
 *  Display of the center part of a metafile picture in a standard
 *  window. This has a frame with title bar, system and application
 *  menus, and maximize and minimize icons.
 *
 *  Copyright (C) 1991 IBM Corporation
 *
 *	DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
 *	sample code created by IBM Corporation. This sample code is not
 *	part of any standard or IBM product and is provided to you solely
 *	for  the purpose of assisting you in the development of your
 *	applications.  The code is provided "AS IS", without
 *	warranty of any kind.  IBM shall not be liable for any damages
 *	arising out of your use of the sample code, even if they have been
 *	advised of the possibility of such damages.						       *
 ******************************************************************************/

/* Include the required sections of the PM header file */

#include <stdlib.h>
#include <string.h>

#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_GPICONTROL
#define INCL_GPIMETAFILES
#define INCL_GPIREGIONS
#define INCL_GPIPRIMITIVES
#define INCL_GPILCIDS
#define INCL_WINSTDFILE
#define INCL_WINSTDDLGS
#define INCL_WINHELP
#define INCL_WINPOINTERS
#define INCL_WINFRAMEMGR
#define INCL_WINWINDOWMGR
#define INCL_WINMESSAGEMGR
#define INCL_WINDIALOGS
#define INCL_WINSYS
#define INCL_WINMENUS
#define INCL_WINMLE
#define INCL_WINERRORS

#include <os2.h>
#include <pmstddlg.h>
#include <ctype.h>
#include <process.h>
#include "graphic.h"

/*
 * Presentation Manager Program Main Body
 *
 * The following routine is the Presentation Manager program Main Body.
 * The Main Body of a PM program is concerned with associating the
 * application with the Presentation Manager system, creating its
 * message queue, registering and displaying its main window, servicing
 * its message queue during the time that the application is active,
 * and disassociating the application from PM when the user is finished
 * with the application. The remaining parts of this source module that
 * are concerned with the Presentation Manager are the application's
 * window procedures (main window procedure, child window procedures,
 * and dialog window procedures) that process the messages associated
 * with the application's various windows.
 */

/* static function definitions */
static	 VOID	    InvalidateTextRect(HWND hWnd);
static	 MAIN_PARM  Parm;
static	 PAPPL_DEFAULTS ApplDefaults;

/**************************************************************************
 * Function: main
 *
 * Initializes the structures and handle the messages for the main window
 *
 * Parameters: none
 *
 * Result: none
 *
 ***************************************************************************/
VOID main(VOID)
{
	 QMSG	    qmsg;	    /* MSG structure to store the messages */
	 BOOL	    fRc;
	 BOOL	    FastQuit = FALSE;

/* Do the Initialization */
   if (!Initialize())
   {
      FastQuit = TRUE;
      ReportError();
      EndProgram();
   }


/* The following is the message loop for the application. */

   do
   {
      fRc = WinGetMsg(Parm.hAB, (PQMSG)&qmsg, 0, 0, 0);
      if (fRc)			 /* if not WM_QUIT, pass the message to the   */
	 WinDispatchMsg(Parm.hAB, (PQMSG)&qmsg);     /* window procedure     */
   } while (fRc);

/* if printing is in process, cancel print job */
   if (Parm.PrintStatus)
   {
      if (GpiSetStopDraw(Parm.hpsPrint, (LONG)TRUE) == GPI_ERROR)
	 DispError(Parm.hAB,Parm.hWndClient);
   }

   EndProgram();
   exit(0);
} /* End of main */

/**************************************************************************
 * Function: Initialize
 *
 * Initializing the structures and handle the messages for the main window
 *
 * Parameters: none
 *
 * Result:  BOOL	      TRUE	Initialization ok
 *			      FALSE	Error in Initialization
 *
 ***************************************************************************/
BOOL Initialize(VOID)
{
	 CHAR	    szAppName[20];	      /* class name of application */
static	 CHAR	    InfoWindow[] = "GRAPHIC"; /* class name of info window */
	 INT	    rc;
	 HELPINIT   hiGRAPHICHelp;     /* Help initialization structure	   */
	 ULONG	    WinCreationFlags;  /* window creation flags		   */
	 PID	    pid;	 /* Process identifier for adding name to  */
				       /* switch list			   */
	 TID	    tid;	       /* Thread identifier		   */
	 SWCNTRL    Swctl;
	 ULONG	   WindowPosOption;


/* Init Structure */
   memset((PVOID)&Parm, '\0', sizeof(MAIN_PARM));
   Parm.PrintEnabled = Parm.PrintPropertiesEnabled = Parm.fNotReady = TRUE;
   Parm.DrawThreadID = (TID)-1;
   Parm.CheckedItem = -1;
   Parm.DrawParm.rclBounds.xLeft = Parm.DrawParm.rclBounds.yBottom =
				   Parm.DrawParm.rclBounds.xRight =
				   Parm.DrawParm.rclBounds.yTop = 0xFFFF;
   Parm.DrawParm.fAllValid = Parm.fStoppable = Parm.DrawParm.fDrawing = TRUE;

   /* Create semaphores */
   DosCreateMutexSem(NULL, &Parm.hmtxsemStoppable, DC_SEM_SHARED, FALSE);
   DosCreateEventSem(NULL, &Parm.hevsemTerminate, DC_SEM_SHARED, TRUE);
   DosCreateEventSem(NULL, &Parm.hevsemPrintEnds, DC_SEM_SHARED, TRUE);
   DosCreateEventSem(NULL, &Parm.hevsemStop, DC_SEM_SHARED, TRUE);
   /*
    * The WinInitialize routine initializes the Presentation Manager
    * facilities for use by this application and returns a handle to the
    * anchor block assigned to the application by PM.
    */
   if ((Parm.hAB = WinInitialize(0)) == (HAB)0)
      return(FALSE);

   Parm.ProgramTitle = GetString(Parm.hAB, APPLICATION_NAME, ALLOC_STRING);

   /* The WinCreateMsgQueue call creates a message queue for this application */
   if ((Parm.hMQ = WinCreateMsgQueue(Parm.hAB, 16384)) == (HMQ)0)
      return(FALSE);

   /* Query System Pointer */
   Parm.hptrGlass = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE);
   Parm.hptrArrow = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE);


/* The following function registers the classes of all application windows */
   strcpy(szAppName, GetString(Parm.hAB, APPLICATION_NAME, STATIC_STRING));
   rc = WinRegisterClass(Parm.hAB,	   /* Anchor block handle	      */
			 (PCH)szAppName,   /* Name of class being registered  */
			 (PFNWP)WndProc,   /* Window procedure for class      */
			 CS_CLIPCHILDREN | CS_SIZEREDRAW | CS_SYNCPAINT,
			 0);

   if (rc == FALSE)
      return(FALSE);

   /* register a class for the information window */
   rc = WinRegisterClass(Parm.hAB,	   /* Anchor block handle	      */
			 (PCH)InfoWindow,  /* Name of class being registered  */
			 (PFNWP)WndProcI,  /* Window procedure for class      */
			 /* CS_SIZEREDRAW | CS_SYNCPAINT | CS_SAVEBITS, */
			 0L,
			 sizeof(PMAIN_PARM));

   if (rc == FALSE)
      {
      strcpy(Parm.ErrorMsg,
	     GetString(Parm.hAB, ERRMSG_REGISTER_FAILED, STATIC_STRING));
      return(FALSE);
      }

   /* IPF Initialization Structure */

   hiGRAPHICHelp.cb = sizeof(HELPINIT);		   /* size of init structure */
   hiGRAPHICHelp.ulReturnCode = 0;
   hiGRAPHICHelp.pszTutorialName = 0;		   /* no tutorial	     */
   hiGRAPHICHelp.phtHelpTable = (PVOID)(0xffff0000 | ID_GRAPHIC);
   hiGRAPHICHelp.hmodAccelActionBarModule = 0;
   hiGRAPHICHelp.idAccelTable = 0;
   hiGRAPHICHelp.idActionBar = 0;
   hiGRAPHICHelp.pszHelpWindowTitle = szAppName;
   hiGRAPHICHelp.hmodHelpTableModule = 0;
   hiGRAPHICHelp.fShowPanelId = 0;
   hiGRAPHICHelp.pszHelpLibraryName = HELP_FILE;

   /* Create Instance of IPF */

   Parm.hWndGRAPHICHelp = WinCreateHelpInstance(Parm.hAB, &hiGRAPHICHelp);

   if (!Parm.hWndGRAPHICHelp || hiGRAPHICHelp.ulReturnCode)
      {
      WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
		    GetString(Parm.hAB, ERRMSG_NO_HELP, STATIC_STRING),
		    (PSZ)Parm.ProgramTitle,
		    1,
		    MB_OK | MB_APPLMODAL | MB_MOVEABLE);
      WinDestroyHelpInstance(Parm.hWndGRAPHICHelp);
      }
    /*
     * The CreateWindow function creates a frame window for this application's
     * top window, and sets the window's size and location as appropriate.
     */
   WinCreationFlags = FCF_TITLEBAR     |
		      FCF_SYSMENU      |
		      FCF_MINBUTTON    |
		      FCF_MAXBUTTON    |
		      FCF_SIZEBORDER   |
		      FCF_MENU	       |
		      FCF_ACCELTABLE   |
		      FCF_ICON;

   WinCreationFlags |= FCF_SHELLPOSITION;

   /* Create the frame window */
   Parm.hWndFrame = WinCreateStdWindow(HWND_DESKTOP, /* parent of window      */
				WS_VISIBLE,	     /* frame window style    */
				&WinCreationFlags,   /* frame flags	      */
				szAppName,	     /* class name	      */
				Parm.ProgramTitle,   /* window title	      */
				WS_VISIBLE |	     /* client window style   */
				WS_CLIPCHILDREN,
				(HMODULE)NULL,	     /* module for resources  */
				ID_GRAPHIC,	     /* resource id	      */
				(HWND FAR *)&Parm.hWndClient); /* client handle*/
      /*
       * if hWndFrame is NULL, an error occured when opening the window,
       *     notify the user and exit this function
       */
   if (Parm.hWndFrame == (HWND)0)
      {
      strcpy(Parm.ErrorMsg, GetString(Parm.hAB, ERRMSG_CREATE_WINDOW,
				       STATIC_STRING));
      return(FALSE);
      }

   /* Associate Instance of IPF */

   if (Parm.hWndGRAPHICHelp)
      WinAssociateHelpInstance(Parm.hWndGRAPHICHelp,
			       Parm.hWndFrame);
   /*
    * The following inline routine fills out the application's switch control
    * structure with the appropriate information to add the application's
    * name to the OS/2 Task Manager List, a list of the jobs currently
    * running on the computer.
    */
   WinQueryWindowProcess(Parm.hWndFrame, &pid, &tid);
   Swctl.hwnd = Parm.hWndFrame;			    /* Frame window handle    */
   Swctl.idProcess = pid;			    /* Process identifier     */
   Swctl.uchVisibility = SWL_VISIBLE;		    /* visibility	      */
   Swctl.fbJump = SWL_JUMPABLE;			    /* Jump indicator	      */
   strcpy(Swctl.szSwtitle, Parm.ProgramTitle);	    /* Frame window title     */
   WinAddSwitchEntry(&Swctl);

   /* Copy Application Defaults */
   if (ApplDefaults)
      {
      strcpy(Parm.DriverName, ApplDefaults->DriverName);
      }

   /* Query Default Printer and set print items (Print & Printer Properties) */
   SetPrintItems(&Parm);

   /* create information window */
     Parm.InfoWnd.hWnd = WinCreateWindow(Parm.hWndClient,
					 InfoWindow,
					 (PSZ)InfoWindow,
					 WS_SAVEBITS | WS_CLIPCHILDREN,
					 0,
					 0,
					 1,
					 1,
					 Parm.hWndClient,
					 HWND_TOP,
					 ID_GRAPHIC,
					 (PVOID)&Parm,
					 NULL);

   if (Parm.InfoWnd.hWnd == (HWND)0)
   {
      strcpy(Parm.ErrorMsg, GetString(Parm.hAB, ERRMSG_INFO_WINDOW, STATIC_STRING));
      return(FALSE);
   }

/*
 * Query current process ID, thread ID and the process ID of the parent
 * process
 */
   DosGetInfoBlocks(&Parm.ptibMain, &Parm.ppibMain);

/* create draw thread */
   if (DosCreateThread(&Parm.DrawThreadID,
		    (PFNTHREAD)DrawThread,
		    (ULONG)(PMAIN_PARM)&Parm,
		    (ULONG)0,
		    (ULONG)STACK_SIZE))
   {
      strcpy(Parm.ErrorMsg, GetString(Parm.hAB, ERRMSG_DRAW_THREAD, STATIC_STRING));
      return(FALSE);
   }

/* create print thread */
   if (DosCreateThread(&Parm.PrintThreadID,
		    (PFNTHREAD)PrintThread,
		    (ULONG)(PMAIN_PARM)&Parm,
		    (ULONG)0,
		    (ULONG)STACK_SIZE))
   {
      strcpy(Parm.ErrorMsg, GetString(Parm.hAB, ERRMSG_PRINT_THREAD,
	     STATIC_STRING));
      return(FALSE);
   }

/* invalidate text rectangle */
   InvalidateTextRect(Parm.hWndClient);
   return(TRUE);

} /* End of Initialize */

/**************************************************************************
 * Function: Report Error
 *
 * Display a message box with the error returned from the function
 * Initialize.
 *
 * Parameters: none
 *
 * Result:  none
 *
 ***************************************************************************/
VOID ReportError(VOID)

{
   if (Parm.ErrorMsg)
      WinMessageBox(HWND_DESKTOP,
		 (Parm.hWndFrame) ? Parm.hWndFrame : HWND_DESKTOP,
		 (PSZ)Parm.ErrorMsg,
		 (PSZ)NULL,
		 0,
		 MB_MOVEABLE | MB_CUACRITICAL | MB_OK);
} /* End of ReportError */

/*************************************************************************
 * Function: EndProgram
 *
 * End the threads and discard all windows
 *
 * Parameters: none
 *
 * Result:  none
 *
 ***************************************************************************/
VOID EndProgram(VOID)
{
   ULONG      ResetCount;
/*
 * Perform clean up before exiting application.
 * Destroy Instance of IPF
 */
   if (Parm.hWndGRAPHICHelp)
      WinDestroyHelpInstance(Parm.hWndGRAPHICHelp);

/* end the draw thread */
   if (Parm.DrawThreadID != -1)
   {
      WinRequestMutexSem(Parm.hmtxsemStoppable, (ULONG)-1);
      Parm.fStoppable = TRUE;
      DosReleaseMutexSem(Parm.hmtxsemStoppable);
      SendCommand(&Parm, (ULONG)FLUSH_COMMAND, (ULONG)NULL);
      DosResetEventSem(Parm.hevsemTerminate, &ResetCount);
      if (SendCommand(&Parm, (ULONG)STOP_THREAD, (ULONG)NULL))
	 WinWaitEventSem(Parm.hevsemTerminate, (ULONG)-1);
   }

/* end the print thread */
   if (Parm.PrintThreadID != -1)
   {
      DosResetEventSem(Parm.hevsemPrintEnds, &ResetCount);
      WinPostQueueMsg(Parm.hMQPrint, STOP_THREAD, MPFROMSHORT(0), MPFROMSHORT(0));
      WinWaitEventSem(Parm.hevsemPrintEnds, (ULONG)-1);
   }

/* wait until Draw Thread has ended */
   DosWaitThread(&Parm.DrawThreadID, DCWW_WAIT);

/* wait until print thread has ended */
   DosWaitThread(&Parm.PrintThreadID, DCWW_WAIT);

   if (Parm.InfoWnd.hWnd)
      WinDestroyWindow(Parm.InfoWnd.hWnd);  /* Destroy the Infowindow		 */
   if (Parm.hWndFrame)
      WinDestroyWindow(Parm.hWndFrame);	    /* Destroy the frame window		 */
   if (Parm.hMQ)
      WinDestroyMsgQueue(Parm.hMQ);  /* Destroy the application message queue */
   if (Parm.hAB)
      WinTerminate(Parm.hAB);	     /* Terminate the application's use of   */
				     /* Presentation Manager resources	     */

   /* Close the semaphores */
   DosCloseMutexSem(Parm.hmtxsemStoppable);	   /* new with 2.0 */
   DosCloseEventSem(Parm.hevsemTerminate);
   DosCloseEventSem(Parm.hevsemPrintEnds);
   DosCloseEventSem(Parm.hevsemStop);
} /* End of EndProgram */

/**************************************************************************
 * Function: WndProc
 *
 * Main Window Procedure
 *
 * This procedure provides service routines for the general PM events
 * (messages) that PM sends to the window, as well as the user
 * initiated events (messages) that are generated when the user selects
 * the action bar and pulldown menu controls or the corresponding
 * keyboard accelerators.
 *
 * The SWITCH statement shown below distributes the window messages to
 * the respective message service routines, which are set apart by the
 * CASE statements. The window procedures must provide an appropriate
 * service routine for its end user initiated messages, as well as the
 * general PM messages (like the WM_CLOSE message). If a message is
 * sent to this procedure for which there is no programmed CASE clause
 * (i.e., no service routine), the message is defaulted to the
 * WinDefWindowProc function, where it is disposed of by PM.
 *
 * Parameters: HWND	    window handle
 *	       USHORT	    message
 *	       MPARAM	    message parameter 1
 *	       MPARAM	    message parameter 2
 *
 * Result:  MRESULT	    message result
 *
 ***************************************************************************/
MRESULT EXPENTRY WndProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2)
{
	 HPS	    hPS;      /* Handle for the Presentation Space	   */
	 RECTL	    rClient;  /* Handle to rectangle formed by client area */
	 PSWP	    WindowPos;
static	 BOOL	    WindowMinimized = FALSE;
	 HMF	    hmfPicture;
static	 CHAR	    Filename[260];
static	 CHAR	    Filemask[260];
static	 MENUITEM   mi =
		    {
		    1, MIS_TEXT, 0, IDM_F_TEXT_PREVIOUS, (HWND)0, (ULONG)0
		    };
static	 BOOL	    MenuUpdated = FALSE;
	 PSZ	    FileName;
	 PSZ	    DialogHeader;

   switch(message)
   {
   case SET_PRINT_STATUS:	       /* set print status		*/
	Parm.PrintStatus = (BOOL)SHORT1FROMMP(mp1);
	Parm.hpsPrint = (HPS)LONGFROMMP(mp2);
	WinSendMsg(Parm.InfoWnd.hWnd,  /* hide/show information window */
		   ENABLE_INFO_WND,
		   mp1,
		   MPFROMSHORT(0));
	SetPrintItems(&Parm);		   /* set item "Print" in the menu */
	break;

   case WM_CREATE:
	return(WndProcCreate(hWnd, &Parm));
	break;

   case WM_ERASEBACKGROUND:
	/*
	 * If the flag fNotReady is set, the default processing for this
	 * message occurs.
	 */
	if (Parm.fNotReady)
	   return(MRESULT)(TRUE);
	else
	   return(MRESULT)(FALSE);
	break;

   case WM_USER_END_ON_ERROR:	       /* Display error and end program */
	WinMessageBox(HWND_DESKTOP,
		      hWnd,
		      (PSZ)PVOIDFROMMP(mp2),
		      (PSZ)PVOIDFROMMP(mp1),
		      (USHORT)0,
		      MB_OK | MB_MOVEABLE | MB_CUACRITICAL | MB_APPLMODAL);
	WinPostMsg(hWnd,
		   WM_QUIT,
		   MPFROMSHORT(0),
		   MPFROMSHORT(0));
	break;
   case WM_USER_DEFINED_CODE:	       /* own messages			*/
	switch (SHORT1FROMMP(mp1))
	   {
	   case CHECK_ITEM:	       /* check item in file menu	*/
		break;
	   }

   case WM_COMMAND:
	/*
	 * The PM messages for action bar and pulldown menu items are
	 * processed in this routine.
	 */
	switch(SHORT1FROMMP(mp1))
	   {
	   case IDM_F_GPI:	       /* menu item "GPI"		*/
	       *Parm.Message = '\0';
		if (Parm.CheckedItem != 1)
		{
		   StopDrawing(&Parm);
		   if (GpiResetPS(Parm.hpsClient, GRES_ALL) == GPI_ERROR)
		       DispError(Parm.hAB,Parm.hWndClient);
		   SendCommand(&Parm, (ULONG)SET_TRANSFORM, (ULONG)NULL);
		   SendCommand(&Parm, (ULONG)DRAW_ORDERS, (ULONG)NULL);
		   Parm.DrawThreadActivated = TRUE;
		   CheckPulldown(&Parm, 1);
		   SetTitleBarText(&Parm, "GPI");
		}
		break;

	   case IDM_F_METAFILE_LOAD:/* load metafile from menu item "METAFILE"*/
		*Parm.Message = '\0';
		strcpy(Filemask, Parm.MetafilePath);
		FileName = strrchr(Filemask, (int)'\\');
		if (FileName == NULL)
		   FileName = Filemask;
		else
		   FileName++;
		strcpy(FileName, "*.MET");

		/* Display File Dialog */
		DialogHeader = GetString(Parm.hAB, FILEDLG_META_HEADER,
					 ALLOC_STRING);
		if (OpenFileDialog(Parm.hWndFrame, DialogHeader,
				   Filemask, Filename))
		   {
		      strcpy(Parm.MetafilePath, Filename);
		      WinSendMsg(hWnd,
				 IDM_F_METAFILE,
				 MPFROMSHORT(0),
				 MPFROMSHORT(0));
		   }
		free(DialogHeader);
		break;

	   case IDM_F_PRINT:		  /* menu item "Print"		*/
		switch (Parm.CheckedItem)
		   {
		   case 1:	       /* print GPI */
			PrintGpiMeta(&Parm, DRAW_GPI);
			break;
		   case 2:	       /* print Metafile */
			PrintGpiMeta(&Parm, DRAW_META);
			break;
		   }
		break;

	   case IDM_O_PRINTPROPERTIES:	 /*  menu item "Job properties" */
		QueryJobProperties(Parm.hAB,
				   &Parm.DriverData,
				   &Parm.DriverDataLength,
				   Parm.DriverName,
				   Parm.QueueName,
				   NULL, TRUE);

		break;

	   case IDM_H_HELPINDEX:	/* menu item "Help for Index"  */
		if (Parm.hWndGRAPHICHelp)
		   WinSendMsg(Parm.hWndGRAPHICHelp, HM_DISPLAY_HELP,
			     MPFROMSHORT(HELP_INDEX), 0L);
		break;

	   case IDM_H_HELPGEN:		/* menu item "Help for General"*/
		if (Parm.hWndGRAPHICHelp)
		   WinSendMsg(Parm.hWndGRAPHICHelp, HM_DISPLAY_HELP,
			     MPFROMSHORT(HELP_GEN), 0L);
		break;

	   case IDM_H_HELPUSING:	/* menu item "Help for Using"  */
		if (Parm.hWndGRAPHICHelp)
		   WinSendMsg(Parm.hWndGRAPHICHelp, HM_DISPLAY_HELP,
			     MPFROMSHORT(HELP_USING), 0L);
		break;

	   case IDM_H_HELPKEYS:		/* menu item "Help for Keys"   */
		if (Parm.hWndGRAPHICHelp)
		   WinSendMsg(Parm.hWndGRAPHICHelp, HM_DISPLAY_HELP,
			      MPFROMSHORT(HELP_KEYS), 0L);
		break;

	   case IDM_H_ABOUT:		/* menu item "About"	       */
		WinDlgBox(HWND_DESKTOP, hWnd, (PFNWP)AboutDlg,
			  0, ID_ABOUT, (PBYTE)NULL);
		break;

	   default:
		break; /* End of default case for switch(mp1) */
	   }
	 break; /* End of WM_COMMAND */

    case IDM_F_METAFILE:
	 StopDrawing(&Parm);
	 if (GpiResetPS(Parm.hpsClient, GRES_ALL) == GPI_ERROR)
	     DispError(Parm.hAB,Parm.hWndClient);
	 if (LONGFROMMP(mp1) == 0L)
	    hmfPicture = GpiLoadMetaFile(Parm.hAB, Parm.MetafilePath);
	 else
	    hmfPicture = (HMF)LONGFROMMP(mp1);
	 if (hmfPicture == (HMF)NULL)
	    {
	    StringWithVarText(Parm.hAB, ERRMSG_METAFILE_FAILED,
			      Parm.MetafilePath, Parm.Message),
	    Parm.fNotReady = FALSE;
	    DisplayMessage(Parm.hWndClient, Parm.Message);
	    }
	 else
	    {
	    SendCommand(&Parm, (ULONG)SET_TRANSFORM,
			(ULONG)hmfPicture);
	    SendCommand(&Parm, (ULONG)DRAW_ORDERS, (ULONG)NULL);
	    Parm.DrawThreadActivated = TRUE;
	    CheckPulldown(&Parm, 2);
	    if (LONGFROMMP(mp1) == 0L)
	       SetTitleBarText(&Parm, Parm.MetafilePath);
	    else
	       SetTitleBarText(&Parm, "!Clipboard Metafile");
	    }
	 break;

    case WM_INITMENU:	   /* message appears on selecting a pulldown menu */
	 switch(SHORT1FROMMP(mp1))
	    {
	    case IDM_FILE:	       /* set items "Print" and "Print      */
	    case IDM_OPTIONS:	       /* properties" when menu is selected */
		 SetPrintItems(&Parm);
		 break;
	    case IDM_F_METAFILE:
		 /* test, if metafile data in the clipboard */
		 /* test, if a metafile was selected */
		   if (*Parm.MetafilePath != '\0')
		    {
		    FileName = strrchr(Parm.MetafilePath, (int)'\\');
		    if (FileName == NULL)
		       FileName = Parm.MetafilePath;
		    else
		       FileName++;
		    WinSendMsg(HWNDFROMMP(mp2),
			       MM_INSERTITEM,
			       MPFROMP(&mi),
			       MPFROMP(FileName));
		    MenuUpdated = TRUE;
		    }
		 break;
	    }
	 break;

   case WM_DESTROY:
      /*
       * The application has asked for the window to be destroyed.
       * Where appropriate, the region and the graphics presentation
       * spaces are destroyed.
       */
      if (Parm.DrawParm.hrgnInvalid != (HRGN)NULL)
	 if (GpiDestroyRegion(Parm.hpsClient,
			      Parm.DrawParm.hrgnInvalid) == GPI_ERROR)
	     DispError(Parm.hAB,Parm.hWndClient);
      if (Parm.hpsClient !=(HPS)NULL)
	 {
	  if (GpiAssociate(Parm.hpsClient, (HDC)NULL) == GPI_ERROR)
	      DispError(Parm.hAB,Parm.hWndClient);
	  if (GpiDestroyPS(Parm.hpsClient) == GPI_ERROR)
	      DispError(Parm.hAB,Parm.hWndClient);
	 }
      if (Parm.hpsPaint !=(HPS)NULL)
	 if (GpiDestroyPS(Parm.hpsPaint) == GPI_ERROR)
	     DispError(Parm.hAB,Parm.hWndClient);
      break;

   case WM_MINMAXFRAME:		  /* minimize/maximize window */
	WindowPos = PVOIDFROMMP(mp1);
	if (WindowPos->fl & SWP_MINIMIZE)
	   {
	   WindowMinimized = TRUE;
	   if (Parm.DrawThreadActivated)
	      SendCommand(&Parm, (ULONG)FLUSH_COMMAND, (ULONG)NULL);
	   }
	else
	   {
	   WindowMinimized = FALSE;
	   }
	break;


   case HM_QUERY_KEYS_HELP:
	/*
	 * If the user requests Keys Help from the help pulldown,
	 * IPF sends the HM_QUERY_KEYS_HELP message to the application,
	 * which should return the panel id of the Keys Help panel
	 */
	return (MRESULT)PANEL_HELPKEYS;	 /* return id of key help panel */
	break;

   case HM_ERROR:
	/*
	 * If an IPF error occurs, an HM_ERROR message will be sent to
	 * the application.
	 */
	if (Parm.hWndGRAPHICHelp && ((ULONG)mp1) == HMERR_NO_MEMORY)
	   {
	   WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
			 GetString(Parm.hAB, ERRMSG_HELP_TERMINATED,
				   STATIC_STRING),
			 Parm.ProgramTitle,
			 1,
			 MB_OK | MB_APPLMODAL | MB_MOVEABLE);
	   WinDestroyHelpInstance(Parm.hWndGRAPHICHelp);
	   }
	 else
	   {
	   strcpy(Parm.ErrorMsg,
		  GetString(Parm.hAB, ERRMSG_HELP_ERROR, STATIC_STRING));
	   ltoa(LONGFROMMP(mp1), &Parm.ErrorMsg[strlen(Parm.ErrorMsg)], 16);

	   WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
			 (PSZ)Parm.ErrorMsg,
			 (PSZ)Parm.ProgramTitle,
			 1,
			 MB_OK | MB_APPLMODAL | MB_MOVEABLE);
	   }
	break;

   case WM_SIZE:     /* code for sizing client area */
	if (WindowMinimized)
	   break;
	if (Parm.ResizeWindow)
	   AdjustWindowSize(&Parm);
	else
	   Parm.ResizeWindow = TRUE;
	if (Parm.DrawThreadActivated)  /* cancel any pending draw requests */
	{
	   SendCommand(&Parm, (ULONG)FLUSH_COMMAND, (ULONG)NULL);
	   SendCommand(&Parm, (ULONG)SIZING, (ULONG)NULL);
	}
	WinPostMsg(Parm.InfoWnd.hWnd,	  /* reposition information window */
		   POS_INFO_WND,
		   MPFROMSHORT(0),
		   MPFROMSHORT(0));
	break;	     /* End of WM_SIZE */

   case WM_PAINT:    /* code for the window's client area */
	if (Parm.DrawThreadActivated)
	   return(WndProcPaint(&Parm));
	/* Obtain a handle to a cache presentation space */
	hPS = WinBeginPaint(hWnd, 0, 0);

	/* Determine the size of the client area */
	WinQueryWindowRect(hWnd, &rClient);

	/* Fill the background with the default background color */
	WinFillRect(hPS, &rClient, CLR_BACKGROUND);

	/* return presentation space to state before WinBeginPaint */
	WinEndPaint(hPS);

	break; /* End of WM_PAINT */

   default:
	/*
	 * For any message which you don't specifically provide a
	 * service routine, you should return the message to PM using
	 * the WinDefWindowProc function.
	 */
	return(WinDefWindowProc(hWnd, message, mp1, mp2));
	break;	/* End of default */
   }
return(0L);
} /* End of WndProc */

/*************************************************************************
 * Function: CheckPulldown
 *
 * Check one of the pulldown items "GPI", "METAFILE"
 *
 * Parameters: PMAIN_PARM   main parameter structure
 *	       ULONG	   number of item to check
 *
 * Result:  none
 *
 ***************************************************************************/
VOID CheckPulldown(PMAIN_PARM Parm, LONG index)
{
static	 ULONG	   Items[] =
		    {
		    IDM_F_GPI,
		    IDM_F_METAFILE,
		    };

/* if item already checked, do nothing */
   if (Parm->CheckedItem != index)
   {
      if (index == 0)		       /* If text is selected */
      {
	 WinSendMsg(Parm->hWndFrame,
		 WM_USER_DEFINED_CODE,
		 MPFROMSHORT(INIT_MLE),
		 MPFROMSHORT(TRUE));
      }
      if (Parm->CheckedItem == 0)      /* If text is deselected */
      {
	 WinSendMsg(Parm->hWndFrame,
		 WM_USER_DEFINED_CODE,
		 MPFROMSHORT(INIT_MLE),
		 MPFROMSHORT(FALSE));
      }
      Parm->CheckedItem = index;
      if (!index)
	 InvalidateTextRect(Parm->hWndClient);
   }
} /* End of CheckPullDown */

/*************************************************************************
 * Function: AdjustWindowSize
 *
 * resize frame window
 *
 * Parameters: PMAIN_PARM   main parameter structure
 *
 * Result:  none
 *
 ***************************************************************************/
VOID AdjustWindowSize(PMAIN_PARM Parm)
{
   SWP	      SizeFrame;
   SWP	      SizeClient;
   HPS	      hPS;
   SIZEF      CharSizeClient;

   hPS = WinGetPS(Parm->hWndClient);	     /* get PS of client area	   */

   /* get size of character box */
   if (GpiQueryCharBox(hPS, (PSIZEF)&CharSizeClient) == GPI_ERROR)
       DispError(Parm->hAB,Parm->hWndClient);

   WinReleasePS(hPS);			     /* release presentation space */

   WinReleasePS(hPS);			     /* release presentation space */
   /*
    * resize window, so that at least the information line and one line of
    * the multiline edit field can be displayed
    */
   WinQueryWindowPos(Parm->hWndFrame,
		     &SizeFrame);

   WinQueryWindowPos(Parm->hWndClient,
		     &SizeClient);
} /* End of AdjustWindowSize */

/*************************************************************************
 * Function: WndProcCreate
 *
 * The WndProcCreate function obtains a device context for the client
 * area of the window, creates a normal graphics presentation space,
 * and associates the two. The presentation page is defined in pels,
 * and is the same size as the maximum client area.
 * A second graphics presentation space is defined for use by the main
 * thread. This is the same size and format as the first presentation
 * space.  WndProcCreate also defines an empty region for hpsClient.
 * This is used by the asynchronous thread to accumulate invalid
 * regions in the client area.
 *
 * Parameters: HWND	    window handle of the frame window
 *	       PMAIN_PARM   main parameter structure
 *
 * Result:  MRESULT	    TRUE if an error appeared, otherwise false
 *
 ***************************************************************************/
MRESULT WndProcCreate(HWND hwnd, PMAIN_PARM Parm)
{
   SIZEL      sizlClient;

/* query size of Desktop */
   sizlClient.cx = WinQuerySysValue(HWND_DESKTOP, SV_CXFULLSCREEN);
   sizlClient.cy = WinQuerySysValue(HWND_DESKTOP, SV_CYFULLSCREEN);

   /* open device context for client area */
   Parm->hdcClient = WinOpenWindowDC(hwnd);
   /* create presentation space for client area	 and associate it with DC */
   Parm->hpsClient = GpiCreatePS(Parm->hAB,
				 Parm->hdcClient,
				 &sizlClient,
				 GPIA_ASSOC | PU_PELS);
   if (Parm->hpsClient == (HPS)NULL)
      return((MRESULT)TRUE);

   /* create presentation space for painting */
   Parm->hpsPaint = GpiCreatePS(Parm->hAB,
				(HDC)NULL,
				&sizlClient,
				PU_PELS);

   /* create region for client area */
   Parm->DrawParm.hrgnInvalid = GpiCreateRegion(Parm->hpsClient,
						(ULONG)0, (PRECTL)NULL);

   return(FALSE);
} /* End of WndProcCreate */

/*************************************************************************
 * Function: SetPrintItems
 *
 * Test (default) printer queue and enable/disable menu items "Print" and
 * "Print properties".
 *
 * Parameters: PMAIN_PARM   main parameter structure
 *
 * Result:  none
 *
 ***************************************************************************/
VOID SetPrintItems(PMAIN_PARM Parm)
{
BOOL	   QueuePredefined;

					/* test, if queue preselected */
   if (Parm->QueueName[0] == '\0')
      QueuePredefined = FALSE;
   else
      QueuePredefined = TRUE;
/*
 * if queue preselected, test if queue is already valid, otherwise query
 * default queue
 */
   if (QueryDefaultQueue(Parm->QueueName, Parm->DriverName))
   {
   /*
    * if item "Print" is disabled and no print request is running, enable
    * menu item "Print"
    */
      if (!Parm->PrintEnabled)
      {
	 if (!Parm->PrintStatus)
	 {
	    WinSendMsg(WinWindowFromID(Parm->hWndFrame, (USHORT)FID_MENU),
		    MM_SETITEMATTR,
		    MPFROM2SHORT(IDM_F_PRINT, TRUE),
		    MPFROM2SHORT(MIA_DISABLED, ~MIA_DISABLED));
	    Parm->PrintEnabled = TRUE;
	 }
      }
      else
   /*
    * if item "Print" is enabled and a print request is running, disable
    * menu item "Print"
    */
	 if (Parm->PrintStatus)
	 {
	    WinSendMsg(WinWindowFromID(Parm->hWndFrame, (USHORT)FID_MENU),
		    MM_SETITEMATTR,
		    MPFROM2SHORT(IDM_F_PRINT, TRUE),
		    MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
	    Parm->PrintEnabled = FALSE;
	 }
   /* if menu item "Print properties" is disabled, enable item */
      if (!Parm->PrintPropertiesEnabled)
      {
	 WinSendMsg(WinWindowFromID(Parm->hWndFrame, (USHORT)FID_MENU),
		 MM_SETITEMATTR,
		 MPFROM2SHORT(IDM_O_PRINTPROPERTIES, TRUE),
		 MPFROM2SHORT(MIA_DISABLED, ~MIA_DISABLED));
	 Parm->PrintPropertiesEnabled = TRUE;
      }
   }
   else
   {
   /*
    * if printer queue is not valid, disable menu items "Print" and
    * "Print properties
    */
      if (Parm->PrintEnabled)
      {
	 WinSendMsg(WinWindowFromID(Parm->hWndFrame, (USHORT)FID_MENU),
		 MM_SETITEMATTR,
		 MPFROM2SHORT(IDM_F_PRINT, TRUE),
		 MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
	 Parm->PrintEnabled = FALSE;
      }
      if (Parm->PrintPropertiesEnabled)
      {
	 WinSendMsg(WinWindowFromID(Parm->hWndFrame, (USHORT)FID_MENU),
		 MM_SETITEMATTR,
		 MPFROM2SHORT(IDM_O_PRINTPROPERTIES, TRUE),
		 MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
	 Parm->PrintPropertiesEnabled = FALSE;
      }
      if (!QueuePredefined)
	 *Parm->QueueName = '\0';
   }
} /* End of SetPrintItems */

/*************************************************************************
 * Function: StopDrawing
 *
 * Stop drawing "GPI or "METAFILE"  on request.
 *
 * Parameters: PMAIN_PARM   main parameter structure
 *
 * Result:  none
 *
 ***************************************************************************/
VOID StopDrawing(PMAIN_PARM Parm)
{
ULONG	   ResetCount;
    /*
     * if not "GPI" or "METAFILE"  do nothing
     * if ((Parm->CheckedItem < 1) || (Parm->CheckedItem > 3))
     */
   if (Parm->CheckedItem < 1)
      return;

   if (Parm->DrawThreadID != -1)
   {
      if (Parm->hpsClient != (HPS)NULL)
	 if (GpiSetStopDraw(Parm->hpsClient, (LONG)TRUE) == GPI_ERROR)
	    DispError(Parm->hAB,Parm->hWndClient);
      WinRequestMutexSem(Parm->hmtxsemStoppable, (ULONG)-1);
      Parm->fStoppable = TRUE;
      DosReleaseMutexSem(Parm->hmtxsemStoppable);
      SendCommand(Parm, FLUSH_COMMAND, 0L);
      DosResetEventSem(Parm->hevsemStop, &ResetCount);
      if (SendCommand(Parm, STOP_DRAWING, 0L))
	 WinWaitEventSem(Parm->hevsemStop, (ULONG)-1);
   }
} /* End of StopDrawing */

/*************************************************************************
 * Function: AboutDlg
 *
 * Dialog procedure for About dialog box.
 *
 * Parameters: HWND	    window handle of dialog box
 *	       USHORT	    message
 *	       MPARAM	    message parameter 1
 *	       MPARAM	    message parameter 2
 *
 * Result:  MRESULT	    message result
 *
 ***************************************************************************/
MRESULT EXPENTRY AboutDlg(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{

   switch (msg)
   {
   case DLG_OK:
	WinDismissDlg(hWnd, FALSE);
	break;
   default:
	return(WinDefDlgProc(hWnd, msg, mp1, mp2));
   }
   return (MRESULT)FALSE;
} /* End of AboutDlg */

/**************************************************************************
 * Function: InvalidateTextRect
 *
 * Query size of information line and invalidate that rectangle.
 *
 * Parameters: HWND	    window handle of client area
 *
 * Result:  none
 *
 ***************************************************************************/
static VOID InvalidateTextRect(HWND hWnd)
{
   HPS	       hPS;
   FONTMETRICS ActFont;
   RECTL       Rectl;

   WinQueryWindowRect(hWnd, &Rectl);
   hPS = WinGetPS(hWnd);
   if (GpiQueryFontMetrics(hPS, (LONG)sizeof(FONTMETRICS), &ActFont) == GPI_ERROR)
       DispError(Parm.hAB,Parm.hWndClient);
   WinReleasePS(hPS);

   Rectl.yBottom = Rectl.yTop - ActFont.lMaxBaselineExt;
   WinInvalidateRect(hWnd, &Rectl, FALSE);
} /* End of InvalidateTextRect */

/*************************************************************************
 * Function: WndProcI
 *
 * Window procedure for information window.
 *
 * Parameters: HWND	    window handle of information window
 *	       USHORT	    message
 *	       MPARAM	    message parameter 1
 *	       MPARAM	    message parameter 2
 *
 * Result:  MRESULT	    message result
 *
 ***************************************************************************/
MRESULT EXPENTRY WndProcI(HWND hWndI, ULONG Msg, MPARAM mp1, MPARAM mp2)
{
	 PMAIN_PARM Parm;
	 FONTMETRICS ActFont;
	 HPS	    hPS;
	 SWP	    WinPos;
	 RECTL	    rInfo;
	 POINTL	    DrawPos;
static	 PSZ	    Message;

   if (Msg != WM_CREATE)
      Parm = WinQueryWindowPtr(hWndI, 0);

   switch (Msg)
   {
   case WM_CREATE:	/* Set window pointer to main parameter stucture   */
	Parm = (PMAIN_PARM)PVOIDFROMMP(mp1);
	Message = GetString(Parm->hAB, TEXT_SPOOLING_MESSAGE, ALLOC_STRING);
	WinSetWindowPtr(hWndI, 0, (PVOID)Parm);
	break;
   case ENABLE_INFO_WND:	       /* show/hide information window	   */
	if (Parm->InfoWnd.SizeX == 0)  /* if first call, calculate size of */
	   {			       /* information window		   */
	   hPS = WinGetPS(hWndI);
	   if (GpiQueryFontMetrics(hPS, (LONG)sizeof(FONTMETRICS), &ActFont) == GPI_ERROR)
	       DispError(Parm->hAB,Parm->hWndClient);
	   Parm->InfoWnd.SizeY = (LONG)ActFont.lMaxBaselineExt;
	   Parm->InfoWnd.DrawLine = (LONG)ActFont.lMaxDescender;
	   Parm->InfoWnd.SizeX = (LONG)12 * (LONG)ActFont.lAveCharWidth;
	   WinReleasePS(hPS);
	   WinSetWindowPos(hWndI,
			   (HWND)NULLHANDLE,
			   0L, 0L, Parm->InfoWnd.SizeX,
			   Parm->InfoWnd.SizeY,
			   SWP_SIZE | SWP_HIDE);
	   }
	/* show/hide information window */
	Parm->InfoWnd.EnableWindow = SHORT1FROMMP(mp1);
	if (!Parm->InfoWnd.EnableWindow)
	   {
	   WinSetWindowPos(hWndI, (HWND)NULLHANDLE,
			   0L, 0L, 0L, 0L,
			   SWP_HIDE);
	   }
	else
	   {
	   WinSendMsg(hWndI,
		      POS_INFO_WND,
		      MPFROMSHORT(0),
		      MPFROMSHORT(0));
	   WinInvalidateRect(hWndI, (PRECTL)NULL, TRUE);
	   }
	break;
   case POS_INFO_WND:		       /* reposition info window if frame */
	if (Parm->InfoWnd.EnableWindow)
	{
	WinQueryWindowPos(Parm->hWndClient, &WinPos); /* window is resized */
	WinSetWindowPos(hWndI, (HWND)HWND_TOP,
			WinPos.cx - Parm->InfoWnd.SizeX,
			WinPos.cy - Parm->InfoWnd.SizeY,
			0L, 0L,
			SWP_MOVE | SWP_SHOW);
	}
	break;
   case WM_PAINT:			     /* paint information window if*/
	if (Parm->InfoWnd.EnableWindow)	     /* window is shown		   */
	   {
	   hPS = WinBeginPaint(hWndI, 0, 0);
	   WinQueryWindowRect(hWndI, &rInfo);
	   WinFillRect(hPS, &rInfo, CLR_RED);
	   GpiSetColor(hPS, CLR_WHITE);
	   DrawPos.x = 4L;
	   DrawPos.y = (LONG)Parm->InfoWnd.DrawLine;
	   GpiCharStringAt(hPS, &DrawPos, strlen(Message) - 1L,
			   Message);
	   WinEndPaint(hPS);
	   }
	else
	   return(WinDefWindowProc(hWndI, Msg, mp1, mp2));
	break;
   default:
	return(WinDefWindowProc(hWndI, Msg, mp1, mp2));
   }
   return (MRESULT)FALSE;
} /* End of WndProcI */

/*************************************************************************
 * Function: SetTitleBarText
 *
 * Change Text of Titlebar
 *
 * Parameters: PMAIN_PARM   Pointer to main parameter structure
 *	       PSZ	    filename to display
 *
 * Result:  none
 *
 ***************************************************************************/
VOID SetTitleBarText(PMAIN_PARM Parm, PSZ Filename)
{
static	 CHAR	    TitleBarText[80];
	 PSZ	    Ptr;

   strcpy(TitleBarText, Parm->ProgramTitle);
   if (Filename != (PSZ)NULL)
      if (*Filename == '!')
      {
	 strcat(TitleBarText, " - ");
	 strcat(TitleBarText, &Filename[1]);
      }
      else
	 if (*Filename != '\0')
	 {
	    strcat(TitleBarText, " - \"");

	 /* Set Ptr to first character after the path if possible */
	    if ((Ptr = strrchr(Filename, '\\')) == NULL)
	       Ptr = Filename;
	    else
	       Ptr++;

	    strcat(TitleBarText, Ptr);
	    strcat(TitleBarText, "\"");
	 }

/* Set Title Bar Text */
   WinSetWindowText(WinWindowFromID(Parm->hWndFrame, FID_TITLEBAR),
		 TitleBarText);
} /* End of SetTitleBarText */

/**************************************************************************
 * Function: GetString
 *
 * Get String from resource file
 *
 * Parameters: HAB	    Anchor block handle
 *	       ULONG	    ID of string
 *	       BOOL	    FALSE - Use static field
 *			    TRUE  - allocate space for the string
 *
 * Result:  PSZ	       Pointer to the loaded string or NULL if error
 *
 ***************************************************************************/
PSZ GetString(HAB hAB, ULONG ID, BOOL Alloc)
{
   LONG	      sLength;
   static PSZ Field[256];
   PSZ	      Ptr;

   if ((sLength = WinLoadString(hAB,
				(HMODULE)NULLHANDLE,
				ID,
				sizeof(Field),
				(PSZ)Field)) == 0)
      return(NULL);

   if (Alloc)
   {
      Ptr = malloc(sLength + 1);
      memcpy(Ptr, Field, sLength + 1);
      return(Ptr);
   }

   return  (PSZ)Field ;
} /* End of GetString */

/**************************************************************************
 * Function: StringWithVarText
 *
 * Get String from resource file
 *
 * Parameters: HAB	    Anchor block handle
 *	       ULONG	    ID of string
 *	       PSZ	    Pointer to variable text
 *	       PSZ	    Pointer to output buffer
 *
 * Result:  PSZ	       Pointer to output buffer
 *
 ***************************************************************************/
PSZ StringWithVarText(HAB hAB, ULONG ID, PSZ VarText, PSZ Result)
{
   PSZ	      Field;
   PSZ	      Ptr;

   Field = GetString(hAB, ID, STATIC_STRING);

   if ((Ptr = strstr(Field, "<t>")) == NULL)
      Ptr = strstr(Field, "<T>");

   strcpy(Result, Field);

   if (Ptr != NULL)
   {
      strcpy(&Result[Ptr - Field], VarText);
      strcat(Result, &Ptr[3]);
   }

   return(Result);
} /* End of StringWithVarText */

/**************************************************************************
 * Function: TemplateOpenFilterProc
 *
 * TemplateOpenFilterProc - This is a procedure that will filter the help
 *			     messages to the open dialog.
 *
 * Parameters: HWND	   window handle of information window
 *	       USHORT	   message
 *	       MPARAM	   message parameter 1
 *	       MPARAM	   message parameter 2
 *
 ***************************************************************************/
MRESULT EXPENTRY TemplateOpenFilterProc(HWND hwnd, ULONG message,
					MPARAM mp1, MPARAM mp2)
{

  if(message == WM_HELP)
  {
      DisplayHelpPanel(HID_FS_OPEN_DLG_HELP_PANEL);
       return FALSE ;
  }

   return WinDefFileDlgProc( hwnd, message, mp1, mp2 ) ;
} /* End of TemplateOpenFilterProc */

/**************************************************************************
 * Function: DisplayHelpPanel(idPanel)
 *
 * DisplayHelpPanel - Displays the help panel whose id is given
 *
 *  Usage:  Called whenever a help panel is desired to be
 *	    displayed, usually from the WM_HELP processing
 *	    of the dialog boxes
 *
 *  Method: Sends HM_DISPLAY_HELP message to the help instance
 *
 ***************************************************************************/
VOID DisplayHelpPanel(SHORT idPanel)
{
   if(WinSendMsg(Parm.hWndGRAPHICHelp,
		 HM_DISPLAY_HELP,
		 MPFROMLONG(MAKELONG(idPanel, NULL)),
		 MPFROMSHORT(HM_RESOURCEID)))
   {
      strcpy(Parm.ErrorMsg,
	  GetString(Parm.hAB, ERRMSG_HELPDISPLAYERROR, STATIC_STRING));
   }

} /* End of DisplayHelpPanel */

/**************************************************************************
 * Function: DispError
 *
 *  DispError -- report an error returned from an API service.
 *
 *  Usage:  The error message is displayed using a message box
 *
 ***************************************************************************/
VOID DispErrorMsg(HAB hab, HWND hwndFrame, PCH FileName, LONG LineNum)
{
   PERRINFO  pErrInfoBlk;
   PSZ	     pszOffSet, pszErrMsg;
   ERRORID   ErrorId;
   PCH	     ErrorStr;
   CHAR	     szbuff[125];

   DosBeep(800,10);

   if (!hab)
   {					 /* Non-PM Error */
      WinLoadString(Parm.hAB, 0L, IDS_UNKNOWNMSG, sizeof(szbuff), (PSZ)szbuff);
      ErrorStr = malloc(strlen(szbuff)+strlen(FileName)+10);
      sprintf(ErrorStr, szbuff, FileName, LineNum);
      WinMessageBox(HWND_DESKTOP,	  /* Parent window is desk top */
		   hwndFrame,		 /* Owner window is our frame */
		   (PSZ)ErrorStr,	 /* PMWIN Error message	      */
		   "Error Message",	 /* Title bar message	      */
		   MSGBOXID,		 /* Message identifier	      */
		   MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */
      free(ErrorStr);
      return;
   }

   ErrorId = WinGetLastError(Parm.hAB);

   if ((pErrInfoBlk = WinGetErrorInfo(Parm.hAB)) != (PERRINFO)NULL)
   {
      pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
      pszErrMsg = ((PSZ)pErrInfoBlk) + *((PSHORT)pszOffSet);

      WinLoadString(Parm.hAB, 0L, IDS_ERRORMSG, sizeof(szbuff), (PSZ)szbuff);
      ErrorStr = malloc(strlen(szbuff)+strlen(pszErrMsg)+strlen(FileName)+10);
      sprintf(ErrorStr, szbuff, pszErrMsg, FileName, LineNum);

      WinMessageBox(HWND_DESKTOP,	  /* Parent window is desktop */
		   hwndFrame,		 /* Owner window is our frame */
		   (PSZ)ErrorStr,	 /* PMWIN Error message	      */
		   "Error Message",	 /* Title bar message	      */
		   MSGBOXID,		 /* Message identifier	      */
		   MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */

      free(ErrorStr);

      WinFreeErrorInfo(pErrInfoBlk);
   }
} /* End of DispErrorMsg */
/****************************** End of Graphic.c **************************/
