/**************************************************************************
 *  File name  :  clipbrd.c
 *
 *  Description:  This program displays a standard window containing a
 *                picture.  The action bar contains the choices Edit and
 *                Help.  The Edit pull-down contains choices that let the
 *                user perform clipboard operations on the picture.
 *
 *                This source file contains the following functions:
 *
 *                  main( VOID );
 *                  ClipbrdHelp ( HWND, USHORT );
 *                  ClearRoutine( VOID );
 *                  CopyRoutine( VOID );
 *                  CutRoutine( VOID );
 *                  DrawRect( VOID );
 *                  EraseRect( VOID );
 *                  ExitRoutine( HWND );
 *                  Finalize( VOID );
 *                  GetBitmap( VOID );
 *                  Initialize( VOID );
 *                  MenuInitialization( MPARAM, MPARAM);
 *                  MouseButtonDown( HWND, MPARAM);
 *                  PaintRoutine( HWND );
 *                  PasteRoutine( VOID );
 *                  RemoveRect( VOID );
 *                  Report_Error( HAB );
 *                  WindowDestroy( VOID );
 *                  WindowInitialization( HWND );
 *                  ReportAPIError( PSZ );
 *                  ProductInfoDlgProc( HWND, ULONG, MPARAM, MPARAM );
 *                  HelpProductInfo( HWND );
 *                  SetSysMenu( HWND );
 *
 *  Concepts   :  clipboard
 *
 *  API's      :  DevOpenDC
 *                DevCloseDC
 *
 *                DosExit
 *
 *                GpiAssociate
 *                GpiBox
 *                GpiBitBlt
 *                GpiCreateBitmap
 *                GpiCreatePS
 *                GpiDestroyPS
 *                GpiDeleteBitmap
 *                GpiLoadBitmap
 *                GpiQueryBitmapParameters
 *                GpiQueryColor
 *                GpiQueryLineType
 *                GpiSetCurrentPosition
 *                GpiSetColor
 *                GpiSetLineType
 *                GpiSetBitmap
 *
 *                WinCreateStdWindow
 *                WinCreateMsgQueue
 *                WinCloseClipbrd
 *                WinDispatchMsg
 *                WinDefDlgProc
 *                WinDefWindowProc
 *                WinDestroyWindow
 *                WinDestroyMsgQueue
 *                WinDlgBox
 *                WinFillRect
 *                WinFreeErrorInfo
 *                WinGetMsg
 *                WinGetErrorInfo
 *                WinIsRectEmpty
 *                WinInitialize
 *                WinLoadString
 *                WinMessageBox
 *                WinOpenClipbrd
 *                WinOpenWindowDC
 *                WinPostMsg
 *                WinQuerySysValue
 *                WinQueryClipbrdData
 *                WinQuerySysPointer
 *                WinQueryWindowText
 *                WinQueryWindowRect
 *                WinQueryUpdateRect
 *                WinRegisterClass
 *                WinSendMsg
 *                WinSetFocus
 *                WinSetPointer
 *                WinSetClipbrdData
 *                WinSetRect
 *                WinSetWindowText
 *                WinTerminate
 *                WinTrackRect
 *                WinValidateRect
 *                WinWindowFromID
 *
 *  Required
 *    Files    :  OS2.H, STRING.H, CLIPBRD.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.                                                    *
 *************************************************************************/

#define INCL_DEV
#define INCL_WINWINDOWMGR
#define INCL_WINDIALOGS
#define INCL_WININPUT
#define INCL_WINRECTANGLES
#define INCL_WINACCELERATORS
#define INCL_WINPOINTERS
#define INCL_WINSETERRORINFO
#define INCL_WINMESSAGEMGR
#define INCL_WINBUTTONS
#define INCL_WINEDITCTLS
#define INCL_WINLISTBOXES
#define INCL_WINMENUS
#define INCL_WINSCROLLBARS
#define INCL_WINFRAMEMGR
#define INCL_WINFRAMECTLS
#define INCL_WINSYS
#define INCL_WINTRACKRECT
#define INCL_WINCLIPBOARD
#define INCL_GPICONTROL
#define INCL_GPITRANSFORMS
#define INCL_GPIPRIMITIVES
#define INCL_GPIREGIONS
#define INCL_GPICORRELATION
#define INCL_GPILCIDS
#define INCL_GPIBITMAPS
#define INCL_ERRORS
#define INCL_DOSPROCESS
#include <os2.h>
#include <string.h>
#include "clipbrd.h"

/*----------------- various window-dependent globals -------------------------*/

HAB     habMain;                       /* Anchor block handle                 */
HMQ     hmqMain;                       /* Application queue handle            */
HWND    hwndFrame=0L;                /* Frame control handle                */
HWND    hwndClient;                    /* Client area handle                  */
HPS     hpsClient=0L;                /* Client area gpi ps handle           */
HDC     hdcClient;                     /* Window dc handle                    */
HACCEL haccelMain;                     /* Accelerator table handle            */
HACCEL haccelTrack;                    /* Tracking rect accelerator table     */

/*-------------------------- memory bit map globals --------------------------*/

HDC     hdcMemory;
HBITMAP bmapMemory;
HPS     hpsMemory;

DRIVDATA    drvdata = {44L, 0L, "DISPLAY", 0L};

  struct {
    PSZ   address;
    PSZ   driver_name;
    PSZ   driver_data;
    PSZ   data_type;
    PSZ   comment;
    PSZ   proc_name;
    PSZ   proc_params;
    PSZ   spl_params;
    PSZ   network_params;
         }

    dcdatablk = {0L, "DISPLAY", 0L, 0L, 0L, 0L, 0L, 0L, 0L};

BITMAPINFOHEADER2 bmpMemory;           /* bitmap information header for
                                          create bitmap API                   */
POINTL  aptlCorners[4];                /* rectangle corners for BitBlting     */


/*---------------------- tracking rectangle info structure -------------------*/

TRACKINFO tiStruct;

/*----------------- only process WM_PAINT when we are ready ------------------*/

BOOL fPaintable = FALSE;

