/**************************************************************************
 *  File name  :  img_main.c
 *
 *  Description:  This application serves as an example of porting a 16-bit
 *		  application to 32-bit.  It modifies a 16-bit application
 *		  which was built using the headers/libraries/tools
 *		  from the OS/2 1.3 toolkit and produces a pure 32-bit
 *		  application.
 *
 *		  This source file contains the following functions:
 *
 *		  main()
 *		  MainWndProc(hwnd, msg, mp1, mp2)
 *		  FrameWndProc(hwnd, msg, mp1, mp2)
 *		  MessageBox(hwnd idMsg, fsStyle, fBeep)
 *		  MainCommand(mp1, mp2)
 *		  ExitProc(usTermCode)
 *
 *  Concepts   :  porting
 *
 *  API's      :  WinInitialize
 *		  DosBeep
 *		  WinCreateMsgQueue
 *		  WinGetMsg
 *		  WinTerminate
 *		  WinDispatchMsg
 *		  WinBeginPaint
 *		  WinFillRect
 *		  WinEndPaint
 *		  WinInvalidateRect
 *		  GpiAssociate
 *		  GpiDestroyPS
 *		  GpiSetBitmap
 *		  GpiDeleteBitmap
 *		  GpiDestroyPS
 *		  DevCloseDC
 *		  WinIsChild
 *		  WinSetParent
 *		  WinPostMsg
 *		  WinQueryWindowRect
 *		  GpiQueryCurrentPosition
 *		  WinMapWindowPoints
 *		  WinCalcFrameRect
 *		  WinLoadMessage
 *		  WinAlarm
 *		  WinIsWindow
 *		  WinDestroyWindow
 *		  WinDestroyMsgQueue
 *		  DosExitList
 *
 *  Required
 *    Files    :  OS2.H, STRING.H, STDIO.H, IMG_MAIN.H, IMG_XTRN.H,
 *		  IMG_HELP.H
 *
 *  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 files, macros, defined constants, and externs
 */
#define INCL_DOSPROCESS
#define INCL_WINWINDOWMGR
#define INCL_WINFRAMEMGR
#define INCL_WINSYS
#define INCL_WINTRACKRECT
#define INCL_WINHELP
#define INCL_WINSTDFILE
#define INCL_GPIPRIMITIVES
#define INCL_GPIBITMAPS

/*
 *  Include files, macros, defined constants, and externs
 */
#include <os2.h>
#include <string.h>
#include <stdio.h>

#include "img_main.h"
#include "img_xtrn.h"
#include "img_help.h"

/*
 *  error defines
 */
#define RETURN_SUCCESS	     0	/* successful return in DosExit */
#define RETURN_ERROR	     1	/* error return in DosExit	*/
#define BEEP_WARN_FREQ	    60	/* frequency of warning beep	*/
#define BEEP_WARN_DUR	   100	/* duration of warning beep	*/

/*
 *  Entry point declarations
 */
VOID MainCommand(MPARAM mp1, MPARAM mp2);

/*
 *  Static variables
 */
HMQ    hmq;	      /* application queue handle */

/**************************************************************************
 *
 *  Name       : main()
 *
 *  Description: Initializes the PM environment, calls the
 *		 initialization routine, creates the main
 *		 window,  and polls the message queue
 *
 *  Concepts   : - obtains anchor block handle and creates message
 *		     queue
 *		 - calls the initialization routine
 *		 - creates the main frame window which creates the
 *		     main client window
 *		 - polls the message queue via Get/Dispatch Msg loop
 *		 - upon exiting the loop, exits
 *
 *  API's      :  WinInitialize
 *		  DosBeep
 *		  WinCreateMsgQueue
 *		  WinGetMsg
 *		  WinTerminate
 *		  WinDispatchMsg
 *
 *  Parameters :  [none]
 *
 *  Return     :  1 - if successful execution completed
 *		  0 - if error
 *
 *************************************************************************/