/*----------------------- Line attribute bundle ------------------------------*/

LINEBUNDLE lbndLineAttr = {(LONG)0,         /*  lColor;       */
                           (LONG)0,         /*  lBackColor;   */
                           FM_XOR,          /*  usMixMode;    */
                           (USHORT)0,       /*  usBackMixMode */
                           (FIXED)0,        /*  fxWidth;      */
                           (LONG)0,         /*  lGeomWidth;   */
                           (USHORT)0,       /*  usType;       */
                           (USHORT)0,       /*  usEnd;        */
                           (USHORT)0};      /*  usJoin;       */


/*---------------------------- loaded strings --------------------------------*/

char szTitleBar[CCHMAXSTRING];
char szTerminate[CCHMAXSTRING];
char szHelp[CCHMAXSTRING];
char szDefErrMesg[]  = "No further infomation";  /* message when no other     */
char szApiErrTitle[] = "API Error Return";       /* title for error message   */
LONG Status = SUCCESSX;
BOOL fErrMem=FALSE;

/*
 * Function prototypes
 */

MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);

/**************************************************************************
 *
 *  Name       : main()
 *
 *  Description: Initializes the PM environment and processes
 *               the application message queue until a WM_QUIT
 *               message is received.  It then destroys all OS/2
 *               PM services and terminates.
 *
 *  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
 *                 WinCreateMsgQueue
 *                 WinGetMsg
 *                 WinDispatchMsg
 *                 WinTerminate
 *
 *  Parameters :  [none]
 *
 *  Return     :  1 - if successful execution completed
 *                0 - if error
 *
 *************************************************************************/
int main()
{
   QMSG qmsgMain;                             /* application queue structure */

   habMain = WinInitialize(0L);
   hmqMain = WinCreateMsgQueue(habMain,0);

  /*
   * Test to see if the queue handle is 0L. If it is, it probably
   * means that the program has been installed in Desktop Manager as
   * VIO or Full Screen. In this case, the WinInitialize works,
   * but creating the message queue will fail and if you continue
   * with anything else you will get invalid selectors.
   * You can't even put up a message box so the program will
   * not start and the user will not know why!
   */
   if (hmqMain != (HMQ)0L)
   {
      if (!Initialize())
      {
         Report_Error(habMain);
         Finalize();
      }

      while (WinGetMsg(habMain, &qmsgMain, 0L, 0,0))
         WinDispatchMsg(habMain, &qmsgMain);

      Finalize();
   }
   else
   {
       WinTerminate(habMain);
   }
   return SUCCESSX;
}   /* end of main  */

/**************************************************************************
 *
 *  Name       : ClientWndProc
 *
 *  Description: This is the window procedure associated with the client
 *               area in the standard frame window.  It processes all
 *               messages either sent or posted to the client area,
 *               depending on the message command and parameters.
 *
 *  Concepts   : messaging
 *
 *  API's      : WinMessageBox
 *               WinDefWindowProc
 *
 *  Parameters :  hwnd = window handle
 *                msg  = message i.d.
 *                mp1  - first message parameter
 *                mp2  - second message parameter
 *
 *  Return     :  depends on type of message processed
 *
 *************************************************************************/
MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
   switch (msg)
   {
   case WM_CREATE:
      WindowInitialization(hwnd);
      break;

   case WM_DESTROY:
      WindowDestroy();
      break;

   case WM_HELP:
      WinMessageBox(HWND_DESKTOP,
                    hwnd,
                   (PSZ)szHelp,
                   (PSZ)szTitleBar,
                    0,
                    MB_MOVEABLE | MB_CUANOTIFICATION | MB_OK
                   );

      break;

   case WM_PAINT:
      PaintRoutine(hwnd);
      break;

   case WM_CLOSE:
      ExitRoutine(hwnd);
      break;

   case WM_INITMENU:
      MenuInitialization(mp1,mp2);
      break;

    /*
     * process menu item commands
     */
   case WM_COMMAND:
      switch (LOUSHORT(mp1))
      {
      case MENU_EXTHELP:
         ClipbrdHelp( hwnd, EXTHELP );
         break;
      case MENU_HELPINDEX:
         ClipbrdHelp( hwnd, HELPINDEX );
         break;
      case MENU_KEYSHELP:
         ClipbrdHelp( hwnd, KEYSHELP );
         break;
      case MENU_HELPUSING:
         ClipbrdHelp( hwnd, GENHELP );
         break;
      case MENU_PRODINFO:
         HelpProductInfo( hwnd );
         break;

      case MENU_COPY:
         CopyRoutine();
         break;
      case MENU_PASTE:
         PasteRoutine();
         break;
      case MENU_CUT:
         CutRoutine();
         break;
      case MENU_CLEAR:
         ClearRoutine();
         break;
        /*
         * Unrecognized WM_COMMAND IDs are processed in a default manner.
         */
      default:
         return(WinDefWindowProc(hwnd, msg, mp1, mp2));
      }
      break;

    /*
     * Clear an existing rectangle from the screen, and set the process into
     * track rectangle mode loop, after setting up the required parameters
     */
   case WM_BUTTON1DOWN:
      MouseButtonDown(hwnd,mp1);
      break;


   default:
      return(WinDefWindowProc(hwnd, msg, mp1, mp2));
   }
   return (MRESULT)0;
}  /*  end of ClientWndProc  */

/**************************************************************************
 *
 *  Name       : ClearRoutine
 *
 *  Description: erases a bounding rectangle from the screen
 *
 *  Concepts   :
 *
 *  API's      : WinIsRectEmpty
 *               WinSetRect
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID ClearRoutine()
{
    /*
     * If a bounding rectangle has been defined, erase that part of the
     * picture from the screen and the memory bit map.
     */
   if(!WinIsRectEmpty(habMain, &tiStruct.rclTrack))
   {
      EraseRect();
      WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);
   } /* endif */
   return;
}  /*  end of ClearRoutine */

/**************************************************************************
 *
 *  Name       : ClipbrdHelp
 *
 *  Description: displays the appropriate help string
 *
 *  Concepts   : help
 *
 *  API's      : WinLoadString
 *               WinMessageBox
 *
 *  Parameters : hwnd  = window handle
 *               HelpId = help string i.d.
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID ClipbrdHelp(HWND hwnd, USHORT HelpId)
{
   CHAR szTemp[CCHMAXSTRING];

   /*
    * Get the appropriate help string.
    */
   if (!WinLoadString(habMain, (HMODULE)0L, HelpId, (SHORT)CCHMAXSTRING,
                          (PSZ)szTemp))
      ReportAPIError("Error loading Help String");

   /*
    * Display the help string.
    */
   WinMessageBox(HWND_DESKTOP,
                  hwnd,
                  (PSZ)szTemp,
                  (PSZ)szTitleBar,
                  0,
                  MB_MOVEABLE | MB_CUANOTIFICATION | MB_OK );
   return;
}  /*  end of ClipbrdHelp  */

/**************************************************************************
 *
 *  Name       : CopyRoutine
 *
 *  Description: copies a rectangle into a fresh bitmap
 *
 *  Concepts   :
 *
 *  API's      : WinOpenClipbrd
 *               WinSetClipbrdData
 *               WinCloseClipbrd
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID CopyRoutine()
{
   HBITMAP bmapTempMem;
    /*
     * If a bounding rectangle has been defined, copy that part of the
     * memory bit map into a newly-created bitmap.
     * Give the new bit map to the clipboard. Finally, clear the
     * bounding rectangle.
     */
   bmapTempMem = GetBitmap();
   if(bmapTempMem != (HBITMAP)0L)
   {
      WinOpenClipbrd(habMain);
      WinSetClipbrdData(habMain, (ULONG)bmapTempMem, CF_BITMAP, 0L);
      WinCloseClipbrd(habMain);
      RemoveRect();
   } /* endif */
   return;
}  /*  end of CopyRoutine  */

/**************************************************************************
 *
 *  Name       : CutRoutine
 *
 *  Description: cuts a rectangle to the clipboard and removes it from the
 *               window
 *
 *  Concepts   : clipboard
 *
 *  API's      : WinOpenClipbrd
 *               WinSetClipbrdData
 *               WinCloseClipbrd
 *               WinSetRect
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID CutRoutine()
{
  HBITMAP bmapTempMem;
    /*
     * If a bounding rectangle has been defined, copy that part of the
     * memory bit map into a newly created bitmap.
     * Give the new bitmap to the clipboard. Finally clear the
     * bounding rectangle and erase that part of the picture from the
     * screen and the memory bit map.
     */
   bmapTempMem = GetBitmap();
   if (bmapTempMem != (HBITMAP)0L)
   {
      WinOpenClipbrd(habMain);
      WinSetClipbrdData(habMain, (ULONG)bmapTempMem, CF_BITMAP, 0L);
      WinCloseClipbrd(habMain);
      EraseRect();
      WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);
   } /* endif */
   return;
}  /*  end of CutRoutine  */

/**************************************************************************
 *
 *  Name       : DrawRect
 *
 *  Description: Draw a rectangle on the screen, using the last position
 *               and size of the tracking rectangle.
 *
 *  Concepts   :
 *
 *  API's      : GpiQueryLineType
 *               GpiSetLineType
 *               GpiQueryColor
 *               GpiSetColor
 *               GpiSetCurrentPosition
 *               GpiBox
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID DrawRect()
{
   POINTL ptlWork;
   LONG lSaveType;
   LONG lSaveColor;

   lSaveType = GpiQueryLineType(hpsClient);
   GpiSetLineType(hpsClient, LINETYPE_DOT);

   lSaveColor = GpiQueryColor(hpsClient);
   GpiSetColor(hpsClient,CLR_RED);

   ptlWork.x = tiStruct.rclTrack.xLeft;
   ptlWork.y = tiStruct.rclTrack.yBottom;
   GpiSetCurrentPosition(hpsClient, &ptlWork);

   ptlWork.x = tiStruct.rclTrack.xRight;
   ptlWork.y = tiStruct.rclTrack.yTop;
   GpiBox(hpsClient, DRO_OUTLINE, &ptlWork, 0L, 0L);

   GpiSetLineType(hpsClient, lSaveType);
   GpiSetColor(hpsClient,lSaveColor);
   return;
} /*  end of DrawRect  */

/**************************************************************************
 *
 *  Name       : EraseRect
 *
 *  Description: Erase a rectangle from the screen and from the memory
 *               bit map
 *
 *  Concepts   :
 *
 *  API's      : WinFillRect
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID EraseRect()
{
   RECTL rclErase;

   rclErase = tiStruct.rclTrack;
   WinFillRect(hpsMemory, &rclErase, CLR_WHITE);
   RemoveRect();
   return;
}  /*  end of EraseRect  */

/**************************************************************************
 *
 *  Name       : ExitRoutine
 *
 *  Description: called when PF3 is pushed, when Close is selected from
 *               the System Menu, or when Exit is selected
 *
 *  Concepts   :
 *
 *  API's      : WinFillRect
 *
 *  Parameters : hwnd = window handle
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID ExitRoutine(HWND hwnd)
{
   WinPostMsg(hwnd, WM_QUIT, (MPARAM)0, (MPARAM)0);
   return;
}   /*  end of ExitRoutine  */

/**************************************************************************
 *
 *  Name       : Finalize
 *
 *  Description: destroy all Presentation Manager resources and end the
 *               process
 *
 *  Concepts   : termination
 *
 *  API's      : WinDestroyWindow
 *               WinDestroyMsgQueue
 *               WinTerminate
 *               DosExit
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID Finalize( VOID )
{
   WinDestroyWindow(hwndFrame);
   WinDestroyMsgQueue(hmqMain);
   WinTerminate(habMain);
   DosExit( Status, 0);
   return;
}   /*  end of Finalize  */