int main(void)
{
   QMSG	  qmsg;		 /* message structure */
#ifdef PORT_16
   USHORT rc;
#endif
#ifdef PORT_32
   ULONG  rc;
#endif

   vhab = WinInitialize(0);
   if(!vhab)
   {
       DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
       return RETURN_ERROR;
   }

   /* find a define for this v */
   hmq = WinCreateMsgQueue(vhab, 0);
   if(!hmq)
   {
       DosBeep(BEEP_WARN_FREQ, BEEP_WARN_DUR);
       WinTerminate(vhab);
       return RETURN_ERROR;
   }

   if(rc = Init())
   {
       MessageBox(HWND_DESKTOP, rc, 0, MB_OK | MB_ERROR, TRUE);
   }
   else
   {
       /* get/dispatch message loop */
       while (WinGetMsg(vhab, &qmsg, (HWND)NULL, 0, 0))
	  WinDispatchMsg(vhab, &qmsg);
   }

  /*
   * release any allocated resource - no need to check return codes
   */
#ifdef HELP_MANAGER_ENABLED
    /* destroy the help instance */
   HelpDestroyInstance();
#endif
   return RETURN_SUCCESS;
}   /* End of main */

/**************************************************************************
 *
 *  Name       : MainWndProc(hwnd, msg, mp1, mp2)
 *
 *  Description: Processes the messages sent to the main client
 *		 window.  This routine processes the basic
 *		 messages all client windows should process
 *		 and passes all others onto UserWndProc where
 *		 the developer can process any others.
 *
 *  Concepts   : Called for each message placed in the main
 *		 window's message queue
 *
 *		 A switch statement branches to the routines to be
 *		 performed for each message processed.	Any messages
 *		 not specifically process are passed to the user's
 *		 message processing procedure UserWndProc().
 *
 *  API's      :  WinBeginPaint
 *		  WinFillRect
 *		  WinEndPaint
 *		  WinInvalidateRect
 *		  GpiQueryCurrentPosition
 *		  WinQueryWindowRect
 *		  GpiAssociate
 *		  GpiDestroyPS
 *		  GpiSetBitmap
 *		  GpiDeleteBitmap
 *		  GpiAssociate
 *		  GpiDestroyPS
 *		  DevCloseDC
 *		  WinIsChild
 *		  WinSetParent
 *		  WinPostMsg
 *
 *  Parameters :  hwnd = window handle
 *		  msg  = message code
 *		  mp1  = first message parameter
 *		  mp2  = second message parameter
 *
 *  Return     :  values are determined by each message
 *
 *************************************************************************/