/**************************************************************************
 *
 *  Name       : GetBitmap
 *
 *  Description: If a bounding rectangle has been defined, create a screen
 *               compatible device context and a screen compatible bit map.
 *               Select the bit map into the DC, create a
 *               suitably sized GPI PS and associate it with the DC.
 *               BitBlt that part of the
 *               screen defined by the rectangle into the new bit map.
 *               Destroy all other resources but return the bit map handle
 *               (to be passed to the clipboard)
 *
 *  Concepts   :
 *
 *  API's      :  WinIsRectEmpty
 *                WinQuerySysPointer
 *                WinSetPointer
 *                DevOpenDC
 *                GpiCreatePS
 *                GpiCreateBitmap
 *                GpiSetBitmap
 *                GpiBitBlt
 *                GpiAssociate
 *                GpiDestroyPS
 *                DevCloseDC
 *
 *  Parameters : [none]
 *
 *  Return     : bitmap handle
 *
 *************************************************************************/
HBITMAP GetBitmap()
{
   HDC   hdc;
   HPS   hps;
   HBITMAP bmap;
   register HPOINTER tptr;

   SIZEL sizlWork;

   if(WinIsRectEmpty(habMain, &tiStruct.rclTrack))
   {
      return((HBITMAP)0L);
   } /* endif */

   if ( (tptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE)) == 0 )
      ReportAPIError("Failed to get System pointer handle");
   WinSetPointer(HWND_DESKTOP, tptr);
  /*
   * It is a bounding rectangle, so we only want what is inside.
   */
   sizlWork.cx = tiStruct.rclTrack.xRight - tiStruct.rclTrack.xLeft - 1;
   sizlWork.cy = tiStruct.rclTrack.yTop - tiStruct.rclTrack.yBottom - 1;

   hdc = DevOpenDC(habMain,
                  OD_MEMORY,
                 (PSZ)"*",
                  8L,
                 (PDEVOPENDATA)&dcdatablk,
                 (HDC)0L
                 );
   if (hdc == 0) ReportAPIError("DevOpenDC Failure");

   bmpMemory.cbFix           = sizeof(bmpMemory);
   bmpMemory.cx              = (USHORT)sizlWork.cx;
   bmpMemory.cy              = (USHORT)sizlWork.cy;
   bmpMemory.cPlanes         = 1L;
   bmpMemory.cBitCount       = 24L;
   bmpMemory.ulCompression   = BCA_UNCOMP;
   bmpMemory.cxResolution    = 0;
   bmpMemory.cyResolution    = 0;
   bmpMemory.cclrUsed        = 0;
   bmpMemory.cclrImportant   = 0;
   bmpMemory.usUnits         = BRU_METRIC;
   bmpMemory.usRecording     = BRA_BOTTOMUP;
   bmpMemory.usRendering     = BRH_NOTHALFTONED;
   bmpMemory.cSize1          = 0;
   bmpMemory.cSize2          = 0;
   bmpMemory.ulColorEncoding = 0;
   bmpMemory.ulIdentifier    = 0;

   hps = GpiCreatePS(habMain, hdc, &sizlWork, GPIA_ASSOC | PU_PELS);
   if (hps == 0)
   {
     ReportAPIError("GpiCreatePS Failure");
   }

   bmap = GpiCreateBitmap(hps,
           (PBITMAPINFOHEADER2)&bmpMemory,
           0L,
           (PBYTE)NULL,
           (PBITMAPINFO2)NULL
            );
   if (bmap ==0)
   {
      ReportAPIError("GpiCreateBitmap Failure");
   }

   GpiSetBitmap(hps, bmap);

  /*
   * No adjustments to the top and right top (using lengths) since the
   * rectangles used for the BitBlt are non-inclusive (the bottom and
   * left are included, but not the top and right)
   */
   aptlCorners[0].x = 0;
   aptlCorners[0].y = 0;
   aptlCorners[1].x = sizlWork.cx;
   aptlCorners[1].y = sizlWork.cy;
  /*
   * Want to copy from inside the bounding rect. Increase the left & bottom
   * by one but leave the top & right since the rectangles used for the BitBlt
   * are non-inclusive (the bottom and left are included, but not the
   * top and right).
   */
   aptlCorners[2].x = tiStruct.rclTrack.xLeft + 1;
   aptlCorners[2].y = tiStruct.rclTrack.yBottom + 1;
   aptlCorners[3].x = tiStruct.rclTrack.xRight;
   aptlCorners[3].y = tiStruct.rclTrack.yTop;
   GpiBitBlt(hps, hpsMemory, 4L, aptlCorners, ROP_SRCCOPY, BBO_IGNORE);

   GpiSetBitmap(hps, (HBITMAP)0L);
   GpiAssociate(hps, (HDC)0L);
   GpiDestroyPS(hps);
   DevCloseDC(hdc);
   WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP,
                                                 SPTR_ARROW,
                                                 FALSE)
                                                 );
   return(bmap);
}  /*  end of GetBitmap  */

/**************************************************************************
 *
 *  Name       : Initialize
 *
 *  Description: initialize the PM interface,
 *               create an application message queue and a
 *               standard frame window
 *
 *  Concepts   :
 *
 *  API's      : WinLoadString
 *               WinRegisterClass
 *               WinSetPointer
 *               WinQuerySysPointer
 *               WinCreateStdWindow
 *               WinQueryWIndowText
 *               WinSetWindowText
 *
 *  Parameters : [none]
 *
 *  Return     : TRUE = successful initialization
 *               FALSE = error occurred
 *
 *************************************************************************/
BOOL Initialize()
{
   ULONG flCreate;
   BOOL  fErrTmp=FALSE;

   fErrMem = (BOOL)!WinLoadString(habMain,
                                (HMODULE)0L,
                                (USHORT)TERMINATE,
                                (SHORT)CCHMAXSTRING,
                                (PSZ)szTerminate
                                );
   fErrTmp = (BOOL)!WinLoadString(habMain,
                                (HMODULE)0L,
                                (USHORT)HELPPANEL,
                                (SHORT)CCHMAXSTRING,
                                (PSZ)szHelp
                                );
   if (fErrMem || fErrTmp)
      return(FALSE);

   if (!WinRegisterClass(habMain,
                         (PSZ)"My Class",
                         (PFNWP)ClientWndProc,
                         CS_SIZEREDRAW,
                         0))

      return(FALSE);

   WinSetPointer(HWND_DESKTOP,
                WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));

   flCreate = FCF_STANDARD;
   hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
                                 WS_VISIBLE,
                                 &flCreate,
                                 (PSZ)"My Class",
                                 (PSZ)NULL,
                                 WS_VISIBLE,
                                 (HMODULE)0L,
                                 AMENU,
                                 &hwndClient
                                 );

   WinSetWindowText(hwndFrame, "CLIPBOARD SAMPLE");

   WinSetPointer(HWND_DESKTOP,
                WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));

   if (hwndFrame == (HWND)0L)
   {
      return(FALSE);
   } /* endif */

  /*
   * Get the window title given to the window by the system
   */
   WinQueryWindowText(hwndFrame, CCHMAXSTRING, (PSZ)szTitleBar);

   return(TRUE);
}  /*  end of Initialize  */

/**************************************************************************
 *
 *  Name       : MenuInitialization
 *
 *  Description: set beginning attributes (enabled or not) of menu items
 *
 *  Concepts   : menu
 *
 *  API's      : WinIsRectEmpty
 *               WinSendMsg
 *               WinOpenClipbrd
 *               WinQueryClipbrdData
 *               WinCloseClipbrd
 *
 *  Parameters : mp1 = first message parameter
 *               mp2 = second message parameter
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID MenuInitialization(MPARAM mp1, MPARAM mp2)
{
   BOOL    fEmptyRect;
    /*
     * Menu items in the Edit pull-down may need to be grayed, depending on
     * the presence of a rectangle and the contents of the clipboard.
     */
   if (LOUSHORT(mp1) == SM_CLIPBRD)
   {
      fEmptyRect = WinIsRectEmpty(habMain, &tiStruct.rclTrack);
      WinSendMsg((HWND)mp2,
                    MM_SETITEMATTR,
                    MPFROM2SHORT(MENU_COPY, TRUE),
                    MPFROM2SHORT(MIA_DISABLED,
                                 fEmptyRect ? MIA_DISABLED : ~MIA_DISABLED)
                                );
      WinSendMsg((HWND)mp2,
                    MM_SETITEMATTR,
                    MPFROM2SHORT(MENU_CUT, TRUE),
                    MPFROM2SHORT(MIA_DISABLED,
                                 fEmptyRect ? MIA_DISABLED : ~MIA_DISABLED)
                                );
      WinSendMsg((HWND)mp2,
                    MM_SETITEMATTR,
                    MPFROM2SHORT(MENU_CLEAR, TRUE),
                    MPFROM2SHORT(MIA_DISABLED,
                                 fEmptyRect ? MIA_DISABLED : ~MIA_DISABLED)
                                );

      WinOpenClipbrd(habMain);

      if ((HBITMAP)WinQueryClipbrdData(habMain, CF_BITMAP) != (HBITMAP)0L &&
            !fEmptyRect)
      {
         fEmptyRect = TRUE;
      }
      else
      {
         fEmptyRect = FALSE;
      }
      WinSendMsg((HWND)mp2,
                 MM_SETITEMATTR,
                 MPFROM2SHORT(MENU_PASTE, TRUE),
                 MPFROM2SHORT(MIA_DISABLED,
                 fEmptyRect ? ~MIA_DISABLED : MIA_DISABLED)
                           );
      WinCloseClipbrd(habMain);
   }
}   /*  end of MenuInitialization  */

/**************************************************************************
 *
 *  Name       : MouseButtonDown
 *
 *  Description: process the mouse button interface
 *
 *  Concepts   : rectangle tracking
 *
 *  API's      : WinSetFocus
 *               WinIsRectEmpty
 *               WinSetRect
 *               WinQueryWindowRect
 *               WinTrackRect
 *
 *  Parameters : hwnd = window handle
 *               mp1 = message parameter
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID MouseButtonDown(HWND hwnd, MPARAM mp1)
{
    /*
     * As the application is handling the button message, set the focus
     * to the frame window.
     */
   WinSetFocus(HWND_DESKTOP,hwndClient);

    /*
     * Clear an existing rectangle from the screen, and set the process into
     * track rectangle mode loop, after setting up the required parameters.
     */
   if(!WinIsRectEmpty(habMain, &tiStruct.rclTrack))
   {
      RemoveRect();
      WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);
   } /* endif */

   tiStruct.cxBorder = 1;
   tiStruct.cyBorder = 1;
   tiStruct.cxGrid = 0;
   tiStruct.cyGrid = 0;
   WinSetRect(habMain, &tiStruct.rclTrack,
             LOUSHORT(mp1),
             HIUSHORT(mp1),
             LOUSHORT(mp1),
             HIUSHORT(mp1));
   WinQueryWindowRect(hwnd, &tiStruct.rclBoundary);
   tiStruct.ptlMinTrackSize.x = 1;
   tiStruct.ptlMinTrackSize.y = 1;
   tiStruct.ptlMaxTrackSize.x = ++tiStruct.rclBoundary.xRight;
   tiStruct.ptlMaxTrackSize.y = ++tiStruct.rclBoundary.yTop;
   tiStruct.fs  = TF_STANDARD | TF_ALLINBOUNDARY | TF_RIGHT | TF_BOTTOM;
   WinTrackRect(hwnd, (HPS)0L, &tiStruct);
   if((tiStruct.rclTrack.xRight - tiStruct.rclTrack.xLeft) > 2 &&
       (tiStruct.rclTrack.yTop - tiStruct.rclTrack.yBottom) > 2)
   {
      DrawRect();
   }
   else
   {
      WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);
   } /* endif */
}    /*  end of MouseButtonDown  */