MRESULT EXPENTRY MainWndProc(
	     HWND hwnd,	     /* handle of window */
#ifdef PORT_16
	     USHORT  msg,     /* id of message */
#endif
#ifdef PORT_32
	     ULONG  msg,     /* id of message */
#endif
	     MPARAM mp1,     /* first message parameter */
	     MPARAM mp2)     /* second message parameter */
{
   PSWP	   pswp;
   BOOL	   fHScroll;
   RECTL   rcl;
   POINTL  ptl;

   switch (msg)
   {
       case WM_CREATE:
	  /*
	   * set application title to 'Untitled'
	   */
	   UtilUpdateTitleText(vhab,
			       ((PCREATESTRUCT)PVOIDFROMMP(mp2))->hwndParent,
			       "");

	   /* return FALSE to continue window creation, TRUE to abort it */
	   return (MRESULT)FALSE;
	   break;

       case WM_INITMENU:

	  /*
	   * disable/enable menu items as appropriate
	   */
	   MenuInit(mp1, mp2);
	   break;

       case WM_ERASEBACKGROUND:

	  /*
	   * The client window is cleared to SYSCLR_WINDOW
	   */
	   return (MRESULT)TRUE;
	   break;

       case WM_MINMAXFRAME:

	  /*
	   * the window can be maximized by double clicking on the
	   * title bar, clicking on the maximize icon, or by
	   * selecting the maximize option in the System Menu.
	   * The SizeCalculateMaxWindow() function is invoked to set the
	   * window to a size that is no larger than the loaded image.
	   */
	   pswp = (PSWP)mp1;
#if (defined(PORT_S132) || defined(PORT_32))
	   if (pswp->fl & SWP_MAXIMIZE) {
#else
	   if (pswp->fs & SWP_MAXIMIZE) {
#endif

	      /*
	       * disable options which aren't valid when
	       * the window is maximized
	       */
	       vfMaximized = TRUE;

	       if (vfDetail)
	       {
		   SizeCalculateMaxWindow(&rcl);
		   pswp->cy = (SHORT)(rcl.yTop - rcl.yBottom);
		   pswp->cx = (SHORT)(rcl.xRight - rcl.xLeft);
		   pswp->y  = (SHORT)rcl.yBottom;
		   pswp->x  = (SHORT)rcl.xLeft;
	       }
	   }
	   else

	      /*
	       * re-enable options which were invalid when
	       * the window was maximized
	       */
	       vfMaximized = FALSE;
	   break;

       case WM_PAINT:

	   WinBeginPaint(hwnd, vhps, (PRECTL)&rcl);
	   if (vfImgLoaded && vfDetail)

	      /*
	       * If an image has been loaded and the user has selected
	       * the 'Detail' view, the PaintUnSizedImage() function is
	       * invoked to draw the image data in the client window.
	       * The image is drawn unscaled, and clipped if necessary.
	       */
	       PaintUnSizedImage();

	   else if (vfImgLoaded && !vfDetail)

	      /*
	       * If an image has been loaded and the user has selected
	       * the 'Non-detailed' view, the PaintSizedImage() function is
	       * invoked to size the image and draw it.
	       * The image is drawn scaled to fit the window.
	       */
	       PaintSizedImage();

	   else
	      /*
	       * If no image data has been loaded, clear the window to
	       * the default system color.
	       */
	       WinFillRect(vhps, &rcl, SYSCLR_WINDOW);

	   WinEndPaint(vhps);
	   break;

       case WM_SIZE:

	  /*
	   * If the window size is altered and the image is being
	   * viewed in detail, the WndSize function is invoked to restrict
	   * the new window size and scroll-bar range to image limits.
	   * If the 'Non-detailed' view has been selected and the window
	   * size is altered, the image has to be redrawn to fit the window.
	   */
	   if (vfImgLoaded && vfDetail)
	       SizePositionImage(mp2);

	   WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
	   break;

       case WM_HSCROLL:
       case WM_VSCROLL:

	  /*
	   * scrolling is implemented only if an image has been
	   * loaded, the 'Detail' view has been selected, and there is
	   * image data still lying outside window limits.
	   */
	   fHScroll = (BOOL)(msg == WM_HSCROLL);
	   if (vfImgLoaded && vfDetail &&
	       (fHScroll ? vulScrollXMax > 0 : vulScrollYMax > 0))
	   {
	      GpiQueryCurrentPosition(vhps, &ptl);
	      WinQueryWindowRect(hwnd, &rcl);

	       /* call the appropriate scroll routine */
	      (fHScroll ? SizeHScroll(mp2, rcl, ptl) :
			  SizeVScroll(mp2, rcl, ptl));
	   }
	   break;

       case WM_DESTROY:

	  /*
	   * delete the image graphics presentation space
	   */
	   GpiAssociate(vhps, (HDC)NULL);
	   GpiDestroyPS(vhps);

	   if (vfImgLoaded)
	   {
	      /*
	       * Free any allocated memory
	       */
#if (defined(PORT_16) || defined(PORT_S132))
	       UtilMemoryFree(SELECTOROF(vpbImgBuf));
#else
	       UtilMemoryFree(vpbImgBuf);
#endif

	      /*
	       * Release all bit-map resources and close the memory
	       * device context
	       */
	       GpiSetBitmap(vhpsMem, (HBITMAP)NULL);
	       GpiDeleteBitmap(vhbm);
	       GpiAssociate(vhpsMem, (HDC)NULL);
	       GpiDestroyPS(vhpsMem);
	       DevCloseDC(vhdcMem);
	   }

	  /*
	   * ensure that the scroll bars are child windows of the
	   * frame, so that they will be destroyed automatically.
	   */
	   if (!WinIsChild(vhwndHScroll, vhwndFrame))
	   {
	       WinSetParent(vhwndVScroll, vhwndFrame, FALSE);
	       WinSetParent(vhwndHScroll, vhwndFrame, FALSE);
	   }
	   break;

       case WM_CLOSE:
	   WinPostMsg(hwnd, WM_QUIT, (MPARAM)NULL, (MPARAM)NULL);
	   break;

       case WM_COMMAND:

	  /*
	   * processing of menu options is required
	   */
	   MainCommand(mp1, mp2);
	   break;

#ifdef HELP_MANAGER_ENABLED

       case HM_ERROR:
	  /*
	   * an error has occurred while using IPF help - report
	   * the error and destroy the help instance
	   */
	   MessageBox(vhwndFrame, IDMSG_HELPMANAGERERROR, 0,
		      MB_OK | MB_ERROR, TRUE);
	   vfHelpEnabled = FALSE;
	   break;
#endif
       default:

	   /*
	    * default must call WinDefWindowProc()
	    */
	  return WinDefWindowProc(hwnd, msg, mp1, mp2);
	  break;
   }
   return (MRESULT)NULL; /* window procedures should return 0 as a default */
}   /* End of MainWndProc */

/**************************************************************************
 *
 *  Name       : FrameWndProc(hwnd, msg, mp1, mp2)
 *
 *  Description: The purpose of the frame-window subclass procedure
 *		 is to restrict frame-window sizing so that it is
 *		 in step with the size of the client-window
 *		 presentation space.  The size of the image
 *		 determines the size of the maximized window.
 *		 Messages intended for the frame-window procedure
 *		 are sent here first.
 *
 *  Concepts   :  Called for each message placed in the main
 *		  window's message queue
 *
 *		 A switch statement branches to the routines to be
 *		 performed for each message processed.	Any messages
 *		 not specifically processed are passed to the user's
 *		 message processing procedure MainWndProc(). The
 *		 message trapped by this wndproc() are
 *		 WM_QUERYTRACKINFO & WM_ADJUSTWINDOWPOS which are
 *		 both posted to the frame procedure initially to
 *		 set up the default values.
 *
 *  API's      :  WinQueryWindowRect(vhwn
 *		  GpiQueryCurrentPosition
 *		  WinMapWindowPoints
 *		  WinCalcFrameRect
 *
 *  Parameters :  hwnd = window handle
 *		  msg  = message code
 *		  mp1  = first message parameter
 *		  mp2  = second message parameter
 *
 *  Return     :  values are determined by each message
 *
 *************************************************************************/
MRESULT EXPENTRY FrameWndProc(
	     HWND hwnd,	     /* handle of window */
#ifdef PORT_16
	     USHORT msg,     /* id of message (16-bit)	*/
#endif
#ifdef PORT_32
	     ULONG  msg,     /* id of message (32-bit)	 */
#endif
	     MPARAM mp1,     /* first message parameter */
	     MPARAM mp2)     /* second message parameter */
{
   SWP	      swp;
   PSWP	      pswp;
   RECTL      rcl;
   ULONG      rc;
   POINTL     ptl;
   PTRACKINFO ptrack;

   switch(msg)
   {
       case WM_ADJUSTWINDOWPOS:

	  /*
	   * restrict the size of the window so that it never exceeds
	   * the maximum size of the image - only handle explicitly
	   * for the 'Detail' mode
	   */
	   if (vfImgLoaded && vfDetail)
	   {
	       rc = (ULONG)(*vpfnwpFrame)(hwnd, msg, mp1, mp2);
	       pswp = (PSWP)mp1;
	       swp = *pswp;

	      /*
	       * Find the maximum allowed size, and ensure that
	       * the window size never exceeds this.
	       */
	       SizeCalculateMaxWindow(&rcl);
	       if (swp.cx > (SHORT)rcl.xRight)
		   swp.cx = (SHORT)rcl.xRight;
	       if (swp.cy > (SHORT)rcl.yTop)
		   swp.cy = (SHORT)rcl.yTop;
	       *pswp = swp;
	       return (MRESULT)rc;
	   }
	   else

	       /* let the system handle the message */
	       return (*vpfnwpFrame)(hwnd, msg, mp1, mp2);

	   break;

       case WM_QUERYTRACKINFO:

	  /*
	   * Invoke the normal frame-window procedure first in order
	   * to update the tracking rectangle to the new position.
	   */
	   (*vpfnwpFrame)(hwnd, msg, mp1, mp2);
	   ptrack = (PTRACKINFO)mp2;

	   if (vfImgLoaded && vfDetail)
	   {
	      /*
	       * Limit the size of the bounding rectangle only if the
	       * window is being sized.
	       * fs and rclBoundary are tracking information structure
	       * elements.
	       */
	       if (((ptrack->fs & TF_MOVE) != TF_MOVE) &&
		   ((ptrack->fs & TF_MOVE)	       ||
		    (ptrack->fs & TF_SETPOINTERPOS  )))
	       {
		   WinQueryWindowRect(vhwndClient, &rcl);
		   GpiQueryCurrentPosition(vhps, &ptl);

		   ptrack->rclBoundary.yTop    = rcl.yBottom + ptl.y;
		   ptrack->rclBoundary.yBottom = rcl.yBottom + ptl.y -
						 vsizlImg.cy;
		   ptrack->rclBoundary.xLeft   = rcl.xLeft + ptl.x;
		   ptrack->rclBoundary.xRight  = rcl.xLeft + ptl.x +
						 vsizlImg.cx;

		  /*
		   * Convert client boundary coordinates to screen
		   * coordinates.
		   */
		   WinMapWindowPoints(vhwndClient,
				      HWND_DESKTOP,
				      (PPOINTL)&ptrack->rclBoundary,
				      sizeof(RECTL)/sizeof(POINTL));

		  /*
		   * Calculate equivalent frame boundary from client
		   * boundary data.
		   */
		   WinCalcFrameRect(vhwndFrame,
				    (PRECTL)&ptrack->rclBoundary,
				    FALSE);

		   ptrack->fs |= TF_ALLINBOUNDARY;
	       }
	   }
	   return (MRESULT)TRUE;
       break;

   default:

      /*
       * return using the normal frame window procedure
       */
       return (*vpfnwpFrame)(hwnd, msg, mp1, mp2);
       break;

   }
   return (MRESULT)NULL; /* window procedures should return 0 as a default */
}   /* End of FrameWndProc */

/**************************************************************************
 *
 *  Name       : MessageBox(hwndOwner, idMsg, idCaption, fsStyle, fBeep)
 *
 *  Description: Displays the message box with the message
 *		 given in idMsg retrived from the message table
 *		 and using the style flags in fsStyle
 *
 *  Concepts   : Called whenever a MessageBox is to be displayed
 *		 - Message string is loaded from the process'
 *		     message table
 *		 - Alarm beep is sounded if desired
 *		 - Message box with the message is displayed
 *		 - WinMessageBox return value is returned
 *
 *  API's      :  WinLoadMessage
 *		  WinAlarm
 *		  WinMessageBox
 *
 *  Parameters :  hwnd	    =  handle of the owner of the message box
 *		  idMsg	    =  i.d. of the message in the message table
 *		  idCaption =  i.d. of the caption in the message table
 *		  fsStyle   =  style of the message box
 *		  fBeep	    =  whether to beep before displaying the box
 *
 *  Return     :  the values from WinMessageBox()
 *
 *************************************************************************/
ULONG MessageBox(
	 HWND hwndOwner,     /* handle of the message box's owner */
#ifdef PORT_16
	 USHORT idMsg,	      /* id of the message in the message table */
	 USHORT idCaption,    /* id of the caption in the message table */
	 USHORT fsStyle,      /* style of the message box */
#endif
#ifdef PORT_32
	 ULONG idMsg,	     /* id of the message in the message table */
	 ULONG idCaption,    /* id of the caption in the message table */
	 ULONG fsStyle,	     /* style of the message box */
#endif
	 BOOL fBeep)	     /* if TRUE, beep before message box is displayed */
{
   CHAR szText[MESSAGELEN];
   CHAR szCaption[MESSAGELEN];

   if (!WinLoadMessage(vhab,
		       (HMODULE)NULL,
		       idMsg,
		       MESSAGELEN,
		       (PSZ)szText))
   {
       WinAlarm(HWND_DESKTOP, WA_ERROR);
       return MBID_ERROR;
   }

  /*
   * if idCaption specified load string else use default
   * caption 'Error!'
   */
   if (idCaption)
   {
       if (!WinLoadMessage(vhab,
			   (HMODULE)NULL,
			   idCaption,
			   MESSAGELEN,
			  (PSZ)szCaption))
       {
	   WinAlarm(HWND_DESKTOP, WA_ERROR);
	   return MBID_ERROR;
       }
   }

   if (fBeep)
       WinAlarm(HWND_DESKTOP, WA_ERROR);

   return WinMessageBox(HWND_DESKTOP,
			hwndOwner,
			szText,
			(idCaption ? szCaption : (PSZ)NULL),
			MSGBOXID,
			fsStyle);
}   /* End of MessageBox */

/**************************************************************************
 *
 *  Name       : MainCommand(mp1, mp2)
 *
 *  Description: Calls the appropriate procedures that deal with
 *		 the selected menu item.
 *
 *  Concepts   : Routine is called whenever a WM_COMMAND message
 *		 is posted to the main window.
 *
 *		 A switch statement branches on the id of the
 *		 menu item that posted the message and the
 *		 appropriate action for that item is taken.  Any
 *		 menu ids that are not part of the standard menu
 *		 set are passed onto the user defined WM_COMMAND
 *		 processing procedure.
 *
 *  API's      :  [none]
 *
 *  Parameters :  mp1	    =  first message parameter
 *		  mp2	    =  second message parameter
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID MainCommand(MPARAM mp1, MPARAM mp2)
{
   switch (SHORT1FROMMP(mp1))
   {
       case IDM_FILEOPEN:

	  /*
	   * Open file and load/draw the selected image
	   */
	   FileOpen(mp2);
	   break;

       case IDM_VIEWDETAIL:

	  /*
	   * toggle between Detail and Non-Detail mode
	   */
	   ViewSwitchMode();
	   break;

       case IDM_VIEWSAVEPOSITION:

	  /*
	   * save the current image position
	   */
	   ViewSavePosition();
	   break;

       case IDM_VIEWRESTOREPOSITION:

	  /*
	   * save the current image position
	   */
	   ViewRestorePosition();
	   break;

       case IDM_VIEWFORECOLORBLACK:
       case IDM_VIEWFORECOLORWHITE:
       case IDM_VIEWFORECOLORBLUE:
       case IDM_VIEWFORECOLORGREEN:
       case IDM_VIEWFORECOLORYELLOW:
       case IDM_VIEWFORECOLORRED:
       case IDM_VIEWBACKCOLORBLACK:
       case IDM_VIEWBACKCOLORWHITE:
       case IDM_VIEWBACKCOLORBLUE:
       case IDM_VIEWBACKCOLORGREEN:
       case IDM_VIEWBACKCOLORYELLOW:
       case IDM_VIEWBACKCOLORRED:
	   ViewChangeColor(SHORT1FROMMP(mp1));
	   break;

#ifdef HELP_MANAGER_ENABLED
       case IDM_HELPUSINGHELP:
	   HelpUsingHelp();
	   break;

       case IDM_HELPGENERAL:
	   HelpGeneral();
	   break;

       case IDM_HELPINDEX:
	   HelpIndex();
	   break;
#endif
       case IDM_HELPPRODUCTINFO:
	   HelpProductInfo();
	   break;
    }
}   /* End of MainCommand */