/**************************************************************************
 *
 *  Name       : PaintRoutine
 *
 *  Description: display bits in the window
 *
 *  Concepts   :
 *
 *  API's      : WinQueryUpdateRect
 *               GpiBitBlt
 *               WinInvalidateRect
 *               WinIsRectEmpty
 *
 *
 *  Parameters : hwnd = window handle
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID PaintRoutine(HWND hwnd)
{
   RECTL   rclUpdt;
   BOOL    RC;
     /*
      * If we are in a position to update the window, get the invalidated
      * rectangle and use this to copy from the memory bit map to the screen,
      * using a BitBlt. Finally, validate the updated rectangle.
      */
   if (fPaintable)
   {
       WinQueryUpdateRect(hwnd, &rclUpdt);
   /*
    * Want the top & right-hand side, so increase by one, since the
    * rectangles used for the BitBlt are non-inclusive (the bottom
    * and left are included, but not the top and right).
    */
       aptlCorners[0].x = rclUpdt.xLeft;
       aptlCorners[0].y = rclUpdt.yBottom;
       aptlCorners[1].x = rclUpdt.xRight+1;
       aptlCorners[1].y = rclUpdt.yTop+1;
   /*
    * Want the top & right-hand side as well, so increase by one, since the
    * rectangles used for the BitBlt are non-inclusive (the bottom
    * and left are included, but not the top and right).
    */
       aptlCorners[2].x = rclUpdt.xLeft;
       aptlCorners[2].y = rclUpdt.yBottom;
       aptlCorners[3].x = rclUpdt.xRight+1;
       aptlCorners[3].y = rclUpdt.yTop+1;
       GpiBitBlt(hpsClient,
                 hpsMemory,
                 4L,
                 aptlCorners,
                 ROP_SRCCOPY,
                 BBO_IGNORE
                );
       RC = WinValidateRect(hwnd, &rclUpdt, FALSE);
       if (!WinIsRectEmpty(habMain, &tiStruct.rclTrack))
           DrawRect();
   }
}  /*  end of PaintRoutine  */

/**************************************************************************
 *
 *  Name       : PasteRoutine
 *
 *  Description: display a rectangle from the clipboard
 *
 *  Concepts   :
 *
 *  API's      : WinIsRectEmpty
 *               WinOpenClipbrd
 *               WinQueryClipbrdData
 *               GpiQueryBitmapParameters
 *               DevOpenDC
 *               GpiCreatePS
 *               GpiSetBitmap
 *               WinSetPointer
 *               GpiBitBlt
 *               GpiAssociate
 *               GpiDestroyPS
 *               DevCloseDC
 *               WinCloseClipbrd
 *               WinSetRect
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID PasteRoutine()
{
   HDC     hdcTempMem;
   HBITMAP bmapTempMem;
   HPS     hpsTempMem;
   BITMAPINFOHEADER bmpTemp;
   SIZEL   sizlWork;
     /*
      * If a bounding rectangle has been defined, open the clipboard and
      * see if it contains a bit map. If one exists, create temporary DCs
      * and GPI PSs to enable the clipboard bit map to be BitBlted into
      * the memory bit map and from there onto the screen. Destroy all the
      * temporary resources, close the clipboard and clear the
      * bounding rectangle.
      */
   if (!WinIsRectEmpty(habMain, &tiStruct.rclTrack))
   {
      WinOpenClipbrd(habMain);
      bmapTempMem = (HBITMAP)WinQueryClipbrdData(habMain, CF_BITMAP);
      if(bmapTempMem != (HBITMAP)0L)
      {
         GpiQueryBitmapParameters(bmapTempMem,
                                  &bmpTemp
                                  );
          /*
           * Want to paste inside the bounding rect. So increase the
           * left & bottom by one but leave the top & right since the
           * rectangles used for the BitBlt are non-inclusive (the
           * bottom and left are included, but not the top and right).
           */
          aptlCorners[0].x = tiStruct.rclTrack.xLeft+1;
          aptlCorners[0].y = tiStruct.rclTrack.yBottom+1;
          aptlCorners[1].x = tiStruct.rclTrack.xRight;
          aptlCorners[1].y = tiStruct.rclTrack.yTop;
          /*
           * No adjustments to the top & right top (using lengths)
           * since the rectangles used for the BitBlt are
           * non-inclusive (the bottom and left are included,
           * but not the top and right).
           */
          aptlCorners[2].x = 0;
          aptlCorners[2].y = 0;
          aptlCorners[3].x = bmpTemp.cx;
          aptlCorners[3].y = bmpTemp.cy;
          hdcTempMem = DevOpenDC(habMain,
                                 OD_MEMORY,
                                (PSZ)"*",
                                 8L,
                                (PDEVOPENDATA)&dcdatablk,
                                (HDC)0L
                                );
          sizlWork.cx = bmpTemp.cx;
          sizlWork.cy = bmpTemp.cy;
          hpsTempMem = GpiCreatePS(habMain,
                                   hdcTempMem,
                                   &sizlWork,
                                   GPIA_ASSOC | PU_PELS
                                  );
          GpiSetBitmap(hpsTempMem, bmapTempMem);
          WinSetPointer(HWND_DESKTOP,
                        WinQuerySysPointer(HWND_DESKTOP,
                                           SPTR_WAIT,
                                           FALSE)
                       );
          GpiBitBlt(hpsMemory,
                    hpsTempMem,
                    4L,
                    aptlCorners,
                    ROP_SRCCOPY,
                    BBO_IGNORE
                   );
          /*
           * Want a slightly bigger rectangle for the screen because
           * we need to remove the bounding rectangle as well as do
           * the paste.
           */
          aptlCorners[2].x =  (--aptlCorners[0].x);
          aptlCorners[2].y =  (--aptlCorners[0].y);
          aptlCorners[3].x =  (++aptlCorners[1].x);
          aptlCorners[3].y =  (++aptlCorners[1].y);
          GpiBitBlt(hpsClient,
                    hpsMemory,
                    4L,
                    aptlCorners,
                    ROP_SRCCOPY,
                    BBO_IGNORE
                   );
          WinSetPointer(HWND_DESKTOP,
                        WinQuerySysPointer(HWND_DESKTOP,
                                           SPTR_ARROW,
                                           FALSE)
                       );

          GpiSetBitmap(hpsTempMem, (HBITMAP)0L);
          GpiAssociate(hpsTempMem, (HDC)0L);
          GpiDestroyPS(hpsTempMem);
          DevCloseDC(hdcTempMem);
      } /* endif */
      WinCloseClipbrd(habMain);
      WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);
   } /* endif */
}   /* end of PasteRoutine  */

/**************************************************************************
 *
 *  Name       : RemoveRect
 *
 *  Description: Update the screen from the memory bitmap, thus erasing
 *               the rectangle
 *
 *  Concepts   :  bitblt
 *
 *  API's      : GpiBitBlt
 *               WinSetRect
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID RemoveRect()
{
  /*
   * Want the top & right-hand side as well, so increase by one since the
   * rectangles used for the BitBlt are non-inclusive (the
   * bottom and left are included, but not the top and right).
   */
   aptlCorners[0].x = tiStruct.rclTrack.xLeft;
   aptlCorners[0].y = tiStruct.rclTrack.yBottom;
   aptlCorners[1].x = tiStruct.rclTrack.xRight+1;
   aptlCorners[1].y = tiStruct.rclTrack.yTop+1;

  /*
   * Want the top & right-hand side as well, so increase by one since the
   * rectangles used for the BitBlt are non-inclusive (the
   * bottom and left are included, but not the top and right).
   */
   aptlCorners[2].x = tiStruct.rclTrack.xLeft;
   aptlCorners[2].y = tiStruct.rclTrack.yBottom;
   aptlCorners[3].x = tiStruct.rclTrack.xRight+1;
   aptlCorners[3].y = tiStruct.rclTrack.yTop+1;
   GpiBitBlt(hpsClient,
             hpsMemory,
             4L,
             aptlCorners,
             ROP_SRCCOPY,
             BBO_IGNORE
            );


   WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);
}  /* end of RemoveRect */

/**************************************************************************
 *
 *  Name       : Report_Error
 *
 *  Description: Display a particular system error message, the latest one
 *               for the required thread.  No resources can be loaded in
 *               case of memory error.
 *
 *  Concepts   :
 *
 *  API's      : WinGetErrorInfo
 *               WinMessageBox
 *               WinFreeErrorInfo
 *
 *  Parameters : hab = anchor block handle
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID Report_Error(HAB hab)
{
   PERRINFO  perriBlk;
   PSZ       pszErrMsg;
   PSZ       pszOffSet;

   if (!fErrMem)
   {
      if((perriBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL)
      {
         pszOffSet = ((PSZ)perriBlk) + perriBlk->offaoffszMsg;
         pszErrMsg = ((PSZ)perriBlk) + *((PUSHORT)pszOffSet);

         WinMessageBox(HWND_DESKTOP,
                        hwndFrame,
                       (PSZ)(pszErrMsg),
                       (PSZ)szTitleBar,
                        0,
                        MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL );
          WinFreeErrorInfo(perriBlk);
          return;
      }
   } /* endif */
   WinMessageBox(HWND_DESKTOP,
                 hwndFrame,
                 (PSZ)"ERROR - Out Of Memory",
                 (PSZ)szTitleBar,
                 0,
                 MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL);
}  /* end of Report_Error */

/**************************************************************************
 *
 *  Name       : WindowDestroy
 *
 *  Description: destroy particular window data
 *
 *  Concepts   :
 *
 *  API's      : GpiSetBitmap
 *               GpiDeleteBitmap
 *               GpiAssociate
 *               GpiDestroyPS
 *               DevCloseDC
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID WindowDestroy()
{
    /*
     * Deselect the bit map from the screen-compatible device context, and
     * delete the bit map. Disassociate the two GPI PSs from their respective
     * DCs and destroy the PSs. Finally destroy the memory DC.
     */

   GpiSetBitmap(hpsMemory, (HBITMAP)0L);
   GpiDeleteBitmap(bmapMemory);
   GpiAssociate(hpsClient, (HDC)0L);
   GpiDestroyPS(hpsClient);
   GpiAssociate(hpsMemory, (HDC)0L);
   GpiDestroyPS(hpsMemory);
   DevCloseDC(hdcMemory);
   return;
}   /*  end of WindowDestroy  */

/**************************************************************************
 *
 *  Name       : WindowInitialization
 *
 *  Description: create window information
 *
 *  Concepts   :
 *
 *  API's      : WinQuerySysValue
 *               WinOpenWindowDC
 *               GpiCreatePS
 *               DevOpenDC
 *               GpiSetBitmap
 *               GpiLoadBitmap
 *               GpiSetRect
 *
 *  Parameters : [none]
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID WindowInitialization(HWND hwnd)
{
   SIZEL   sizlWork;

    /*
     * Get the maximum client area size. Create a window DC for the client
     * area and a normal GPI Presentation Space and associate the two. The
     * GPI PS will be the maximum client area size in pels. Create a
     * memory DC compatible with the screen, create a GPI PS and associate it
     * with the screen compatible DC. Load a bit map from the resource
     * file, and select the bit map into the screen-compatible DC.
     * Initialize the rectangle tracking and set a flag to enable window
     * painting.
     */
   sizlWork.cx = WinQuerySysValue(HWND_DESKTOP, SV_CXFULLSCREEN);
   sizlWork.cy = WinQuerySysValue(HWND_DESKTOP, SV_CYFULLSCREEN);

   hdcClient = WinOpenWindowDC(hwnd);
   hpsClient = GpiCreatePS(habMain,
                           hdcClient,
                           &sizlWork,
                           GPIA_ASSOC | PU_PELS
                          );

   dcdatablk.driver_data = (PSZ)&drvdata;
   hdcMemory = DevOpenDC(habMain,
                         OD_MEMORY,
                        (PSZ)"*",
                         8L,
                        (PDEVOPENDATA)&dcdatablk,
                        (HDC)0L
                        );

   hpsMemory = GpiCreatePS(habMain,
                           hdcMemory,
                           &sizlWork,
                           GPIA_ASSOC | PU_PELS
                          );

   bmapMemory = GpiLoadBitmap( hpsMemory
                             , (HMODULE)0L
                             , (USHORT)ID_BITMAP
                             , sizlWork.cx
                             , sizlWork.cy
                             );

   GpiSetBitmap(hpsMemory, bmapMemory);
   WinSetRect(habMain, &tiStruct.rclTrack, 0, 0, 0, 0);

   fPaintable = TRUE;
   return;
}   /*  end of WindowInitialization  */