/**************************************************************************
 *
 *  Name       : ExitProc(usTermCode)
 *
 *  Description: Cleans up certain resources when the application ends
 *
 *  Concepts   : Routine is called by DosExitList when the
 *		 application exits
 *
 *		 Global resources, such as the main window and
 *		 message queue, are destroyed and any system
 *		 resources used are freed.
 *
 *  API's      : WinIsWindow
 *		 WinDestroyWindow
 *		 WinDestroyMsgQueue
 *		 WinTerminate
 *		 DosExitList
 *
 *  Parameters : usTermCode = the termination code
 *
 *  Return     : EXLST_EXIT to the DosExitList handler
 *
 *************************************************************************/
VOID  ExitProc(USHORT usTermCode)
{
   /* destroy the main window if it exists */
   if (WinIsWindow(vhab, vhwndFrame))
       WinDestroyWindow(vhwndFrame);

   WinDestroyMsgQueue(hmq);
   WinTerminate(vhab);

   DosExitList(EXLST_EXIT, (PFNEXITLIST)NULL);	 /* termination complete */

   /* This routine currently doesn't use the usTermCode parameter so
    *  it is referenced here to prevent an 'Unreferenced Parameter'
    *  warning at compile time
    */
   usTermCode;

}   /* End of ExitProc */
/***************************  End of img_main.c	 *************************/