/**************************************************************************
 *
 *  Name       : ReportAPIError
 *
 *  Description: display an error message returned from an API call
 *
 *  Concepts   :
 *
 *  API's      : WinGetErrorInfo
 *               WinMessageBox
 *               WinPostMsg
 *
 *  Parameters : what = message string
 *
 *  Return     : [none]
 *
 *************************************************************************/
VOID ReportAPIError(PSZ what)
{
   PERRINFO  pErrInfoBlk;
   PSZ       pszErrMsg;
   PSZ       pszOffSet;
   char      ErrorMsg[CCHMAXSTRING];                          /* error text buffer */

   pszErrMsg = &szDefErrMesg[0];               /* set default in case no err */
   strcpy(ErrorMsg, what);                     /* init message string        */
   strcat(ErrorMsg, "\n\n");                   /* double space for neatness  */
   if ((pErrInfoBlk = WinGetErrorInfo(habMain)) != (PERRINFO)NULL)
   {
       pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
       pszErrMsg = ((PSZ)pErrInfoBlk) + *((PUSHORT)pszOffSet);

       WinFreeErrorInfo(pErrInfoBlk);
   } /*  if ((pErrInfoBlk = WinGetErrorInfo(hab)) != (PCH)NULL) */
   strcat(ErrorMsg, pszErrMsg);                 /* combine specific text     */
   WinMessageBox(HWND_DESKTOP,                  /* parent window is desk top */
                 hwndFrame,                     /* owner window is our frame */
                (PSZ)&ErrorMsg[0],              /* text for message          */
                (PSZ)szApiErrTitle,             /* title is API error        */
                 0,                             /* null window id            */
                 MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* flags        */
   Status = ERRORX;
   WinPostMsg(hwndClient, WM_QUIT, (ULONG)0, (ULONG)0);
   return;
}  /* end of ReportAPIError  */

/**************************************************************************
 *
 *  Name       :  ProductInfoDlgProc(hwnd, msg, mp1, mp2)
 *
 *  Description:  Processes all messages sent to the Product
 *                information dialog
 *
 *  Concepts   :  Called for each message sent to the Product information
 *                dialog box.
 *
 *                the Product information dialog has only a button control, so this
 *                routine processes only WM_COMMAND messages.  Any
 *                WM_COMMAND posted must have come from the OK
 *                button, so we dismiss the dialog upon receiving it.
 *
 *  API's      :  WinDefDlgProc
 *
 *  Parameters :  [none]
 *
 *  Return     :  dependent on message sent
 *
 *************************************************************************/
MRESULT EXPENTRY ProductInfoDlgProc(HWND hwnd,ULONG msg, MPARAM mp1, MPARAM mp2)
{
   switch (msg)
   {
   case WM_INITDLG:
      SetSysMenu(hwnd);       /* system menu for this dialog  */
         return (MRESULT)NULL;

   default:
      return WinDefDlgProc(hwnd, msg, mp1, mp2);
   }
   return (MRESULT)NULL;
}   /*  End of ProductInfoDlgProc  */

/**************************************************************************
 *
 *  Name       :  HelpProductInfo(hwndMain)
 *
 *  Description: Processes the Product information choice from the Help
 *               pulldown
 *
 *  Concepts   : Processes the WM_COMMAND message posted by the
 *               Product information item of the Help menu
 *               Called from MainCommand when the Product information
 *               menu item is selected
 *               Calls WinDlgBox to display the Product information
 *               dialog.
 *
 *  API's      :  WinDlgBox
 *
 *  Parameters :  hwndMain = main window handle
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID  HelpProductInfo(HWND hwndMain)
{
    /* display the Product Information dialog. */
   if(DID_ERROR == WinDlgBox(HWND_DESKTOP,
                             hwndMain,
                             (PFNWP)ProductInfoDlgProc,
                             0,
                             IDD_PRODUCTINFO,
                             (PVOID)NULL))
      ReportAPIError("Can't start dialog");
   return;
}   /*  End of HelpProductInfo   */

/**************************************************************************
 *
 *  Name       :  SetSysMenu(hDlg)
 *
 *  Description:  Enables only the Move and Close items in the
 *                system menu pulldown for any dialog
 *
 *  Concepts   :
 *
 *  API's      :  WinWindowFromID
 *                WinSendMsg
 *
 *  Parameters :  hDlg = dialog handle
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID SetSysMenu(HWND hDlg)
{
   HWND     hSysMenu;
   MENUITEM Mi;
   SHORT    Pos;
   SHORT    Id;
   SHORT    cItems;

   /*
    *  We only want Move and Close in the system menu.
    */
   hSysMenu = WinWindowFromID(hDlg, FID_SYSMENU);
   WinSendMsg( hSysMenu, MM_QUERYITEM
             , MPFROM2SHORT(SC_SYSMENU, FALSE), MPFROMP((PCH) & Mi));
   Pos = 0;
   cItems = (SHORT)WinSendMsg( Mi.hwndSubMenu, MM_QUERYITEMCOUNT,
                               (MPARAM)NULL, (MPARAM)NULL);
   while (cItems--)
   {
      Id = SHORT1FROMMR(WinSendMsg( Mi.hwndSubMenu, MM_ITEMIDFROMPOSITION
                         , MPFROM2SHORT(Pos, TRUE), (MPARAM)NULL));
      switch (Id)
      {
      case SC_MOVE:
      case SC_CLOSE:
         Pos++;  /* Don't delete that one. */
         break;
      default:
         WinSendMsg( Mi.hwndSubMenu, MM_DELETEITEM
                     , MPFROM2SHORT(Id, TRUE), (MPARAM)NULL);
      }
   }
} /*  End of SetSysMenu  */
/***************************  End of clipbrd.c  **************************/
